一、Session的简单介绍
当客户端访问服务端时,服务端会为每一个用户创建一个独一无二的Session对象,因此服务端如果需要保存客户端的一些数据的话,可以把数据存放到Session对象中,当用户使用浏览器访问该服务端其他的web资源时,服务端可以,从Session对象中取出必要的数据来服务用户。
二、Session与Cookie的区别
存放的位置:
Cookie是把用户的数据写给用户的浏览器。
Session是服务器把用户的数据写到Session中,来完成必要的数据获取。
储存数据方面:
Cookie只能存取String数据类型的数据,Session能够储存任意的Java对象。
安全方面:
Cookie保存在的是客户端,所以会被窃取,不太安全。Session存取在服务器,比较安全存放用户的一些重要的信息。
三、Session与Cookie的应用场景
Cookie:主要是一些网站用来存取账号与密码。登录所需要的数据。
Session:主要是购物网站中的购物车,添加了商品,把商品的信息存在Session中。
四、Session实现原理
虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。
HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,
它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。
该Cookie为服务器自动生成的,它的maxAge属性一般为–1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。
因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。
注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,
子窗口便可以访问父窗口的Session。如果客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?
例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另一种解决方案:URL地址重写。
package com.luther.TestWeb;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/sessiontest")
public class TestSession extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
HttpSession session=req.getSession();
session.setAttribute("country","中国");
String sessionId = session.getId();
if(session.isNew()){
resp.getWriter().write("Session创建,Session的ID是"+sessionId);
}else{
resp.getWriter().println("服务器已经有session了,Session的ID是"+sessionId);
}
}
}
五、session共享数据的实例展示
response.encodeRedirectURL(java.lang.String url) 用于对sendRedirect方法后的url地址进行重写。
response.encodeURL(java.lang.String url)用于对表单action和超链接的url地址进行重写
展示购买的书籍的页面:
package com.luther.TestWeb;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
//返回的是map的映射关系,一个关系就是一个键值对,就是把(key和value)当成一个整体
Set<Map.Entry<String,Book>> set=DB.getAll().entrySet();
PrintWriter out=resp.getWriter();
out.write("有下面的一些书:<br>");
for(Map.Entry<String,Book> set1:set){
//返回一个映射关系
Book book=set1.getValue();
//获取名称
String name=book.getName();
//获取值
String id=book.getId();
out.write(name+":");
String url=req.getContextPath()+"/BuyServlet?id="+book.getId();
resp.encodeURL("url");
out.write("<a href='"+url+"'>购买</a><br/>");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
//这里应该是从数据库里获取的,这里简单就直接展示出来,也可以自己写XML文件来进行储存
class DB{
private static Map<String,Book> map=new HashMap<String,Book>();
static {
map.put("1",new Book("JAVA开发","1"));
map.put("2",new Book("C++开发","2"));
map.put("3",new Book("C语言开发","3"));
}
public static Map<String,Book> getAll(){
return map;
}
}
class Book{
private String name;
private String id;
public Book(String name, String id) {
this.name = name;
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
购买图书,存取数据的中间过程:
package com.luther.TestWeb;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class BuyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session=req.getSession();
//获取传来的ID
String id=(String)req.getParameter("id");
Book book=DB.getAll().get(id);
List<Book> list=(List)session.getAttribute("List");
if(list==null) {
list = new ArrayList<Book>();
}
list.add(book);
//把数据存放到Session中
session.setAttribute("List",list);
String url=req.getContextPath()+"/ListServlet";
resp.sendRedirect(url);//这里可以防止表单的重复提交
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
展示已经购买的书籍:
package com.luther.TestWeb;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
public class ListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out=resp.getWriter();
HttpSession session=req.getSession();
//获取到Session存取的值
List<Book> list=(List)session.getAttribute("List");
if(list==null){
out.println("服务器出错误了");
}else {
out.println("你已经购买了:<br/>");
for(Book l:list)
out.println(l.getName()+"<br/>");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
运行截图:
六、Session的创建与销毁
1、Session的创建是当我们第一次调用getSession()方法时创建
2、Session对象的销毁(默认的是30分钟之后销毁),可以在web.xml文件中设置销毁的时间
<!--分钟为单位-->
<session-config>
<session-timeout>900</session-timeout>
</session-config>
3、也可以手动的销毁
session.invalidate();