3.5.2 Action访问ServletAPI
Struts 2的Action并未直接与Servlet API耦合,这是Struts 2的一个改良之处,因为Action类不再与Servlet API耦合,从而能更轻松地测试Action。
但对于 Web 应用的控制器而言,不访问 Servlet API 几乎是不可能的,例如跟踪 HTTP Session状态等。Struts 2框架提供了一种更轻松的方式来访问Servlet API。Web应用中通常需要访问的Servlet API就是HttpServletRequest、HttpSession和ServletContext,这3个类分别代表JSP内置对象中的request、session和appliaction。
Struts 2提供了一个ActionContext类,Struts 2的Action可以通过该类来访问Servlet API。下面是ActionContext类中包含的几个常用方法。
Object get(Object key):获取当前 ActionContext 里 key 对应的 value。该方法可获取HttpServletRequest属性。
put(String key, Object value):将key-value对存入当前ActionContext中。该方法可用于向HttpServletRequest存入属性。
Map getApplication():返回一个Map对象,此对象模拟了该应用的ServletContext实例。
void setApplication(Map application):直接传入一个 Map 实例,将该 Map 实例里的key-value对转换成application的属性名、属性值。
static ActionContext getContext():静态方法,获取系统的ActionContext实例。
Map getParameters():获取所有的请求参数。类似于调用 HttpServletRequest 对象的getParameterMap方法。
Map getSession():返回一个Map对象,该Map对象模拟了HttpSession实例。
void setSession(Map session):直接传入一个Map实例,将该Map实例里的key-value对转换成session的属性名、属性值。
下面的应用将在Action类中通过ActionContext访问Servlet API,以如图3.14所示的登录页面为例。
图3.14 简单的登录页面
当单击图3.14所示页面中的“登录”按钮时,系统将提交到login,该Action对应的Action处理类如下。
程序清单:codes\03\3.5\ActionContext\WEB-INF\src\org\crazyit\struts\action\LoginAction.java
// 处理用户请求的Action类 public class LoginAction implements Action { // 封装用户请求参数的username和password属性 private String username; private String password; // username属性对应的setter和getter方法 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } // password属性对应的setter和getter方法 public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // 下面是处理用户请求的execute方法 public String execute() throws Exception { // 获取ActionContext实例,通过该实例访问Servlet API ActionContext ctx = ActionContext.getContext(); // 获取ServletContext里的counter属性 Integer counter = (Integer)ctx .getApplication().get("counter"); // 如果counter属性为null,则设置该counter属性为1 if (counter == null) { counter = 1; } // 否则,将counter加1 else { counter = counter + 1; } // 将增加1后的counter值设置成counter属性 ctx.getApplication().put("counter" , counter); // 将登录用的username属性设置成一个HttpSession属性 ctx.getSession().put("user" , getUsername()); // 如果用户名为crazyit,密码为leegang if (getUsername().equals("crazyit") && getPassword().equals("leegang") ) { // 直接设置HttpServletRequest属性, // request.setAttribute("tip" , "服务器提示:您已经成功登录"); // 下面代码的作用类似于设置HttpServletRequest属性 ctx.put("tip" , "服务器提示:您已经成功登录"); return SUCCESS; } else { // 通过ActionContext设置HttpServletRequest属性 ctx.put("tip" , "服务器提示:登录失败"); return ERROR; } } }
上面的 Action 访问了 HttpServletRequest 属性,也访问了 HttpSession 属性,还访问了ServletContext属性。将该Action配置在struts.xml文件中,struts.xml文件的代码如下。
程序清单:codes\03\3.5\ActionContext\WEB-INF\src\struts.xml
<?xml version="1.0" encoding="GBK" ?> <!-- 指定Struts 2配置文件的DTD信息 --> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- Struts 2的Action必须放在指定的包空间下定义 --> <package name="struts2qs" extends="struts-default"> <!-- 定义login的Action,该Action的实现类为 org.crazyit.struts2.action.LoginAction类 --> <action name="login" class="org.crazyit.struts2.action.LoginAction"> <!-- 定义处理结果和视图资源之间的映射关系 --> <result name="error">/WEB-INF/content/error.jsp</result> <result name="success">/WEB-INF/content/welcome.jsp</result> </action> <action name="*"> <result>/WEB-INF/content/{1}.jsp</result> </action> </package> </struts>
如果浏览者在图3.14所示页面的“用户名”输入框中输入crazyit,在“密码”输入框中输入leegang,单击“提交”按钮,将提交给org.crazyit.sturts2.action.LoginAction处理,该Action的execute方法分别设置了HttpServletRequest属性、HttpSession属性和ServletContext属性。为了验证是否成功设置了这3个属性,下面在welcome.jsp页面中访问这3个对象里的属性。welcome.jsp页面的代码如下。
程序清单:codes\03\3.5\ActionContext\WEB-INF\content\welcome.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GBK" /> <title>成功页面</title> </head> <body> 本站访问次数为:${applicationScope.counter}<br> ${sessionScope.user},您已经登录!<br> ${requestScope.tip} </body> </html>
Action的execute方法返回success字符串,系统将进入welcome.jsp页面,将看到如图3.15所示的页面。
图3.15 输出application、session和request属性
Struts 2通过ActionContext访问Servlet API十分优雅——可以让Action彻底从Servlet API中分离出来,从而可以允许该Action脱离Web容器运行。最大的好处就是,可以脱离Web容器测试Action。