Struts2 访问 Web 资源的两种方式详解
在 Struts2 框架中,Web 资源(如HttpServletRequest
、HttpSession
、ServletContext
等)的访问方式分为与 Servlet API 解耦和与 Servlet API 耦合两种。两种方式各有适用场景,下面详细解析其实现方式与使用场景。
与 Servlet API 解耦的方式
这种方式通过 Struts2 封装的 API 访问 Web 资源,不直接依赖 Servlet 原生类,便于进行单元测试,适合大多数业务场景。
1. 使用 ActionContext(核心方式)
ActionContext
是 Struts2 的上下文对象,封装了当前请求的所有信息,可通过它间接访问 Web 资源对应的 Map 对象。
核心方法与示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import com.opensymphony.xwork2.ActionContext; import java.util.Map;
public class UserAction { public String execute() { ActionContext actionContext = ActionContext.getContext();
Map<String, Object> applicationMap = actionContext.getApplication(); applicationMap.put("appKey", "全局应用数据"); Object appValue = applicationMap.get("appKey");
Map<String, Object> sessionMap = actionContext.getSession(); sessionMap.put("userName", "张三"); Object user = sessionMap.get("userName");
Map<String, Object> requestMap = (Map<String, Object>) actionContext.get("request"); requestMap.put("msg", "请求数据"); Object msg = requestMap.get("msg");
Map<String, Object> params = actionContext.getParameters(); String[] ids = (String[]) params.get("id"); String name = (String) params.get("name");
return "success"; } }
|
特点:
- 间接访问:通过
Map
对象模拟 Servlet 域对象,操作方式与原生 API 类似;
- 线程安全:
ActionContext
与当前请求绑定,线程安全;
- 局限性:无法调用 Servlet 原生方法(如
request.getHeader()
)。
2. 实现 XxxAware 接口(依赖注入方式)
Struts2 提供了一系列Aware
接口,通过依赖注入(DI)方式将 Web 资源的 Map 对象注入 Action,更符合面向接口编程思想。
常用接口与示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import org.apache.struts2.interceptor.ApplicationAware; import org.apache.struts2.interceptor.RequestAware; import org.apache.struts2.interceptor.SessionAware; import java.util.Map;
public class TestAwareAction implements ApplicationAware, SessionAware, RequestAware { private Map<String, Object> application; private Map<String, Object> session; private Map<String, Object> request;
@Override public void setApplication(Map<String, Object> application) { this.application = application; }
@Override public void setSession(Map<String, Object> session) { this.session = session; }
@Override public void setRequest(Map<String, Object> request) { this.request = request; }
public String execute() { application.put("appKey", "通过Aware注入的全局数据"); session.put("userId", "1001"); request.put("pageNum", 1); return "success"; } }
|
特点:
- 依赖注入:Struts2 在创建 Action 时自动注入 Map 对象,无需手动获取;
- 代码清晰:通过接口明确声明依赖的资源,可读性强;
- 适用场景:适合中型项目,平衡了封装性与易用性。
与 Servlet API 耦合的方式
这种方式直接使用 Servlet 原生 API(如HttpServletRequest
、HttpServletResponse
),可调用所有原生方法,适合需要深度操作 Web 资源的场景(如文件上传、设置响应头)。
1. 使用 ServletActionContext(工具类方式)
ServletActionContext
是 Struts2 提供的工具类,直接暴露 Servlet 原生对象,是访问原生 API 的便捷方式。
核心方法与示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import org.apache.struts2.ServletActionContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.ServletContext;
public class TestServletActionContextAction { public String execute() { HttpServletRequest request = ServletActionContext.getRequest(); request.setAttribute("msg", "原生request数据"); String ip = request.getRemoteAddr();
HttpServletResponse response = ServletActionContext.getResponse(); response.setContentType("text/html;charset=UTF-8"); response.setHeader("Cache-Control", "no-cache");
HttpSession session = request.getSession(); HttpSession session2 = ServletActionContext.getRequest().getSession(); session.setAttribute("user", new User("李四"));
ServletContext application = ServletActionContext.getServletContext(); application.setAttribute("appName", "Struts2应用"); String realPath = application.getRealPath("/");
return "success"; } }
|
特点:
- 直接操作原生对象:支持所有 Servlet API 方法,功能完整;
- 静态方法调用:通过
ServletActionContext
的静态方法直接获取,代码简洁;
- 耦合性高:依赖 Servlet API,单元测试需依赖容器(如 Spring TestContext)。
2. 实现 ServletXxxAware 接口(注入原生对象)
通过实现 Struts2 的ServletXxxAware
接口,可直接注入 Servlet 原生对象,适合需要长期持有原生对象的场景。
常用接口与示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.apache.struts2.util.ServletContextAware; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletContext;
public class TestServletAwareAction implements ServletRequestAware, ServletResponseAware, ServletContextAware { private HttpServletRequest request; private HttpServletResponse response; private ServletContext application;
@Override public void setServletRequest(HttpServletRequest request) { this.request = request; }
@Override public void setServletResponse(HttpServletResponse response) { this.response = response; }
@Override public void setServletContext(ServletContext application) { this.application = application; }
public String execute() { request.setAttribute("data", "通过Aware注入的request数据"); response.setStatus(200); application.log("操作日志:用户访问了资源"); return "success"; } }
|
特点:
- 对象持久化:原生对象通过成员变量持有,可在 Action 的多个方法中复用;
- 功能完整:支持所有原生方法,适合复杂 Web 操作(如文件下载、Cookie 处理);
- 侵入性强:Action 与 Servlet API 强耦合,灵活性较低。
两种方式的对比与选择建议
维度 |
与 Servlet API 解耦方式(ActionContext/Aware 接口) |
与 Servlet API 耦合方式(ServletActionContext/ServletXxxAware) |
依赖关系 |
依赖 Struts2 封装的 Map,不依赖 Servlet 原生类 |
直接依赖 Servlet API(如HttpServletRequest ) |
功能完整性 |
支持基本操作(存 / 取数据),不支持原生方法 |
支持所有 Servlet API 方法,功能完整 |
单元测试难度 |
易(可模拟 Map 对象) |
难(需依赖 Servlet 容器) |
代码侵入性 |
低(通过 Struts2 API 操作) |
高(直接使用 Servlet 类) |
适用场景 |
大多数业务逻辑(数据存储、参数获取) |
复杂 Web 操作(文件上传、响应头设置、Cookie 处理等) |
选择建议:
- 优先使用解耦方式:对于简单的数据存储与获取,推荐使用
ActionContext
或XxxAware
接口,降低框架耦合度,便于测试;
- 必要时使用耦合方式:当需要调用 Servlet 原生方法(如
getHeader()
、setContentType()
)时,使用ServletActionContext
或ServletXxxAware
接口;
- 混合使用注意事项:两种方式可共存,但需注意数据同步(如通过
ActionContext
的sessionMap
存储的数据,可通过原生HttpSession
获取,两者本质是同一数据)。
常见问题与解决方案
- request 对象获取方式差异:
解耦方式中,ActionContext
没有直接提供getRequest()
方法,需通过actionContext.get("request")
获取 Map 对象;耦合方式中可直接通过ServletActionContext.getRequest()
获取原生HttpServletRequest
。
- 参数获取的注意事项:
解耦方式中,actionContext.getParameters()
返回的是Map<String, Object>
,其中多值参数(如复选框)的值是String[]
类型,需强制转换;耦合方式中request.getParameterValues()
更直观。
- 线程安全问题:
两种方式均线程安全,ActionContext
和ServletActionContext
的对象与当前请求绑定,不会出现线程干扰
v1.3.10