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

Struts2 訪問 Servlet API 三大方式:ActionContext、Aware 接口、ServletActionContext

     編輯:Java 綜合教學

前言

Struts2 Action 默認與 Servlet API 解耦,但實際開發中往往需要訪問 Request、Session、Application 等 Servlet 核心對象。本文系統梳理 Struts2 提供的三種訪問機制,對比優缺點,給出最佳實踐建議。

一、核心機制對比總覽

方式核心類/接口耦合度適用場景推薦指數
ActionContext 上下文ActionContext低(Map 代理)只需讀寫屬性值,不依賴 Servlet 原生 API⭐⭐⭐⭐
Aware 接口注入ServletRequestAware 等中(接口依賴)需直接操作原生 Servlet API 對象⭐⭐⭐⭐⭐
工具類靜態獲取ServletActionContext高(靜態依賴)非 Action 類(Service、Util、攔截器)需訪問⭐⭐⭐

二、方式一:ActionContext 上下文訪問(推薦)

核心原理

Struts2 將 Servlet API 封裝為 Map 結構,Action 通過 ActionContext 獲取代理 Map,間接操作底層 Servlet 對象,實現解耦。

常用 API

方法返回類型對應 Servlet API說明
getContext()ActionContext-靜態方法獲取當前線程上下文
getParameters()Maprequest.getParameterMap()獲取所有請求參數
getSession()MapHttpSession操作 Session 屬性(讀寫/移除)
getApplication()MapServletContext操作 Application 屬性
get(key)Objectrequest.getAttribute(key)獲取 Request 屬性
put(key, value)voidrequest.setAttribute(key, value)設置 Request 屬性

代碼示例

public class UserAction extends ActionSupport {
    public String login() {
        // 1. 獲取上下文
        ActionContext ctx = ActionContext.getContext();
        
        // 2. 操作 Session(Map 方式)
        Map session = ctx.getSession();
        session.put("loginUser", currentUser);
        
        // 3. 操作 Application
        Map application = ctx.getApplication();
        Integer onlineCount = (Integer) application.get("onlineCount");
        application.put("onlineCount", onlineCount == null ? 1 : onlineCount + 1);
        
        // 4. 獲取請求參數
        Map params = ctx.getParameters();
        String username = ((String[]) params.get("username"))[0];
        
        return SUCCESS;
    }
}

優缺點分析

  • ✅ 完全解耦 Servlet API,Action 單元測試極其簡單(只需構造 Map)
  • ✅ 代碼簡潔,類 Map 操作符合 Java 習慣
  • ❌ 無法直接訪問 Servlet 原生對象的高級特性(如 request.getInputStream()、response.sendRedirect())
  • ❌ Session/Application Map 非線程安全,高併發下需注意

三、方式二:Aware 接口注入(最常用)

核心接口

接口注入對象典型用途
ServletRequestAwareHttpServletRequest獲取請求頭、輸入流、Request 屬性、轉發
ServletResponseAwareHttpServletResponse設置響應頭、輸出流、重定向、Cookie
ServletContextAwareServletContext讀取配置文件、獲取真實路徑、應用級屬性
SessionAwareMap<String, Object>操作 Session(Struts2 代理 Map,非原生 HttpSession)
PrincipalAwarePrincipal獲取當前登錄用戶主體信息

實現示例

public class FileUploadAction extends ActionSupport 
        implements ServletRequestAware, ServletResponseAware, ServletContextAware {
    
    private HttpServletRequest request;
    private HttpServletResponse response;
    private ServletContext servletContext;
    
    // Struts2 通過 Setter 注入(非構造器注入)
    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
    
    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }
    
    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
    
    public String upload() {
        // 直接使用原生 API
        String realPath = servletContext.getRealPath("/uploads");
        Part filePart = request.getPart("file");  // Servlet 3.0+ 文件上傳
        // ...
        response.setContentType("application/json");
        response.getWriter().write("{\"success\":true}");
        return NONE;  // 已手動輸出響應
    }
}

注意事項

  • 實現接口後,Struts2 會在 Action 實例創建後、調用 execute() 前自動調用 Setter 注入
  • Action 必須是**原型模式**(prototype,默認),否則多線程共享同一實例會導致線程安全問題
  • 單元測試時需手動設置依賴,或使用 Mock 框架(Mockito)模擬

四、方式三:ServletActionContext 工具類(特殊場景)

靜態方法一覽

方法返回類型說明
getRequest()HttpServletRequest獲取當前請求對象
getResponse()HttpServletResponse獲取當前響應對象
getServletContext()ServletContext獲取應用上下文
getPageContext()PageContext獲取 JSP 頁面上下文
getContext()ActionContext等同於 ActionContext.getContext()

適用場景

  • 非 Action 類中訪問 Servlet API:Service 層、工具類、自定義攔截器、監聽器
  • 舊代碼重構過渡期臨時使用

代碼示例

public class ImageUtil {
    public static void writeImage(HttpServletResponse response, BufferedImage image) {
        try {
            // 直接靜態獲取響應對象(不推薦在 Service 中這樣做,破壞分層)
            ServletActionContext.getResponse().setContentType("image/jpeg");
            ImageIO.write(image, "JPEG", ServletActionContext.getResponse().getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException("圖片輸出失敗", e);
        }
    }
}

⚠️ 強烈不建議在 Service/DAO 層使用

破壞分層架構,導致業務邏輯難以單元測試,耦合 Web 容器。正確做法:Controller 接收 Request/Response,提取參數傳給 Service,Service 返回結果對象,Controller 再寫入 Response。

五、最佳實踐總結

  1. 首選 ActionContext Map 方式:簡單屬性讀寫、Session/Application 操作,零耦合,測試友好
  2. 次選 Aware 接口注入:需直接操作原生 Servlet API(流、重定向、Cookie、轉發)時使用
  3. 禁用 ServletActionContext:除非在攔截器、監聽器、工具類等非 Action 環境中被迫使用
  4. Action 必須配置為 prototype 作用域(struts.xml 默認即是),防止線程安全問題
  5. 單元測試策略:
    • ActionContext 方式:構造 Map 注入
    • Aware 接口方式:Mockito mock HttpServletRequest/Response
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved