会话管理基本原则
使用隐藏域
在HTTP协议中,服务器是没有记忆功能的,每个请求对服务器来说都是新请求。
所以就有了隐藏域,隐藏域是主动告知服务器多次请求间必要信息的方式之一。
如何将上一次的结果成为下一次请求的隐藏域呢?
做法之一就是将上一次的结果发送至服务器,由服务器将上一次的结果以隐藏域的方式再响应给浏览器。
比如调查问卷,第一页的结果会在第二页成为隐藏域,当第二页发送后,可以看到两页问卷的所有答案。
...
@WebServlet("/questionnarie")
public class Questionnaire extends HttpServlet {
protected void processRequest(HttpServlertRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
PritWriter out = response.getWriter();
String page = request.getParameter("page");
...
if(page == null) {
out.println("问题一:<input type='text' name='p1q1'><br>");
out.println("问题二:<input type='text' name='p1q2'><br>");
out.println("input type='submit' name='page' value='下一页'");
}
else if("下一页".equals(page)) {
String p1q1 = request.getParameter("p1q1");
String p1q2 = request.getParameter("p1q2");
out.println("问题三:<input type='text' name='p2q1'><br>");
out.println("<input type='hidden' name='p1q1' value='" + p1q1 + "'>");
out.println("<input type='hidden' name='p1q1' value='" + p1q2 + "'>");
out.println("<input type='submit' name='page' value='完成'>");
}
else if("完成".equals(page)) {
out.println(request.getParameter("p1q1") + "<br>");
out.println(request.getParameter("p1q2") + "<br>");
out.println(request.getParameter("p2q1") + "<br>");
}
...
}
...
}
使用Cookie
Cookie是在浏览器存储信息的一种方式,服务器可以响应浏览器set-cookie标头,浏览器收到这个标头与数值后,会将它以文件形式存储在计算机上,这个文件就是Cookie
Cookie可以设定存活期限,保留一些有用的信息在客户端,如果关闭浏览器后,再次打开,若Cookie仍在有效期,浏览器会使用cookie标头自动将Cookie发送给服务器,服务器就可以得知一些先前浏览器请求的相关信息。默认关闭浏览器后Cookie失效。
//创建Cookie
Cookie cookie = new Cookie("user", "caterpillar");
cookie.setMaxage(7 * 24 * 60 * 60); //单位是“秒”
response.addCookie(cookie);
用HttpServletRequest的getCookies()来取得浏览器上存储的Cookie,返回Cookie[]数组
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for(Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
...
}
}
Cookie可以实现用户自动登录功能。
当用户访问首页时,会先取得所有的Cookie,然后一个一个检查是否有Cookie存储名称name与值value和你要登录的一样的,如果有,则表示先前用户登录时,曾将选取过“自动登录”选项(请求中会带有login参数且值为auto),因此直接转发至用户页面。如果没有,重定向到登录窗体。
使用URL重写
通常URL重写是用在一些简单的客户端信息保留,或者是辅助会话管理。
HttpSession会话管理
Servlet/JSP中进行会话管理的机制:使用HttpSession
使用HttpSession
如果想在浏览器与Web应用程序的会话期间,保留请求之间的相关信息,可以使用HttpSession的setAttribute()方法将相关信息设置为属性。在会话期间,你就可以当作Web应用程序“记得”客户端的信息,如果像取出这些信息,则通过HttpSession的getAttribute()就可以取出。
如果想在此次会话期间,直接让目前的HttpSession失效,可以执行invalidate()方法,可以用来实现注销的功能。
在登录时,如果名称与密码正确,就取得HttpSession并设定一个login属性,用以代表用户作完成登录的动作。其他的Servlet/JSP,如果可以从HttpSession取得login属性,基本上就可以确定这是一个已经登录的用户。这种属性通常称为登录令牌。
执行HttpSession的invalidate()之后,容器就会销毁回收HttpSession对象,如果再次通过HttpServletRequest的getSession(),取得HttpSession就是另一个新对象了。
HttpSession会话管理原理
尝试执行httpServletRequest的getSession()时,Web容器就会创建HttpSession对象。每个HttpSession对象都会有一个特殊的ID,称为Session ID(默认使用Cookie存放在浏览器中),你可以执行getId()来取得。
当浏览器请求应用程序时,会将Cookie中存放的Session ID一并发送给应用程序,Web容器会根据Session ID来找出对应的HttpSession对象。
由于HttpSession对象会占用内存空间,所以HttpSession的属性中尽量不要存储耗费资源的大型对象,必要时将属性移除,或者不需使用HttpSession时,执行invalidate()让HttpSession失效。
默认关闭浏览器马上失效的是浏览器上的Cookie,不是HttpSession。因为Cookie失效了,就无法通过Cookie来发送Session ID。要让HttpSession立即失效必须运行invalidate()方法,否则HttpSession会等到设定的时效期间过后才会被容器销毁回收。
可以执行HttpSession的setMaxInactiveInterval()方法,设定浏览器多久没有请求应用程序的话,HttpSession就自动失效(而不是存储Session ID的Cookie失效时间),单位是“秒”。
HttpSession与URL重写
如果在用户禁用Cookie的情况下,仍打算运用HttpSession来进行会话管理,那么可以搭配URL重写的,向浏览器响应一段超链接,超链接URL后附加Session ID,当用户单击超链接,将Session ID以GET请求发送给Web应用程序。
使用HttpServletResponse的encodeURL()就会产生有Session ID的URL。