Struts 2.x权威指南
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

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。