HTTP 是一種“無狀態(tài)”協(xié)議,這意味著每次客戶端檢索 Web 頁面時(shí),客戶端打開一個(gè)單獨(dú)的連接到 Web 服務(wù)器,服務(wù)器不會(huì)自動(dòng)保存之前客戶端請(qǐng)求的任何記錄。
仍然有以下三種方式來維持 web 客戶端和 web 服務(wù)器之間的會(huì)話:
一個(gè) web 服務(wù)器可以分配一個(gè)唯一的會(huì)話 ID 作為每個(gè) web 客戶端的 cookie,并且對(duì)于來自客戶端的后續(xù)請(qǐng)求,它們可以使用已接收的 cookie 來識(shí)別。
這可能不是一個(gè)有效的方法,因?yàn)楹芏鄷r(shí)候?yàn)g覽器不支持 cookie,所以我不建議使用這種方式來維持會(huì)話。
一個(gè) web 服務(wù)器可以發(fā)送一個(gè)隱藏的 HTML 表單字段以及一個(gè)唯一的會(huì)話 ID,如下所示:
<input type="hidden" name="sessionid" value="12345">
該條目意味著,當(dāng)表單被提交時(shí),指定的名稱和值會(huì)被自動(dòng)包含在 GET 或 POST 數(shù)據(jù)中。每次當(dāng) web 瀏覽器發(fā)送回請(qǐng)求時(shí),session_id 的值可以用于跟蹤不同的 web 瀏覽器。
這可能是保持會(huì)話跟蹤的一種有效的方式,但是點(diǎn)擊常規(guī)的(<A HREF...>)
超文本鏈接不會(huì)導(dǎo)致表單提交,因此隱藏的表單字段也不支持常規(guī)的會(huì)話跟蹤。
你可以在每個(gè)標(biāo)識(shí)會(huì)話的 URL 末尾追加一些額外的數(shù)據(jù),且服務(wù)器會(huì)把該會(huì)話標(biāo)識(shí)符與它已存儲(chǔ)的有關(guān)會(huì)話的數(shù)據(jù)關(guān)聯(lián)起來。
例如,http://w3cschool.cn/file.htm;sessionid=12345
,會(huì)話標(biāo)識(shí)符被附加為 sessionid=12345,可能會(huì)在 web 服務(wù)器端被訪問來識(shí)別客戶端。
URL 重寫是維持會(huì)話的一種更好的方式,當(dāng)瀏覽器不支持 cookie 時(shí)為瀏覽器工作,但是它的缺點(diǎn)是會(huì)動(dòng)態(tài)的生成每個(gè) URL 來分配會(huì)話 ID,即使頁面是簡(jiǎn)單的靜態(tài)的 HTML 頁面。
除了上述提到的三種方式,servlet 還提供了 HttpSession 接口,該接口提供了一種對(duì)網(wǎng)站的跨多個(gè)頁面請(qǐng)求或訪問的方法來識(shí)別用戶并存儲(chǔ)有關(guān)用戶的信息。
Servlet 容器使用這個(gè)接口來創(chuàng)建在 HTTP 客戶端和 HTTP 服務(wù)器之間的會(huì)話。會(huì)話在一個(gè)指定的時(shí)間段內(nèi)持續(xù),跨多個(gè)連接或來自用戶的請(qǐng)求。
你可以通過調(diào)用 HttpServletRequest 的公共方法 getSession() 來獲取 HttpSession 對(duì)象,如下所示:
HttpSession session = request.getSession();
在向客戶端發(fā)送任何文檔內(nèi)容之前,你需要調(diào)用 request.getSession()。這里是一些重要方法的總結(jié),這些方法通過 HttpSession 對(duì)象是可用的:
序號(hào) | 方法 & 描述 |
---|---|
1 |
public Object getAttribute(String name) 該方法返回在該 session 會(huì)話中具有指定名稱的對(duì)象,如果沒有指定名稱的對(duì)象,則返回 null。 |
2 |
public Enumeration getAttributeNames() 該方法返回 String 對(duì)象的枚舉,String 對(duì)象包含所有綁定到該 session 會(huì)話的對(duì)象的名稱。 |
3 |
public long getCreationTime() 該方法返回該 session 會(huì)話被創(chuàng)建的時(shí)間,自格林尼治標(biāo)準(zhǔn)時(shí)間 1970 年 1 月 1 日凌晨零點(diǎn)算起,以毫秒為單位。 |
4 |
public String getId() 該方法返回一個(gè)包含分配給該 session 會(huì)話的唯一標(biāo)識(shí)符的字符串。 |
5 |
public long getLastAccessedTime() 該方法返回客戶端最后一次發(fā)送與該 session 會(huì)話相關(guān)的請(qǐng)求的時(shí)間自格林尼治標(biāo)準(zhǔn)時(shí)間 1970 年 1 月 1 日凌晨零點(diǎn)算起,以毫秒為單位。 |
6 |
public int getMaxInactiveInterval() 該方法返回 Servlet 容器在客戶端訪問時(shí)保持 session 會(huì)話打開的最大時(shí)間間隔,以秒為單位。 |
7 |
public void invalidate() 該方法指示該 session 會(huì)話無效,并解除綁定到它上面的任何對(duì)象。 |
8 |
public boolean isNew( 如果客戶端還不知道該 session 會(huì)話,或者如果客戶選擇不參入該 session 會(huì)話,則該方法返回 true。 |
9 |
public void removeAttribute(String name) 該方法將從該 session 會(huì)話移除指定名稱的對(duì)象。 |
10 |
public void setAttribute(String name, Object value) 該方法使用指定的名稱綁定一個(gè)對(duì)象到該 session 會(huì)話。 |
11 |
public void setMaxInactiveInterval(int interval) 該方法在 Servlet 容器指示該 session 會(huì)話無效之前,指定客戶端請(qǐng)求之間的時(shí)間,以秒為單位。 |
這個(gè)例子描述了如何使用 HttpSession 對(duì)象獲取會(huì)話創(chuàng)建時(shí)間和上次訪問的時(shí)間。如果不存在會(huì)話,我們將一個(gè)新的會(huì)話與請(qǐng)求聯(lián)系起來。
// 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>");
}
}
編譯上述 servlet SessionTrack 并在 web.xml 文件中創(chuàng)建適當(dāng)?shù)臈l目。在瀏覽器地址欄輸入 http://localhost:8080/SessionTrack
,當(dāng)你第一次運(yùn)行時(shí)將顯示如下所示的結(jié)果:
Welcome to my website Session Infomation
現(xiàn)在嘗試再次運(yùn)行相同的 servlet,它將顯示如下所示的結(jié)果:
Welcome Back to my website Session Infomation
當(dāng)你完成了一個(gè)用戶的會(huì)話數(shù)據(jù),你有以下幾種選擇:
移除一個(gè)特定的屬性:你可以調(diào)用 public void removeAttribute(String name) 方法來刪除與特定的鍵相關(guān)聯(lián)的值。
刪除整個(gè)會(huì)話:你可以調(diào)用 public void invalidate() 方法來刪除整個(gè)會(huì)話。
設(shè)置會(huì)話超時(shí):你可以調(diào)用 public void setMaxInactiveInterval(int interval) 方法來單獨(dú)設(shè)置會(huì)話超時(shí)。
注銷用戶:支持 servlet 2.4 的服務(wù)器,你可以調(diào)用 logout 來注銷 Web 服務(wù)器的客戶端,并把屬于所有用戶的所有會(huì)話設(shè)置為無效。
<session-config>
<session-timeout>15</session-timeout>
</session-config>
超時(shí)時(shí)間是以分鐘為單位的,并覆蓋了 Tomcat 中默認(rèn)的 30 分鐘的超時(shí)時(shí)間。
Servlet 中的 getMaxInactiveInterval() 方法為會(huì)話返回的超時(shí)時(shí)間是以秒為單位的。所以如果在 web.xml 中配置會(huì)話超時(shí)時(shí)間為 15 分鐘,那么 getMaxInactiveInterval() 會(huì)返回 900。
更多建議: