Struts2 核心設計目標是降低 Action 對 Servlet API 的依賴,提升可測試性。但在實際開發中,仍需訪問 HttpServletRequest、HttpSession、ServletContext。框架提供三種獲取途徑,耦合度遞增,靈活度遞增。
透過 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()、上傳文件處理等)。
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),仍無法滿足。
直接獲取原生 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% 原生功能 |
| 推薦指數 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ (特定場景) |
ActionContext.getContext()。ServletActionContext,完成後立即轉換為領域模型傳給 Service。