本文承接系列第二期「有狀態網路的 J2EE 技術」,將焦點從宏觀概覽轉向建立與管理有狀態使用者體驗的細節。創建有狀態應用的基石是資料管理:透過跨會話蒐集使用者資料建立簡檔,進而個人化體驗。為智慧管理使用者資料,必須置於上下文中,故使用「作用域」。
J2EE 提供四種作用域(上下文)管理資料:application(應用程式)、session(會話)、request(請求)、page(頁面)。每種作用域為有狀態開發帶來不同能力,適用不同會話管理場景。
若使用者僅需檢視靜態內容,HTML 即足。但現代使用者追求複雜電子商務交易、線上社群、媒體上傳下載等互動功能,個人化成為關鍵。個人化需具備「持久性」:使用者體驗超越單一交易,如登入 Yahoo 入口網站建立身份,導航全域身份不變;線上銀行、股票交易、購物網站同理。這種跨越單一交易的使用者體驗稱為「會話」,支援會話而非孤立交易的應用即為「有狀態應用」。
有狀態應用中,使用者導航多處、執行多筆交易,仍保持唯一身份,因系統持續追蹤會話狀態。J2EE 透過後端資料伺服器儲存每位使用者資訊管理此類開發:使用者首次登入建立唯一 ID,隨後相關資料被儲存並隨需存取。Java 平台可用 URL 重寫、隱藏表單欄位、HTTP Cookies 關聯使用者 ID,並透過 HttpSession API 儲存、檢索會話資料或關聯特定使用者 ID。
除儲存資料,必須能將資料置於上下文中。「作用域」即指被儲存資料的上下文,妥善處理作用域是有狀態 Web 應用設計核心。
| 作用域 | Servlets | JSP 頁面 | 描述 |
|---|---|---|---|
| page | 否 | 是 | 代表與單一頁面相關的物件與屬性。頁面由編譯後的 Java Servlet 類別表示(含 include 指令,不含 include 動作),包含 Servlet 與編譯為 Servlet 的 JSP。 |
| request | 是 | 是 | 代表與客戶端單一請求相關的物件與屬性。請求可跨越多頁面、涉及多 Web 組件(因 forward 指令與 include 動作)。 |
| session | 是 | 是 | 代表與某客戶端單一使用者體驗相關的物件與屬性。Web 會話常跨越多客戶端請求。 |
| application | 是 | 是 | 代表與整個 Web 應用程式相關的物件與屬性。實質上是跨越整個應用(含多頁面、請求、會話)的全域作用域。 |
四種作用域各有專屬類別儲存與檢索上下文相關資料:
| 類別名稱 | 作用域 | 備註 |
|---|---|---|
| javax.servlet.jsp.PageContext | page | JSP 專用類型,代表當前 JSP 頁面。抽象類別,供 JSP 引擎廠商擴充。實例提供對所有 JSP 頁面相關命名空間的存取。 |
| javax.servlet.http.HttpServletRequest | request | 代表當前 HTTP 請求。介面,供 Servlet 引擎廠商實作。客戶端提供的請求特定資料(方法、URI、HTTP 參數等)及其他 Servlet/JSP 提供的資料可儲於此。 |
| javax.servlet.http.HttpSession | session | 代表當前 HTTP 會話。介面,供 Servlet 引擎廠商實作。 |
| javax.servlet.ServletContext | application | 代表整個運行時 Web 模組。模組,供 Servlet 引擎廠商實作。 |
雖然機制直觀,但釐清特定場景下最適合的作用域並非總是清晰。以下討論常見場景與原則。
提供 JSP 頁面上下文,常與使用者所見頁面一對一對應。僅用於 JSP,為所有物件(含 JavaBean)的預設作用域。page 作用域物件通常為 scriptlet、運算式、JavaBean 標籤、自定義標籤中存取的區域變數。需取得引用時,可在 javax.servlet.jsp.PageContext 變數上呼叫 getAttribute()。
最適合單一使用者請求涉及多 Servlet 或 JSP 頁面的環境。request 是能在單一原子請求內跨越多頁面的上下文。資料儲於 javax.servlet.ServletRequest 物件(使用 HttpServletRequest),透過 getAttribute() 與 setAttribute() 存取。
有狀態 J2EE Web 應用作用域的核心靈魂。使跨越多請求的持久使用者體驗成為可能。資料儲於 javax.servlet.http.HttpSession,透過 getAttribute()、setAttribute() 存取。在 JSP 頁面使用 session 作用域資料,必須先宣告頁面參與會話:於頁面任意處(通常頂部)插入 <%@ page session="true" %>。
壽命最長的作用域,J2EE 提供的全域資料機制。應用程式資料被應用模組內所有 Web 組件共享。物件屬於 javax.servlet.ServletContext,透過 getAttribute()、setAttribute() 存取。
include 指令編譯時處理,指令內容在 page 作用域上下文操作。include 動作運行時處理,若用動作在組件間共享資料,應用 request 作用域。forward 或 include 動作在多組件間共享請求,設資料作用域為 request 即可共享。妥善處理會話作用域(即會話中儲存與維護資料的上下文)是有狀態應用開發關鍵。本文指出四種 J2EE 會話作用域、代表各上下文的多種資料類型,並討論實際考量助您善用作用域。
下月我們將探討 JSP 隱含物件專題。隱含物件為預先定義、所有 JSP 頁面可用的物件,部分提供本文所述四種作用域的存取途徑。下月繼續快樂探索!