Servlet的会话(Session)跟踪
以下内容引用自http://wiki.jikexueyuan.com/project/servlet/session-tracking.html:
HTTP是一种“无状态”协议,这意味着每次客户端检索Web页面时,客户端打开一个单独的连接到Web服务器,服务器不会自动保存之前客户端请求的任何记录。
仍然有以下三种方式来维持Web客户端和Web服务器之间的会话:
一、Cookies
一个Web服务器可以分配一个唯一的会话ID作为每个Web客户端的Cookie,并且对于来自客户端的后续请求,它们可以使用已接收的Cookie来识别。
这可能不是一个有效的方法,因为很多时候浏览器不支持Cookie,所以我不建议使用这种方式来维持会话(由于年代问题,现在的浏览器全部都支持Cookie)。
二、隐藏的表单字段
一个Web服务器可以发送一个隐藏的HTML表单字段以及一个唯一的会话ID,如下所示:
<input type="hidden" name="sessionid" value="12345">
该条目意味着,当表单被提交时,指定的名称和值会被自动包含在GET或POST数据中。每次当Web浏览器发送回请求时,session_id的值可以用于跟踪不同的Web浏览器。
这可能是保持会话跟踪的一种有效的方式,但是点击常规的(<A HREF...>)
超文本链接不会导致表单提交,因此隐藏的表单字段也不支持常规的会话跟踪。
三、URL重写
可以在每个标识会话的URL末尾追加一些额外的数据,且服务器会把该会话标识符与它已存储的有关会话的数据关联起来。
例如,http://jsoft.com/file.htm;sessionid=12345
,会话标识符被附加为sessionid=12345,可能会在Web服务器端被访问来识别客户端。
URL重写是维持会话的一种更好的方式,当浏览器不支持Cookie时为浏览器工作,但是它的缺点是会动态的生成每个URL来分配会话ID,即使页面是简单的静态的HTML页面。
四、HttpSession对象
除了上述提到的三种方式,Servlet还提供了HttpSession接口,该接口提供了一种对网站的跨多个页面请求或访问的方法来识别用户并存储有关用户的信息。
Servlet容器使用这个接口来创建在HTTP客户端和HTTP服务器之间的会话。会话在一个指定的时间段内持续,跨多个连接或来自用户的请求。
可以通过调用HttpServletRequest的公共方法getSession()来获取HttpSession对象,如下所示:
HttpSession session = request.getSession();
在向客户端发送任何文档内容之前,需要调用request.getSession()。这里是一些重要方法的总结,这些方法通过HttpSession对象是可用的:
方法 | 描述 |
---|---|
public Object getAttribute(String name) |
该方法返回在该Session会话中具有指定名称的对象,如果没有指定名称的对象,则返回null。 |
public Enumeration getAttributeNames() |
该方法返回String对象的枚举,String对象包含所有绑定到该Session会话的对象的名称。 |
public long getCreationTime() |
该方法返回该Session 会话被创建的时间,自格林尼治标准时间1970年1月1日凌晨零点算起,以毫秒为单位。 |
public String getId() |
该方法返回一个包含分配给该Session会话的唯一标识符的字符串。 |
public long getLastAccessedTime() |
该方法返回客户端最后一次发送与该Session会话相关的请求的时间自格林尼治标准时间1970年1月1日凌晨零点算起,以毫秒为单位。 |
public int getMaxInactiveInterval() |
该方法返回Servlet容器在客户端访问时保持Session会话打开的最大时间间隔,以秒为单位。 |
public void invalidate() |
该方法指示该Session会话无效,并解除绑定到它上面的任何对象。 |
public boolean isNew() |
如果客户端还不知道该Session会话,或者如果客户选择不参入该Session会话,则该方法返回true。 |
public void removeAttribute(String name) |
该方法将从该Session会话移除指定名称的对象。 |
public void setAttribute(String name, Object value) |
该方法使用指定的名称绑定一个对象到该Session会话。 |
public void setMaxInactiveInterval(int interval) |
该方法在Servlet容器指示该Session会话无效之前,指定客户端请求之间的时间,以秒为单位。 |
五、会话跟踪实例
这个例子描述了如何使用HttpSession对象获取会话创建时间和上次访问的时间。如果不存在会话,将一个新的会话与请求联系起来。
// Import required java libraries import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; // Extend HttpServlet class public class SessionTrack extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Create a session object if it is already not created. HttpSession session = request.getSession(true); // Get session creation time. Date createTime = new Date(session.getCreationTime()); // Get last access time of this web page. Date lastAccessTime = new Date(session.getLastAccessedTime()); String title = "Welcome Back to my website"; Integer visitCount = new Integer(0); String visitCountKey = new String("visitCount"); String userIDKey = new String("userID"); String userID = new String("ABCD"); // Check if this is new comer on your web page. if (session.isNew()){ title = "Welcome to my website"; session.setAttribute(userIDKey, userID); } else { visitCount = (Integer)session.getAttribute(visitCountKey); visitCount = visitCount + 1; userID = (String)session.getAttribute(userIDKey); } session.setAttribute(visitCountKey, visitCount); // Set response content type response.setContentType("text/html"); PrintWriter out = response.getWriter(); String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n"; out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n" + "<h1 align=\"center\">" + title + "</h1>\n" + "<h2 align=\"center\">Session Infomation</h2>\n" + "<table border=\"1\" align=\"center\">\n" + "<tr bgcolor=\"#949494\">\n" + " <th>Session info</th><th>value</th></tr>\n" + "<tr>\n" + " <td>id</td>\n" + " <td>" + session.getId() + "</td></tr>\n" + "<tr>\n" + " <td>Creation Time</td>\n" + " <td>" + createTime + " </td></tr>\n" + "<tr>\n" + " <td>Time of Last Access</td>\n" + " <td>" + lastAccessTime + " </td></tr>\n" + "<tr>\n" + " <td>User ID</td>\n" + " <td>" + userID + " </td></tr>\n" + "<tr>\n" + " <td>Number of visits</td>\n" + " <td>" + visitCount + "</td></tr>\n" + "</table>\n" + "</body></html>"); } }
配置web.xml:
<servlet> <servlet-name>SessionTrack</servlet-name> <servlet-class>com.jsoft.testservletbasics.SessionTrack</servlet-class> </servlet> <servlet-mapping> <servlet-name>SessionTrack</servlet-name> <url-pattern>/SessionTrack</url-pattern> </servlet-mapping>
编译上述Servlet SessionTrack并在web.xml文件中创建适当的条目。在浏览器地址栏输入http://localhost:8080/SessionTrack
,当第一次运行时将显示如下所示的结果:
现在尝试再次运行相同的Servlet,它将显示如下所示的结果:
六、删除会话数据
当完成了一个用户的会话数据,有以下几种选择:
-
移除一个特定的属性:可以调用public void removeAttribute(String name)方法来删除与特定的键相关联的值。
-
删除整个会话:可以调用public void invalidate()方法来删除整个会话。
-
设置会话超时:可以调用public void setMaxInactiveInterval(int interval)方法来单独设置会话超时。
-
注销用户:支持Servlet 2.4的服务器,可以调用logout来注销Web服务器的客户端,并把属于所有用户的所有会话设置为无效。
- web.xml配置:如果使用的是Tomcat,除了上述方法,还可以在web.xml文件中配置会话超时,如下所示:
<session-config> <session-timeout>15</session-timeout> </session-config>
超时时间是以分钟为单位的,并覆盖了Tomcat中默认的30分钟的超时时间。
Servlet中的getMaxInactiveInterval()方法为会话返回的超时时间是以秒为单位的。所以如果在web.xml中配置会话超时时间为15分钟,那么getMaxInactiveInterval()会返回900。
测试工程:https://github.com/easonjim/5_java_example/tree/master/servletbasics/test9