在 Web 應用程式開發中,Session 是維持伺服器端與客戶端之間狀態的關鍵機制,例如電商網站需在用戶登入後持續驗證身分權限。傳統做法直接在 Controller 中使用 HttpServletRequest 獲取 HttpSession,雖然直觀,卻造成程式碼強依賴 Servlet API,導致單元測試困難、程式碼耦合度高、難以復用。
Spring 2.5 引入註解驅動的 Controller 模型,提供了多種優雅的方式來存取 Session 屬性,本文將深入剖析四種核心策略,並從設計原則角度探討其優劣與適用場景。
最直觀的方式是在 Action 方法參數中聲明 HttpSession 或 HttpServletRequest,Spring 會自動綁定注入。
@RequestMapping
public void hello(HttpSession session) {
User user = (User) session.getAttribute("currentUser");
// 業務邏輯...
}
利用 Spring MVC 的 HandlerInterceptor,在 preHandle 階段將 User 物件注入實作特定介面(如 IUserAware)的 Controller 成員變數中。
public class UserInjectInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof IUserAware) {
User user = (User) request.getSession().getAttribute("currentUser");
((IUserAware) handler).setUser(user);
}
return true;
}
}
Spring MVC 提供 WebArgumentResolver(後續版本為 HandlerMethodArgumentResolver)擴展點,針對 Action 參數類型進行自定義解析注入。
public class UserArgumentResolver implements WebArgumentResolver { public Object resolveArgument(MethodParameter param, NativeWebRequest webRequest) { if (param.getParameterType().equals(User.class)) { return webRequest.getAttribute("currentUser", RequestAttributes.SCOPE_SESSION); } return UNRESOLVED; } }@RequestMapping public void hello(User user) { // 直接使用 user 物件 }優點
利用 Spring MVC 內建的 @SessionAttributes 與 @ModelAttribute 協作,將 Session 中指定名稱的屬性自動綁定至 Action 參數。
@SessionAttributes 設計初衷(原為表單資料跨請求保持),可能引發語意爭議。四種策略的演進路徑清晰可見:從「全域強耦合」→「Controller 層級注入」→「Action 層級統一注入」→「Action 層級精確聲明」。每種方案皆為特定上下文下的最優解:
選型核心在於權衡「依賴反轉程度」、「注入粒度」、「程式碼冗餘度」與「語意純粹度」。建議團隊建立架構決策記錄(ADR),根據專案規模、團隊習慣、測試策略統一規範,避免專案中混用多種風格導致維護混亂。
後續文章將深入探討這些選擇背後的 OOP 設計原則(如單一職責、介面隔離、依賴反轉)在實戰中的體現,敬請期待。