1.8.2 Session

相對於Cookie, 另一個解決方案就是Session, 不一樣的地方是, Session是透過server來保持狀態的. 由於Session這個詞的意思很多, 這邊先明確定義一下我們要討論的範圍. 通常我們稱Session為會話或是期程, 我們可以把client跟server之間一系列互動的動作稱為一個Session. 從這個語意出發的話, 我們會提到Session持續的時間, 會提到在Session過程中進行了什麼操作等等; 其次, Session指的是server端為client所開闢的儲存空間, 而該空間中保存的訊息就是用來保持狀態的. 最後, 也會提到Session中存放什麼內容, 如何根據key值從Session中取得匹配的內容(value)等.

首先, 要使用Session, 第一步就是要建立Session. 至於建立的時間點, 基本上是在server端的程式運作的過程中建立的, 不同的程式語言實作的應用程式有不同的建立Session的方法, 在Java中, 是通過呼叫HttpServletRequest的getSession方法(以true作為參數, 表示若尚未存在HttpSession實例時, 直接建立一個新的物件. 以false為參數, 表示若尚未存在HttpSession實例,則直接傳回null)來建立的.

HttpSession session = request.getSession();

在建立了Session的同時, server會為該Session生成唯一的Session id, 而這個id會在往後的request中被用來重新獲得已經建立的Session; 在Session被建立後, 就可以呼叫Session相關的方法往Session中增加內容了, 而這些內容只會保存在server中, 發送到client的就只有Session id; 當client再次發送request的時候, 會將這個Session id帶上, server在收到了request之後就會根據Session id找出相對應的Session物件, 並且重複利用此Session. 透過這樣的過程, 就可以保存狀態了.

在使用上, HttpSession最常被呼叫到的方法大概就是setAttribute跟getAttribute了, 這可以讓你在Session物件中設置與取得attribute.

下面有一個簡單的範例, 假設今天我們有一個index.jsp, 且此jsp頁面上有兩個連結, 分別將request轉到FirstServlet以及SecondServlet, 其中, FirstServlet的主要內容如下:

public class FirstServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute("name", "RuRu");

        HttpSession session = request.getSession();
        session.setAttribute("name", "MaoMao");

        request.getRequestDispatcher("index.jsp").forward(request, response);

    }

}

邏輯很單純, 將request的name屬性之值設定為"RuRu", 而session的name屬性之值則設定為"MaoMao", 然後送回index頁面.

而SecondServlet的內容如下:

public class SecondServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String requestName = (String) request.getAttribute("name"); 
        System.out.println("requestName:" + requestName);

        HttpSession session = request.getSession();
        String sessionName = (String) session.getAttribute("name"); 
        System.out.println("sessionName:" + sessionName);

        request.getRequestDispatcher("index.jsp").forward(request, response); 
    }

}

首先把request的name屬性之值取出來, 然後再把session的name屬性之值取出來, 然後送回index頁面.

在實際操作上, 如下步驟:

  1. 進入index.jsp

  2. 點擊呼叫FirstServlet的url

  3. 點擊呼叫SecondServlet的url

此時在server端的console應該會看到如下輸出:

requestName:null

requestName:MaoMao

原因很簡單, 因為request的屬性狀態無法保留, 即FirstServlet與SecondServlet中的request並不是同一個, 所以在SecondServlet的request中是找不到name屬性的. 至於session的部分, 可以看得出來是可以保留的, 因為當client發出第一個request給Container時, Container就會自動為此次連線建立一個session id並紀錄起來, 然後將session id存放在回應給客戶端的response物件中, 當下一次客戶端再送出新的request時, 瀏覽器會將session id一起送給Container, 當Container檢查到這個request中的session id與先前紀錄的session id相同, 就會認得這次的請求的session了.

另一個要注意的是, session是non thread-safe的, 所以操作來自同個client的session物件時要留意一下.

Last updated