一、会话概述
HttpSession对象可以保存跨同一个客户多个请求的会话状态。即与一个特定客户的整个会话期间,HttpSession会持久存储。对于会话期间客户做的所有请求,从中得到的所有信息,都可以使用HttpSession对象保存。
会话的工作方式:
此时,假设又有一个客户访问该网站:
上图展示了会话是如何工作的,但是,有一个问题,Http协议是无状态协议,对容器来说,每个请求都来自于一个新的客户,那么容器是怎么区分不同的客户呢?
1.1 会话ID
为了让容器区分不同的客户,客户需要一个唯一的会话ID。
当容器接收到客户的第一个请求时,容器会生成一个唯一的会话ID,并通过响应将其返回给客户。客户再在之后的每一次请求中,携带该会话ID,容器在拿到ID之后,就会找到相应的会话,并把这个请求与该会话关联。
容器必须以某种方式将会话ID作为响应的一部分交给客户,而客户发出在请求时,必须把会话ID作为请求的一部分发回。最通用的方式是通过cookie来交换会话信息。
1.2 会话创建
除了必须告诉容器想要创建或使用一个会话之外, 容器几乎会做所有工作,如生成会话ID、创建新的cookie对象、把会话ID放到cookie中,把cookie设置为响应的一部分;从请求中的cookie得到会话ID、将会话ID与一个现有的会话匹配、将会话与当前请求关联等等。
如下在响应中发送一个会话cookie:
HttpSession session = requset.getSession();
如下从请求中得到一个会话cookie
HttpSession session = requset.getSession();
会发现,得到一个会话ID cookie的方法与发送一个会话ID cookie的方法是一样的。该方法进行如下操作:
如上所示,getSession()会返回一个会话,无论是否已经有了一个会话。如果想知道该会话是不是新创建的,可以使用HttpSession.isNew()方法。
HttpSession session = request.getSession();if (session.isNew()){//会话为新建的会话,即直接返回给用户}else{//为用户返回的会话ID,找到与该ID匹配的会话}
若不想创建会话,而是想要一个已经存在的会话,可以使用以下操作:
//返回一个已有会话,若无与用户匹配的会话,返回null
HttpSession session = request.getSession(false);
if(session == null){//创建新会话session = request.getSession();
}else{//操作
}
1.3 URL重写
当客户不支持cookie时,可以使用URL重写在客户和容器之间传递会话ID。
- 在写至响应的HTML中,URL重写会把会话ID添加到其中所有URL的后面,格式:URL+;jsessionid=XXX
- URL重写中,会话id会作为请求URL的最后“额外”信息返回给容器;
- 若客户不接受cookie,容器会自动地完成URL重写,但必须显示地对所有重写的URL进行编码,其他工作(添加会话id到URL)容器会自动地完成。
- 对URL进行编码,需要调用response.encodeURL(String);
- 若想在重定向中使用会话,可以用response.encodeRedirectURL(“/BeerSelect.do”);编码重定位URL;
- 容器在使用会话时,首先会尝试使用cookie进行会话ID交换,若不支持cookie,再回采用URL重写,此时需要编码所有重写的URL;
- 不能对静态页面完成URL重写,使用会话必须使用动态页面。
1.4 删除会话
客户到来,开始一个会话,而客户离开后,或浏览器崩溃后,或完成一次购买交易后等等情况下需要结束会话。Http协议没有提供任何机制让服务器知道客户是不是已经离开,那么容器应该如何安全的撤销一个会话呢?
会话有三种方式可以结束,分别是超时、在会话对象上调用invalidate()方法、应用结束。
- 超时,以下两种超时方式效果完全一样
- 在web.xml中设置会话超时时间。
<!--设置会话超时--> <session-config><session-timeout>15</session-timeout> <!--分钟为单位--> </session-config>
- 会话对象设置时间,会话时间设为-1后,会话永远不会到期
session.setMaxInactiveInterval(15*60); //秒数为单位
- 在web.xml中设置会话超时时间。
- 会话对象调用invalidate()
- 应用结束(崩溃或取消部署)
二、Cookie
Cookie不仅可用于在客户端和服务器间传递会话ID;还可用于在客户和服务器中传递信息,Cookie实际上是客户与服务器之间交换的一小段数据(一个名/值string对)。每一个Cookie都是一个String键值对对象,Cookie对象声明:new Cookie(String, String)。
当客户想要长时间保持信息时(如用户名),客户在第一次请求时,Servlet从请求参数中获取信息,创建Cookie并发送给用户,用户保存在客户端,当用户再次发送请求时,用户会在每一个请求中将Cookie发回给服务端(自动),服务器从Cookie得到信息分清客户。
当客户会话消失时,会话Cookie就会消失,但可以设置Cookie时间使之在客户端持久存储。
2.1 cookie示例
如下,服务端设置cookie:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//设置响应类型response.setContentType("text/html");//得到表单中提交的用户名String username = request.getParameter("username");//建立一个新的Cookie,用来存储用户名Cookie cookie = new Cookie("username",username);//设置Cookie在客户端上的存活时间cookie.setMaxAge(10);//将此Cookie增加为“set-cookie”响应首部response.addCookie(cookie);RequestDispatcher view = request.getRequestDispatcher("cookieresult.jsp");view.forward(request,response);}
如下,服务器获取cookie:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();Cookie[] cookies = request.getCookies(); //获取客户请求携带的cookieif(cookies!=null){for(int i=0;i<cookies.length;i++){Cookie cookie = cookies[i];if(cookie.getName().equals("wangy")){String userName = cookie.getName();out.println("Hello "+userName);break;}}}}
2.2 会话生命周期事件
事件 | 监听器与监听事件 | |
生命周期 | 创建会话:容器第一次创建会话,即此时用户未使用该会话访问服务器。 删除会话:容器置会话无效。 | HttpSessionListener HttpSessionEvent |
属性 | 增加属性:setAttribute() 删除属性:removeAttribute() 替换属性:重新调用setAttribute() | HttpSessionAttributeListener HttpSessionBindingEvent |
迁移 | 会话钝化:容器在将会话迁移到另一个VM中,要在会话移动之前调用。 会话激活:容器已经将会话迁移到另一个VM,要在应用的其他部分对会话调用getAttribute()之前调用。 | HttpSessionActivationListener HttpSessionEvent |
监听示例: 对象实现了HttpSessionBindingListener,会监听自己被绑定或解除绑定事件。
public class Dog implements HttpSessionBindingListener {private String breed;public Dog(String breed){this.breed = breed;}public String getBreed() {return breed;}//监听到绑定会话时@Overridepublic void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {}//监听到解除绑定会话时@Overridepublic void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {}/*** 重写toString方法* @return*/@Overridepublic String toString() {return "Dog{" +"breed='" + breed + '\'' +'}';}
}
三、结束
本文主要介绍了会话,以及cookie。会话是保存跨同一个客户多个请求的状态,其实现手段是在响应和请求时通过cookie携带会话ID。Cookie实际上是客户与服务器之间交换的一小段数据,其不仅可用于在客户端和服务器间传递会话ID;还可用于在客户和服务器中传递信息。