struts2访问web资源
Struts2 访问 Web 资源的两种方式详解
在 Struts2 框架中,Web 资源(如HttpServletRequest、HttpSession、ServletContext等)的访问方式分为与 Servlet API 解耦和与 Servlet API 耦合两种。两种方式各有适用场景,下面详细解析其实现方式与使用场景。
与 Servlet API 解耦的方式
这种方式通过 Struts2 封装的 API 访问 Web 资源,不直接依赖 Servlet 原生类,便于进行单元测试,适合大多数业务场景。
1. 使用 ActionContext(核心方式)
ActionContext是 Struts2 的上下文对象,封装了当前请求的所有信息,可通过它间接访问 Web 资源对应的 Map 对象。
核心方法与示例:
import com.opensymphony.xwork2.ActionContext;
import java.util.Map;
public class UserAction {
public String execute() {
// 获取ActionContext实例(单例,与当前请求绑定)
ActionContext actionContext = ActionContext.getContext();
// 1. 获取application域(对应ServletContext)
Map<String, Object> applicationMap = actionContext.getApplication();
applicationMap.put("appKey", "全局应用数据"); // 存储数据
Object appValue = applicationMap.get("appKey"); // 获取数据
// 2. 获取session域
Map<String, Object> sessionMap = actionContext.getSession();
sessionMap.put("userName", "张三"); // 存储用户会话数据
Object user = sessionMap.get("userName");
// 3. 获取request域(需通过"request"键获取,Struts2未直接提供getRequest()方法)
Map<String, Object> requestMap = (Map<String, Object>) actionContext.get("request");
requestMap.put("msg", "请求数据");
Object msg = requestMap.get("msg");
// 4. 获取请求参数(封装为Map,键是参数名,值是参数值数组)
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,更符合面向接口编程思想。
常用接口与示例:
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import java.util.Map;
// 实现接口,通过setter方法注入对应Map
public class TestAwareAction implements ApplicationAware, SessionAware, RequestAware {
// 注入的application域Map
private Map<String, Object> application;
// 注入的session域Map
private Map<String, Object> session;
// 注入的request域Map
private Map<String, Object> request;
// 实现ApplicationAware接口的方法
public void setApplication(Map<String, Object> application) {
this.application = application;
}
// 实现SessionAware接口的方法
public void setSession(Map<String, Object> session) {
this.session = session;
}
// 实现RequestAware接口的方法
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public String execute() {
// 使用注入的Map操作Web资源
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 的便捷方式。
核心方法与示例:
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() {
// 1. 获取HttpServletRequest对象
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("msg", "原生request数据");
String ip = request.getRemoteAddr(); // 调用原生方法(获取客户端IP)
// 2. 获取HttpServletResponse对象
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/html;charset=UTF-8"); // 设置响应编码
response.setHeader("Cache-Control", "no-cache"); // 设置响应头
// 3. 获取HttpSession对象(两种方式)
HttpSession session = request.getSession(); // 方式1:通过request获取
HttpSession session2 = ServletActionContext.getRequest().getSession(); // 方式2:直接获取
session.setAttribute("user", new User("李四"));
// 4. 获取ServletContext对象
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 原生对象,适合需要长期持有原生对象的场景。
常用接口与示例:
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;
// 实现ServletRequestAware接口
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
// 实现ServletResponseAware接口
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
// 实现ServletContextAware接口
public void setServletContext(ServletContext application) {
this.application = application;
}
public String execute() {
// 使用原生对象操作
request.setAttribute("data", "通过Aware注入的request数据");
response.setStatus(200); // 设置响应状态码
application.log("操作日志:用户访问了资源"); // 调用ServletContext的日志方法
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的对象与当前请求绑定,不会出现线程干扰