當自動綁定無法滿足需求(如動態參數名、攔截器預處理、需直接操作 Servlet API)時,Struts 2 提供兩大核心上下文類:ActionContext(框架級、線程安全)與 ServletActionContext(Servlet 級、繼承前者)。
ActionContext 內部靜態持有 ThreadLocal<ActionContext>,每個請求線程獨享上下文副本,保證線程安全。因此絕不可在構造函數或屬性初始化處調用 getContext() 或 getRequest(),必須在具體 Action 方法(execute()、login() 等)內調用,確保當前線程已綁定上下文。
ActionContext ctx = ActionContext.getContext();
// 1. 獲取請求參數 (Map<String, String[]>)
Map<String, String[]> params = ctx.getParameters();
String username = params.get("username")[0]; // 注意:值為數組
// 2. 獲取/設置 Session (Map<String, Object>)
Map<String, Object> session = ctx.getSession();
session.put("loginUser", user); // 相當於 session.setAttribute
User u = (User) session.get("loginUser");
// 3. 獲取 Request/Response (需 StrutsStatics 常量)
HttpServletRequest req = (HttpServletRequest) ctx.get(StrutsStatics.HTTP_REQUEST);
HttpServletResponse resp = (HttpServletResponse) ctx.get(StrutsStatics.HTTP_RESPONSE);
ServletContext sc = (ServletContext) ctx.get(StrutsStatics.SERVLET_CONTEXT);
優點:不依賴 Servlet API、單元測試友好(可 Mock Map)。
注意:Session 底層已被封裝為 Map,直接操作即可,無需取出 HttpSession。
// 必須在 Action 方法內調用!
HttpServletRequest req = ServletActionContext.getRequest();
HttpServletResponse resp = ServletActionContext.getResponse();
HttpSession session = req.getSession(); // 原生 HttpSession
ServletContext sc = ServletActionContext.getServletContext();
PageContext pageContext = ServletActionContext.getPageContext();
適用場景:需設定響應頭、Cookie、輸出流、文件上傳/下載等 Servlet 原生操作。
實作對應 Aware 接口,框架自動注入:
public class UserAction extends ActionSupport
implements SessionAware, ServletRequestAware, ServletResponseAware {
private Map<String, Object> session; // 注入 Session Map
private HttpServletRequest request;
private HttpServletResponse response;
@Override public void setSession(Map<String, Object> session) { this.session = session; }
@Override public void setServletRequest(HttpServletRequest request) { this.request = request; }
@Override public void setServletResponse(HttpServletResponse response) { this.response = response; }
public String login() {
session.put("user", user); // 直接用 Map
// 或用原生 request
request.getSession().setAttribute("user", user);
return SUCCESS;
}
}
優點:依賴注入、無靜態調用、測試極易(直接傳 Map/Mock Request)。
原理:ServletConfigInterceptor 攔截器識別 Aware 接口並回調 Setter 注入。
ctx.getParameters() 返回 Map<String, String[]>,單值取 [0],多值(checkbox)遍歷數組。ctx.getSession() 若 Session 未建立會自動創建,等同 request.getSession(true)。ServletActionContext.getRequest() 獲取 MultipartRequest 或配合 FileUploadInterceptor 使用 File 屬性自動注入。