Action 访问 Servlet API 的四种方式示例说明

Struts 2 的 Action 和 Servlet API 没有任何耦合,这是 Struts 2被称为「低侵入式」的一个改进,有利于测试。但在实际的 web 项目中,不可能不用到 web 对象,不可能不访问 Servlet API,如最常用的 request(HttpServletRequest), session(HttpSession), application(ServletContext) 等。如何操作这些对象,可以有如下四种方式:

1. 模拟——通过 ActionContext

参附件 Demo1

public class Demo1Action extends ActionSupport {
   
     private Map request;
     private Map session;
     private Map application;
     @Override
     public String execute() throws Exception {
          ActionContext context = ActionContext.getContext();
          request = (Map) context.get("request");
          session = context.getSession();
          application = context.getApplication();
        
          request.put("r1", "demo1, r1_value");
          session.put("s1", "demo1, s1_value");
          application.put("a1", "demo1, a1_value");
        
          return SUCCESS;
     }
}

2. 模拟——通过 XxxAware 接口

参附件 Demo2

在 org.apache.struts2.interceptor 包下有如下 Aware 接口

这里使用 RequestAware, SessionAware, ApplicationAware 这三个接口操作 request, session, application 对象。

public class Demo2Action extends ActionSupport implements RequestAware,
          SessionAware, ApplicationAware {
     private Map<String, Object> request;
     private Map<String, Object> session;
     private Map<String, Object> application;
     @Override
     public String execute() throws Exception {
          request.put("r1", "demo2, r1_value");
          session.put("s1", "demo2, s1_value");
          application.put("a1", "demo2, a1_value");
          return SUCCESS;
     }
     public void setApplication(Map<String, Object> application) {
          this.application = application;
     }
     public void setSession(Map<String, Object> session) {
          this.session = session;
     }
     public void setRequest(Map<String, Object> request) {
          this.request = request;
     }
}

注:这种方式可能是项目实践中用的比较多的那类。其中 request 一般无需这样操作,因为 Action 的成员变量会自动存放到 ValueStack 中,而 ValueStack 会存放到 request 对象中。

3. 访问真实的 Servlet 对象——通过 ServletActionContext 类

参附件 Demo3

public class Demo3Action extends ActionSupport {
     @Override
     public String execute() throws Exception {
          HttpServletRequest request = ServletActionContext.getRequest();
          HttpSession session = ServletActionContext.getRequest().getSession();
          ServletContext application = ServletActionContext.getServletContext();
          request.setAttribute("r1", "demo3, r1_value");
          session.setAttribute("s1", "demo3, s1_value");
          application.setAttribute("a1", "demo3, a1_value");
          return super.execute();
     }
}

4. 访问真实的 Servlet 对象——通过 ServletRequestAware 接口

参附件 Demo4

通过 ServletRequestAware 接口也可以直接访问 Servlet API

public class Demo4Action extends ActionSupport implements ServletRequestAware {
     HttpServletRequest request;
     @Override
     public String execute() throws Exception {
          ServletContext application = ServletActionContext.getServletContext();
          request.setAttribute("r1", "demo4, r1_value");
          request.getSession().setAttribute("s1", "demo4, s1_value");
          request.getServletContext().setAttribute("a1", "demo4, a1_value");
          return super.execute();
     }
     public void setServletRequest(HttpServletRequest request) {
          this.request = request;
     }
}

注意,还可以用 ServletContextAware 这个接口,这里不再示例。

示例代码说明

以上代码在对应的页面代码片段是一样的:

request:

<s:property value="#request.r1"/>
or
<%=request.getAttribute("r1") %>

session:

<s:property value="#session.s1"/>
or
<%=session.getAttribute("s1") %>

application:

<s:property value="#application.a1"/>
or
<%=application.getAttribute("a1") %>

完整的示例代码,参附件。

总结和问题

总结。以上 Demo2 和 Demo4 体现了 DI 的思想:三个对象依赖于 Struts 2 框架初始化和注入;也体现了 IoC 的思想:对三个对象的控制,传统方式是程序员自己,现在控制权交给 Struts 2 框架了。

问题。为什么要提供这么多中方式访问 Servlet API?