Servlet Session 跟蹤

2022-07-23 14:33 更新

Servlet Session 跟蹤

HTTP 是一種"無(wú)狀態(tài)"協(xié)議,這意味著每次客戶端檢索網(wǎng)頁(yè)時(shí),客戶端打開(kāi)一個(gè)單獨(dú)的連接到 Web 服務(wù)器,服務(wù)器會(huì)自動(dòng)不保留之前客戶端請(qǐng)求的任何記錄。

但是仍然有以下三種方式來(lái)維持 Web 客戶端和 Web 服務(wù)器之間的 session 會(huì)話:

Cookies

一個(gè) Web 服務(wù)器可以分配一個(gè)唯一的 session 會(huì)話 ID 作為每個(gè) Web 客戶端的 cookie,對(duì)于客戶端的后續(xù)請(qǐng)求可以使用接收到的 cookie 來(lái)識(shí)別。

這可能不是一個(gè)有效的方法,因?yàn)楹芏酁g覽器不支持 cookie,所以我們建議不要使用這種方式來(lái)維持 session 會(huì)話。

隱藏的表單字段

一個(gè) Web 服務(wù)器可以發(fā)送一個(gè)隱藏的 HTML 表單字段,以及一個(gè)唯一的 session 會(huì)話 ID,如下所示:

<input type="hidden" name="sessionid" value="12345">

該條目意味著,當(dāng)表單被提交時(shí),指定的名稱(chēng)和值會(huì)被自動(dòng)包含在 GET 或 POST 數(shù)據(jù)中。每次當(dāng) Web 瀏覽器發(fā)送回請(qǐng)求時(shí),session_id 值可以用于保持不同的 Web 瀏覽器的跟蹤。

這可能是一種保持 session 會(huì)話跟蹤的有效方式,但是點(diǎn)擊常規(guī)的超文本鏈接(<A HREF...>)不會(huì)導(dǎo)致表單提交,因此隱藏的表單字段也不支持常規(guī)的 session 會(huì)話跟蹤。

URL 重寫(xiě)

您可以在每個(gè) URL 末尾追加一些額外的數(shù)據(jù)來(lái)標(biāo)識(shí) session 會(huì)話,服務(wù)器會(huì)把該 session 會(huì)話標(biāo)識(shí)符與已存儲(chǔ)的有關(guān) session 會(huì)話的數(shù)據(jù)相關(guān)聯(lián)。

例如,http://w3cschool.cn/file.htm;sessionid=12345,session 會(huì)話標(biāo)識(shí)符被附加為 sessionid=12345,標(biāo)識(shí)符可被 Web 服務(wù)器訪問(wèn)以識(shí)別客戶端。

URL 重寫(xiě)是一種更好的維持 session 會(huì)話的方式,它在瀏覽器不支持 cookie 時(shí)能夠很好地工作,但是它的缺點(diǎn)是會(huì)動(dòng)態(tài)生成每個(gè) URL 來(lái)為頁(yè)面分配一個(gè) session 會(huì)話 ID,即使是在很簡(jiǎn)單的靜態(tài) HTML 頁(yè)面中也會(huì)如此。

HttpSession 對(duì)象

除了上述的三種方式,Servlet 還提供了 HttpSession 接口,該接口提供了一種跨多個(gè)頁(yè)面請(qǐng)求或訪問(wèn)網(wǎng)站時(shí)識(shí)別用戶以及存儲(chǔ)有關(guān)用戶信息的方式。

Servlet 容器使用這個(gè)接口來(lái)創(chuàng)建一個(gè) HTTP 客戶端和 HTTP 服務(wù)器之間的 session 會(huì)話。會(huì)話持續(xù)一個(gè)指定的時(shí)間段,跨多個(gè)連接或頁(yè)面請(qǐng)求。

您會(huì)通過(guò)調(diào)用 HttpServletRequest 的公共方法 getSession() 來(lái)獲取 HttpSession 對(duì)象,如下所示:

HttpSession session = request.getSession();

你需要在向客戶端發(fā)送任何文檔內(nèi)容之前調(diào)用 request.getSession()。下面總結(jié)了 HttpSession 對(duì)象中可用的幾個(gè)重要的方法:

