Servlet Session 跟踪
HTTP 是一種"無狀態"協議,這意味著每次客戶端檢索網頁時,客戶端打開一個單獨的連接到Web 服務器,服務器會自動不保留之前客戶端請求的任何記錄。
但是仍然有以下三種方式來維持Web 客戶端和Web 服務器之間的session 會話:
Cookies
一個Web 服務器可以分配一個唯一的session 會話ID 作為每個Web 客戶端的cookie,對於客戶端的後續請求可以使用接收到的cookie 來識別。
這可能不是一個有效的方法,因為很多瀏覽器不支持cookie,所以我們建議不要使用這種方式來維持session 會話。
隱藏的表單字段
一個Web 服務器可以發送一個隱藏的HTML 表單字段,以及一個唯一的session 會話ID,如下所示:
<input type="hidden" name="sessionid" value="12345">
該條目意味著,當表單被提交時,指定的名稱和值會被自動包含在GET 或POST 數據中。 每次當Web 瀏覽器發送回請求時,session_id 值可以用於保持不同的Web 瀏覽器的跟踪。
這可能是一種保持session 會話跟踪的有效方式,但是點擊常規的超文本鏈接(<A HREF...>)不會導致表單提交,因此隱藏的表單字段也不支持常規的session 會話跟踪。
URL 重寫
您可以在每個URL 末尾追加一些額外的數據來標識session 會話,服務器會把該session 會話標識符與已存儲的有關session 會話的數據相關聯。
例如,http://w3cschool.cc/file.htm;sessionid=12345,session 會話標識符被附加為sessionid=12345,標識符可被Web 服務器訪問以識別客戶端。
URL 重寫是一種更好的維持session 會話的方式,它在瀏覽器不支持cookie 時能夠很好地工作,但是它的缺點是會動態生成每個URL 來為頁面分配一個session 會話ID,即使是在很簡單的靜態HTML 頁面中也會如此。
HttpSession 對象
除了上述的三種方式,Servlet 還提供了HttpSession 接口,該接口提供了一種跨多個頁面請求或訪問網站時識別用戶以及存儲有關用戶信息的方式。
Servlet 容器使用這個接口來創建一個HTTP 客戶端和HTTP 服務器之間的session 會話。 會話持續一個指定的時間段,跨多個連接或頁面請求。
您會通過調用HttpServletRequest的公共方法getSession()來獲取HttpSession對象,如下所示:
HttpSession session = request.getSession();
你需要在向客戶端發送任何文檔內容之前調用request.getSession() 。 下面總結了HttpSession 對像中可用的幾個重要的方法:
序号 | 方法 & 描述 |
---|---|
1 | public Object getAttribute(String name) 该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null。 |
2 | public Enumeration getAttributeNames() 该方法返回 String 对象的枚举,String 对象包含所有绑定到该 session 会话的对象的名称。 |
3 | public long getCreationTime() 该方法返回该 session 会话被创建的时间,自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。 |
4 | public String getId() 该方法返回一个包含分配给该 session 会话的唯一标识符的字符串。 |
5 | public long getLastAccessedTime() 该方法返回客户端最后一次发送与该 session 会话相关的请求的时间自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。 |
6 | public int getMaxInactiveInterval() 该方法返回 Servlet 容器在客户端访问时保持 session 会话打开的最大时间间隔,以秒为单位。 |
7 | public void invalidate() 该方法指示该 session 会话无效,并解除绑定到它上面的任何对象。 |
8 | public boolean isNew() 如果客户端还不知道该 session 会话,或者如果客户选择不参入该 session 会话,则该方法返回 true。 |
9 | public void removeAttribute(String name) 该方法将从该 session 会话移除指定名称的对象。 |
10 | public void setAttribute(String name, Object value) 该方法使用指定的名称绑定一个对象到该 session 会话。 |
11 | public void setMaxInactiveInterval(int interval) 该方法在 Servlet 容器指示该 session 会话无效之前,指定客户端请求之间的时间,以秒为单位。 |
Session 跟踪實例
本實例說明瞭如何使用HttpSession 對象獲取session 會話創建時間和最後訪問時間。 如果不存在session 會話,我們將通過請求創建一個新的session 會話。
package com.w3big.test; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; 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; /** * Servlet implementation class SessionTrack */ @WebServlet("/SessionTrack") public class SessionTrack extends HttpServlet { private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 如果不存在 session 会话,则创建一个 session 对象 HttpSession session = request.getSession(true); // 获取 session 创建时间 Date createTime = new Date(session.getCreationTime()); // 获取该网页的最后一次访问时间 Date lastAccessTime = new Date(session.getLastAccessedTime()); //设置日期输出的格式 SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String title = "Servlet Session 实例 - 本教程"; Integer visitCount = new Integer(0); String visitCountKey = new String("visitCount"); String userIDKey = new String("userID"); String userID = new String("w3big"); // 检查网页上是否有新的访问者 if (session.isNew()){ title = "Servlet Session 实例 - 本教程"; session.setAttribute(userIDKey, userID); } else { visitCount = (Integer)session.getAttribute(visitCountKey); visitCount = visitCount + 1; userID = (String)session.getAttribute(userIDKey); } session.setAttribute(visitCountKey, visitCount); // 设置响应内容类型 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String docType = "<!DOCTYPE html>\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 信息</h2>\n" + "<table border=\"1\" align=\"center\">\n" + "<tr bgcolor=\"#949494\">\n" + " <th>Session 信息</th><th>值</th></tr>\n" + "<tr>\n" + " <td>id</td>\n" + " <td>" + session.getId() + "</td></tr>\n" + "<tr>\n" + " <td>创建时间</td>\n" + " <td>" + df.format(createTime) + " </td></tr>\n" + "<tr>\n" + " <td>最后访问时间</td>\n" + " <td>" + df.format(lastAccessTime) + " </td></tr>\n" + "<tr>\n" + " <td>用户 ID</td>\n" + " <td>" + userID + " </td></tr>\n" + "<tr>\n" + " <td>访问统计:</td>\n" + " <td>" + visitCount + "</td></tr>\n" + "</table>\n" + "</body></html>"); } }
編譯上面的ServletSessionTrack ,並在web.xml文件中創建適當的條目。
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <!-- 类名 --> <servlet-name>SessionTrack</servlet-name> <!-- 所在的包 --> <servlet-class>com.w3big.test.SessionTrack</servlet-class> </servlet> <servlet-mapping> <servlet-name>SessionTrack</servlet-name> <!-- 访问的网址 --> <url-pattern>/TomcatTest/SessionTrack</url-pattern> </servlet-mapping> </web-app>
在瀏覽器地址欄輸入http://localhost:8080/TomcatTest/SessionTrack ,當您第一次運行時將顯示如下結果:
再次嘗試運行相同的Servlet,它將顯示如下結果:
刪除Session 會話數據
當您完成了一個用戶的session 會話數據,您有以下幾種選擇:
- 移除一個特定的屬性:您可以調用public void removeAttribute(String name)方法來刪除與特定的鍵相關聯的值。
- 刪除整個session會話:您可以調用public void invalidate()方法來丟棄整個session會話。
- 設置session會話過期時間:您可以調用public void setMaxInactiveInterval(int interval)方法來單獨設置session會話超時。
- 註銷用戶:如果使用的是支持servlet 2.4的服務器,您可以調用logout來註銷Web服務器的客戶端,並把屬於所有用戶的所有session會話設置為無效。
- web.xml配置:如果您使用的是Tomcat,除了上述方法,您還可以在web.xml文件中配置session會話超時,如下所示:
<session-config> <session-timeout>15</session-timeout> </session-config>
上面實例中的超時時間是以分鐘為單位,將覆蓋Tomcat 中默認的30 分鐘超時時間。
在一個Servlet 中的getMaxInactiveInterval() 方法會返回session 會話的超時時間,以秒為單位。 所以,如果在web.xml 中配置session 會話超時時間為15 分鐘,那麼getMaxInactiveInterval() 會返回900。