HTTP 是一種"無狀態(tài)"協(xié)議,這意味著每次客戶端檢索網(wǎng)頁時,客戶端打開一個單獨的連接到 Web 服務(wù)器,服務(wù)器會自動不保留之前客戶端請求的任何記錄。
但是仍然有以下三種方式來維持 Web 客戶端和 Web 服務(wù)器之間的 session 會話:
一個 Web 服務(wù)器可以分配一個唯一的 session 會話 ID 作為每個 Web 客戶端的 cookie,對于客戶端的后續(xù)請求可以使用接收到的 cookie 來識別。
這可能不是一個有效的方法,因為很多瀏覽器不支持 cookie,所以我們建議不要使用這種方式來維持 session 會話。
一個 Web 服務(wù)器可以發(fā)送一個隱藏的 HTML 表單字段,以及一個唯一的 session 會話 ID,如下所示:
<input type="hidden" name="sessionid" value="12345">
該條目意味著,當(dāng)表單被提交時,指定的名稱和值會被自動包含在 GET 或 POST 數(shù)據(jù)中。每次當(dāng) Web 瀏覽器發(fā)送回請求時,session_id 值可以用于保持不同的 Web 瀏覽器的跟蹤。
這可能是一種保持 session 會話跟蹤的有效方式,但是點擊常規(guī)的超文本鏈接(<A HREF...>)不會導(dǎo)致表單提交,因此隱藏的表單字段也不支持常規(guī)的 session 會話跟蹤。
您可以在每個 URL 末尾追加一些額外的數(shù)據(jù)來標(biāo)識 session 會話,服務(wù)器會把該 session 會話標(biāo)識符與已存儲的有關(guān) session 會話的數(shù)據(jù)相關(guān)聯(lián)。
例如,http://(cainiaoplus.com)/file.htm;sessionid=12345,session 會話標(biāo)識符被附加為 sessionid=12345,標(biāo)識符可被 Web 服務(wù)器訪問以識別客戶端。
URL 重寫是一種更好的維持 session 會話的方式,它在瀏覽器不支持 cookie 時能夠很好地工作,但是它的缺點是會動態(tài)生成每個 URL 來為頁面分配一個 session 會話 ID,即使是在很簡單的靜態(tài) HTML 頁面中也會如此。
除了上述的三種方式,Servlet 還提供了 HttpSession 接口,該接口提供了一種跨多個頁面請求或訪問網(wǎng)站時識別用戶以及存儲有關(guān)用戶信息的方式。
Servlet 容器使用這個接口來創(chuàng)建一個 HTTP 客戶端和 HTTP 服務(wù)器之間的 session 會話。會話持續(xù)一個指定的時間段,跨多個連接或頁面請求。
您會通過調(diào)用 HttpServletRequest 的公共方法 getSession() 來獲取 HttpSession 對象,如下所示:
HttpSession session = request.getSession();
你需要在向客戶端發(fā)送任何文檔內(nèi)容之前調(diào)用 request.getSession()。下面總結(jié)了 HttpSession 對象中可用的幾個重要的方法:
| 序號 | 方法 & 描述 |
|---|---|
| 1 | public Object getAttribute(String name) 該方法返回在該 session 會話中具有指定名稱的對象,如果沒有指定名稱的對象,則返回 null。 |
| 2 | public Enumeration getAttributeNames() 該方法返回 String 對象的枚舉,String 對象包含所有綁定到該 session 會話的對象的名稱。 |
| 3 | public long getCreationTime() 該方法返回該 session 會話被創(chuàng)建的時間,自格林尼治標(biāo)準(zhǔn)時間 1970 年 1 月 1 日午夜算起,以毫秒為單位。 |
| 4 | public String getId() 該方法返回一個包含分配給該 session 會話的唯一標(biāo)識符的字符串。 |
| 5 | public long getLastAccessedTime() 該方法返回客戶端最后一次發(fā)送與該 session 會話相關(guān)的請求的時間自格林尼治標(biāo)準(zhǔn)時間 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 會話無效之前,指定客戶端請求之間的時間,以秒為單位。 |
本示例說明了如何使用 HttpSession 對象獲取 session 會話創(chuàng)建時間和最后訪問時間。如果不存在 session 會話,我們將通過請求創(chuàng)建一個新的 session 會話。
package com.nhooo.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 會話,則創(chuàng)建一個 session 對象
HttpSession session = request.getSession(true);
// 獲取 session 創(chuàng)建時間
Date createTime = new Date(session.getCreationTime());
// 獲取該網(wǎng)頁的最后一次訪問時間
Date lastAccessTime = new Date(session.getLastAccessedTime());
//設(shè)置日期輸出的格式
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("Nhooo");
if(session.getAttribute(visitCountKey) == null) {
session.setAttribute(visitCountKey, new Integer(0));
}
// 檢查網(wǎng)頁上是否有新的訪問者
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);
// 設(shè)置響應(yīng)內(nèi)容類型
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>創(chuàng)建時間</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>訪問統(tǒng)計:</td>\n" +
" <td>" + visitCount + "</td></tr>\n" +
"</table>\n" +
"</body></html>");
}
}編譯上面的 Servlet SessionTrack,并在 web.xml 文件中創(chuàng)建適當(dāng)?shù)臈l目。
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <!-- 類名 --> <servlet-name>SessionTrack</servlet-name> <!-- 所在的包 --> <servlet-class>com.nhooo.test.SessionTrack</servlet-class> </servlet> <servlet-mapping> <servlet-name>SessionTrack</servlet-name> <!-- 訪問的網(wǎng)址 --> <url-pattern>/TomcatTest/SessionTrack</url-pattern> </servlet-mapping> </web-app>
在瀏覽器地址欄輸入 http://localhost:8080/TomcatTest/SessionTrack,當(dāng)您第一次運行時將顯示如下結(jié)果:

再次嘗試運行相同的 Servlet,它將顯示如下結(jié)果:

當(dāng)您完成了一個用戶的 session 會話數(shù)據(jù),您有以下幾種選擇:
移除一個特定的屬性:您可以調(diào)用 public void removeAttribute(String name) 方法來刪除與特定的鍵相關(guān)聯(lián)的值。
刪除整個 session 會話:您可以調(diào)用 public void invalidate() 方法來丟棄整個 session 會話。
設(shè)置 session 會話過期時間:您可以調(diào)用 public void setMaxInactiveInterval(int interval) 方法來單獨設(shè)置 session 會話超時。
注銷用戶:如果使用的是支持 servlet 2.4 的服務(wù)器,您可以調(diào)用 logout 來注銷 Web 服務(wù)器的客戶端,并把屬于所有用戶的所有 session 會話設(shè)置為無效。
web.xml 配置:如果您使用的是 Tomcat,除了上述方法,您還可以在 web.xml 文件中配置 session 會話超時,如下所示:
<session-config> <session-timeout>15</session-timeout> </session-config>
上面示例中的超時時間是以分鐘為單位,將覆蓋 Tomcat 中默認(rèn)的 30 分鐘超時時間。
在一個 Servlet 中的 getMaxInactiveInterval() 方法會返回 session 會話的超時時間,以秒為單位。所以,如果在 web.xml 中配置 session 會話超時時間為 15 分鐘,那么 getMaxInactiveInterval() 會返回 900。