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 物件中可用的幾個重要的方法:

序號方法& 描述
#1public Object getAttribute(String name )
該方法傳回在該session 會話中具有指定名稱的對象,如果沒有指定名稱的對象,則傳回null。
2public Enumeration getAttributeNames()
該方法傳回String 物件的枚舉,String 物件包含所有綁定到該session 會話的物件的名稱。
3public long getCreationTime()
該方法傳回該session 會話被建立的時間,自格林尼治標準時間1970 年1 月1 日午夜算起,以毫秒為單位。
4public String getId()
該方法傳回一個包含指派給該session 會話的唯一識別碼的字串。
5public long getLastAccessedTime()
該方法傳回客戶端最後一次傳送與該session 會話相關的請求的時間自格林尼治標準時間1970 年1 月1 日午夜算起,以毫秒為單位。
6public int getMaxInactiveInterval()
該方法傳回Servlet 容器在客戶端存取時保持session 會話開啟的最大時間間隔,以秒為單位。
7public void invalidate()
該方法指示該session 會話無效,並解除綁定到它上面的任何對象。
8public boolean isNew(
如果客戶端還不知道該session 會話,或者如果客戶選擇不參入該session會話,則該方法傳回true。移除指定名稱的物件。名稱綁定一個物件到該session 會話。指示該session 會話無效之前,指定客戶端請求之間的時間,以秒為單位。

Session 追蹤實例

本實例說明如何使用 HttpSession 物件取得 session 會話建立時間和最後存取時間。如果不存在 session 會話,我們將透過請求建立一個新的 session 會話。

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
 
// 扩展 HttpServlet 类
public class SessionTrack extends HttpServlet {
 
  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());

      String title = "欢迎回到我的网站";
      Integer visitCount = new Integer(0);
      String visitCountKey = new String("visitCount");
      String userIDKey = new String("userID");
      String userID = new String("ABCD");

      // 检查网页上是否有新的访问者
      if (session.isNew()){
         title = "欢迎来到我的网站";
         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");
      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 檔案中建立適當的條目。在瀏覽器網址列輸入http://localhost:8080/SessionTrack,當您第一次執行時將顯示下列結果:

歡迎來到我的網站

Session 訊息

Session 訊息
id 0AE3EC93FF44E3C525B4351B77ABB2D5
Creation TimeTue Jun 08 17:26:40 GMT+04:00 2014
#n AccessTue Jun 08 17:26:40 GMT+04:00 2014
User ID##ABCD
#Number of visits0

#再次嘗試執行相同的Servlet,它將顯示如下結果:

歡迎回到我的網站

Session 訊息

##id0AE3EC93FF44E3C525B4351B77ABB2D5Creation TimeTue Jun 08 17:26:40 GMT+04:#Time of Last AccessTue Jun 08 17:26:40 GMT+04:00 2014#User ID#ABCDNumber of visits1#

刪除Session 會話資料

當您完成了一個使用者的session 會話數據,您有以下幾個選擇:

  • 移除一個特定的屬性:您可以呼叫public void removeAttribute(String name) 方法來刪除與特定的鍵相關聯的值。 to delete the value associated with a particular key.

  • 刪除整個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。

#Session 訊息
##Tue Jun 08 17:26:40 GMT+04:00##2014