首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Struts2 獲取 Servlet API 三大方式深度對比:耦合度與可測試性權衡

     編輯:Java 綜合教學

Struts2 獲取 Servlet API 三大方式深度對比:耦合度與可測試性權衡

Struts2 核心設計目標是降低 Action 對 Servlet API 的依賴,提升可測試性。但在實際開發中,仍需訪問 HttpServletRequest、HttpSession、ServletContext。框架提供三種獲取途徑,耦合度遞增,靈活度遞增。

方式一:ActionContext 線程局部變量 (推薦,零耦合)

透過 ActionContext.getContext() 獲取上下文 Map,完全不依賴 Servlet API,單元測試極其方便 (無需 Mock Servlet 容器)。

public class MyAction extends ActionSupport {
    public String execute() {
        // 獲取 Request 參數 Map
        Map<String, Object> params = ActionContext.getContext().getParameters();
        // 獲取/設置 Session
        Map<String, Object> session = ActionContext.getContext().getSession();
        session.put("user", "admin");
        // 獲取 Application (ServletContext)
        Map<String, Object> application = ActionContext.getContext().getApplication();
        application.put("globalConfig", loadConfig());
        return SUCCESS;
    }
}

優點:POJO 化,極易測試。缺點:無法直接操作原生 HttpServletRequest 特有功能 (如 getInputStream()、getHeader()、上傳文件處理等)。

方式二:實現 *Aware 接口 (官方推薦,低耦合)

Action 實現特定接口,框架在構建 Action 時自動注入對應 Map 封裝。仍不直接暴露 Servlet API 原生物件,但比方式一功能豐富。

  • ServletRequestAware → setServletRequest(Map<String, Object> request):獲取請求參數、屬性 Map。
  • SessionAware → setSession(Map<String, Object> session):操作 Session Map。
  • ServletContextAware → setServletContext(Map<String, Object> application):操作 Application Map。
  • RequestAware / ParameterAware / PrincipalAware 等細粒度接口。
public class MyAction implements SessionAware, ServletRequestAware {
    private Map<String, Object> session;
    private Map<String, Object> request;

    @Override public void setSession(Map<String, Object> session) { this.session = session; }
    @Override public void setServletRequest(Map<String, Object> request) { this.request = request; }

    public String execute() {
        request.put("attr", "value"); // 設置請求屬性
        session.put("loginUser", getUser()); // 寫入 Session
        return SUCCESS;
    }
}

優點:類型安全注入,代碼清晰;Map 封裝隔離 Servlet API,測試時構造 Map 即可。缺點:若需原生 HttpServletRequest 方法 (如獲取 Header、Cookie、Client IP),仍無法滿足。

方式三:ServletActionContext 靜態訪問 (強耦合,慎用)

直接獲取原生 Servlet API 物件,完全綁定 Servlet 容器,單元測試需完整 Mock 環境 (如 Spring MockMvc、Mockito 模擬)。

import org.apache.struts2.ServletActionContext;

public class MyAction {
    public String execute() {
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        ServletContext application = ServletActionContext.getServletContext();

        String ip = request.getRemoteAddr(); // 獲取客戶端 IP
        String ua = request.getHeader("User-Agent"); // 獲取 Header
        Cookie[] cookies = request.getCookies(); // 操作 Cookie
        // 文件上傳需 request.getInputStream() / MultipartRequestWrapper
        return SUCCESS;
    }
}

適用場景:文件上傳處理、複雜 Header/Cookie 操作、整合 legacy Servlet 代碼、第三方庫需原生 Request/Response 時。原則:能用方式一/二絕不用方式三。

總結對比表

維度ActionContext (方式一)*Aware 接口 (方式二)ServletActionContext (方式三)
Servlet API 耦合度零 (Map 封裝)低 (Map 封裝)高 (原生物件)
單元測試難度極低 (構造 Map)低 (構造 Map 注入)高 (需 Mock 容器)
功能完整性基礎屬性/參數/Session/Application同上,注入更結構化100% 原生功能
推薦指數⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ (特定場景)

最佳實踐建議

  1. 優先使用 實現 *Aware 接口,代碼結構清晰,依賴注入語義明確。
  2. 簡單臨時讀取參數/屬性可用 ActionContext.getContext()。
  3. 嚴禁在 Service/DAO 層使用方式三,污染業務層純粹性。
  4. 文件上傳、複雜 Header 解析等必須原生 API 時,僅在 Action 方法內部 使用 ServletActionContext,完成後立即轉換為領域模型傳給 Service。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved