最近在读一本市面上刚有得卖的新书:李刚著的《Struts 2权威指南》,感觉写得非常好,于是就参考该书作了一个关于在Struts中Action访问Servlet API案例。如下:
Struts2的Action并未直接与任何Servlet API耦合,这是Struts2的一个改良之处,因为Action类不再与Servlet API耦合,从而能更轻松的测试该Action。
但对于Web应用的控制器而言,不访问Servlet API几乎是不可能的,例如跟踪HTTP Session状态等。Struts2框架提供了一种更轻松的方式来访问Servlet API。Web应用中通常需要访问的Servlet API就是HttpServletRequest,HttpSession和ServletContext,这三个类分别代表JSP内置对象中的request,session和appliaction。
Struts2提供了一个ActionContext类,Struts2的Action可以通过该类来访问Servlet API。下面是ActionContext类中包含的几个常用方法:
Object get(Object key):该方法类似于调用HttpServletRequest的getAttribute(String name)方法。
Map getApplication():返回一个Map对象,该对象模拟了该应用的ServletContext实例。
static ActionContext getContext():静态方法,获取系统的ActionContext实例。
Map getParameters():获取所有的请求参数。类似于调用HttpServletRequest对象的getParameterMap方法。
Map getSession():返回一个Map对象,该Map对象模拟了HttpSession实例。
void setApplication(Map application):直接传入一个Map实例,将该Map实例里的key-value对转换成application的属性名、属性值。
void setSession(Map session):直接传入一个Map实例,将该Map实例里的key-value对转换成session的属性名、属性值。
下面的应用将在Action类中通过ActionContext访问Servlet API。以登陆页面为示例。
当单击登陆页面中的“登陆”按钮时,系统将提交到login.action,该Action对应的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,设置该conter属性为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());
//如果用户名为scott,密码为tiger
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
...{
//直接设置HttpServletRequest属性,下面代码的作用类似于设置HttpServletRequest属性
//request.setAttribute("tip" , "服务器提示:您已经成功的登陆");
ctx.put("tip" , "服务器提示:您已经成功的登陆");
return SUCCESS;
}
else
...{
//直接设置HttpServletRequest属性
ctx.put("tip" , "服务器提示:登陆失败");
return ERROR;
}
}
}
上面的Action访问了HttpServletRequest的属性,也访问了HttpSession属性,还访问了ServletContext属性。将该Action配置在struts.xml文件中,struts.xml文件的代码如下:
<!-- 指定Struts2配置文件的DTD信息 -->
<! DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd" >
<!-- 配置文件的根元素 -->
< struts >
< package name ="lee" extends ="struts-default" >
<!-- 定义名为login的Action,其实现类为lee.LoginAction -->
< action name ="login" class ="lee.LoginAction" >
< result name ="error" > /error.jsp </ result >
< result name ="success" > /welcome.jsp </ result >
</ action >
</ package >
</ struts >
如果浏览者在登陆页面中的“用户名”输入框中输入scott,“密码”输入框中输入tiger,将提交给LoginAction处理,该Action的execute方法分别设置了HttpServletRequest属性、HttpSession属性和ServletContext属性。为了验证是否成功设置了这三个属性,下面在welcome.jsp页面中访问这三个对象里的属性。下面是welcome.jsp页面的代码。
< html >
< head >
< title > 成功页面 </ title >
</ head >
< body >
<!-- 通过表达式访问ServletContext对象的属性 -->
本站访问次数为:$ ... {applicationScope.counter} < br >
<!-- 通过表达式访问HttpSession对象的属性 -->
$ ... {sessionScope.user} ,您已经登录! < br >
<!-- 通过表达式访问HttpServletRequest对象的属性 -->
$ ... {requestScope.tip}
</ body >
</ html >
显然,相比Struts1中直接访问Servlet API,Struts2通过ActionContext访问Servlet API更加优雅:让Action彻底从Servlet API中分离出来,从而可以允许该Action脱离Web容器运行。最大的好处就是:可以脱离Web容器测试Action。