序號(hào)方法 & 描述
1public Object getAttribute(String name)
該方法返回在該 session 會(huì)話中具有指定名稱(chēng)的對(duì)象,如果沒(méi)有指定名稱(chēng)的對(duì)象,則返回 null。
2public Enumeration getAttributeNames()
該方法返回 String 對(duì)象的枚舉,String 對(duì)象包含所有綁定到該 session 會(huì)話的對(duì)象的名稱(chēng)。
3public long getCreationTime()
該方法返回該 session 會(huì)話被創(chuàng)建的時(shí)間,自格林尼治標(biāo)準(zhǔn)時(shí)間 1970 年 1 月 1 日午夜算起,以毫秒為單位。
4public String getId()
該方法返回一個(gè)包含分配給該 session 會(huì)話的唯一標(biāo)識(shí)符的字符串。
5public long getLastAccessedTime()
該方法返回客戶端最后一次發(fā)送與該 session 會(huì)話相關(guān)的請(qǐng)求的時(shí)間自格林尼治標(biāo)準(zhǔn)時(shí)間 1970 年 1 月 1 日午夜算起,以毫秒為單位。
6public int getMaxInactiveInterval()
該方法返回 Servlet 容器在客戶端訪問(wèn)時(shí)保持 session 會(huì)話打開(kāi)的最大時(shí)間間隔,以秒為單位。
7public void invalidate()
該方法指示該 session 會(huì)話無(wú)效,并解除綁定到它上面的任何對(duì)象。
8public boolean isNew(
如果客戶端還不知道該 session 會(huì)話,或者如果客戶選擇不參入該 session 會(huì)話,則該方法返回 true。
9public void removeAttribute(String name)
該方法將從該 session 會(huì)話移除指定名稱(chēng)的對(duì)象。
10public void setAttribute(String name, Object value)
該方法使用指定的名稱(chēng)綁定一個(gè)對(duì)象到該 session 會(huì)話。
11public void setMaxInactiveInterval(int interval)
該方法在 Servlet 容器指示該 session 會(huì)話無(wú)效之前,指定客戶端請(qǐng)求之間的時(shí)間,以秒為單位。

Session 跟蹤實(shí)例

本實(shí)例說(shuō)明了如何使用 HttpSession 對(duì)象獲取 session 會(huì)話創(chuàng)建時(shí)間和最后訪問(wèn)時(shí)間。如果不存在 session 會(huì)話,我們將通過(guò)請(qǐng)求創(chuàng)建一個(gè)新的 session 會(huì)話。

// 導(dǎo)入必需的 java 庫(kù)
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
 
// 擴(kuò)展 HttpServlet 類(lèi)
public class SessionTrack extends HttpServlet {
 
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 如果不存在 session 會(huì)話,則創(chuàng)建一個(gè) session 對(duì)象
      HttpSession session = request.getSession(true);
      // 獲取 session 創(chuàng)建時(shí)間
      Date createTime = new Date(session.getCreationTime());
      // 獲取該網(wǎng)頁(yè)的最后一次訪問(wèn)時(shí)間
      Date lastAccessTime = 
                        new Date(session.getLastAccessedTime());

      String title = "歡迎回到我的網(wǎng)站";
      Integer visitCount = new Integer(0);
      String visitCountKey = new String("visitCount");
      String userIDKey = new String("userID");
      String userID = new String("ABCD");

      // 檢查網(wǎng)頁(yè)上是否有新的訪問(wèn)者
      if (session.isNew()){
         title = "歡迎來(lái)到我的網(wǎng)站";
         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)容類(lèi)型
      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 信息</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>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é)果:

歡迎來(lái)到我的網(wǎng)站

Session 信息

Session 信息
id 0AE3EC93FF44E3C525B4351B77ABB2D5
Creation Time Tue Jun 08 17:26:40 GMT+04:00 2014
Time of Last Access Tue Jun 08 17:26:40 GMT+04:00 2014
User ID ABCD
Number of visits 0

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

歡迎回到我的網(wǎng)站

Session 信息

Session 信息
id 0AE3EC93FF44E3C525B4351B77ABB2D5
Creation Time Tue Jun 08 17:26:40 GMT+04:00 2014
Time of Last Access Tue Jun 08 17:26:40 GMT+04:00 2014
User ID ABCD
Number of visits 1

刪除 Session 會(huì)話數(shù)據(jù)

當(dāng)您完成了一個(gè)用戶的 session 會(huì)話數(shù)據(jù),您有以下幾種選擇:

  • 移除一個(gè)特定的屬性:您可以調(diào)用 public void removeAttribute(String name) 方法來(lái)刪除與特定的鍵相關(guān)聯(lián)的值。 to delete the value associated with a particular key.
  • 刪除整個(gè) session 會(huì)話:您可以調(diào)用 public void invalidate() 方法來(lái)丟棄整個(gè) session 會(huì)話。
  • 設(shè)置 session 會(huì)話過(guò)期時(shí)間:您可以調(diào)用 public void setMaxInactiveInterval(int interval) 方法來(lái)單獨(dú)設(shè)置 session 會(huì)話超時(shí)。
  • 注銷(xiāo)用戶:如果使用的是支持 servlet 2.4 的服務(wù)器,您可以調(diào)用 logout 來(lái)注銷(xiāo) Web 服務(wù)器的客戶端,并把屬于所有用戶的所有 session 會(huì)話設(shè)置為無(wú)效。
  • web.xml 配置:如果您使用的是 Tomcat,除了上述方法,您還可以在 web.xml 文件中配置 session 會(huì)話超時(shí),如下所示:
  <session-config>
    <session-timeout>15</session-timeout>
  </session-config>

上面實(shí)例中的超時(shí)時(shí)間是以分鐘為單位,將覆蓋 Tomcat 中默認(rèn)的 30 分鐘超時(shí)時(shí)間。

在一個(gè) Servlet 中的 getMaxInactiveInterval() 方法會(huì)返回 session 會(huì)話的超時(shí)時(shí)間,以秒為單位。所以,如果在 web.xml 中配置 session 會(huì)話超時(shí)時(shí)間為 15 分鐘,那么 getMaxInactiveInterval() 會(huì)返回 900。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)