在说 Struts2 中的 Action 时,我们首先来说一下 Struts1 中的 ActionForm ,大家知道在 Struts1 中, ActionForm 本身是一个抽象类,若想将客户端提交的信息自动变成对象赋予到 Java 类中就必须提供一个自定义类,让它继承 ActionForm ,并提供相应的属性,然后自动 set 和 get 该 Formbean 总是与我们自定义的 JavaBean 有些重复,这就有点冗余的感觉。在 Struts2 中就取消了 ActionForm ,它直接用一个 Action 来实现 ActionForm 的功能,客户端提交的信息,如 name ,它会自动调用 Action 的 setName() 赋值到 name 属性中。
那么我们来说说 Struts2 中的 Action,Action 是 Struts2 的核心组件,是 MVC 模型中的粘贴剂,通过下图可以发现。
那么我们把 Action 与 Servlet 模式对比一下,如下图:
结合上图,我们对 Struts2 运行过程进行说明:
1 、 HttpRequest 被 struts2 的内置核心过滤器 Filterdispather 拦截
2 、 Struts 根据 url 查找并创建 Action 对象,并且将 Request Parameters 设置到 Action Property
3 、 Struts 调用 Action 的 execute 方法将调用业务逻辑并返回适合的结果视图名称
4 、 Struts 将 Action Property 封装为 ValueStack ,然后将 Request 转发到 JSP 页面
5 、 JSP 页面取得 ValueStack 值,并输出 HTML
注意:
invoke 方法和 Servlet 过滤器中调用 FilterChain.doFilter 方法类似,如果在当前拦截器后面还有其他的拦截器,则 invoke 方法就是调用后面拦截器的 intercept 方法,否则, invoke 会调用 Action 类的 execute 方法 ;
execute 方法又类似 Servlet 中的 service 方法
Action 三大作用:
1 、封装对请求的实际处理
Action 类似于 Servlet ,但封装性更高
Struts2 实现了 Action 与请求响应对象间的解耦,分离了 Action 与 Request/Response 的关联
2 、承载用户请求与结果视图的数据
Action 可以自动接收表单数据
在结果视图( JSP )中可以获取 Action 中的数据
3 、选择响应的结果视图
根据业务逻辑的处理结果选择适当的结果视图
Ok ,那来说说 Struts1 和 Struts2 中 Action 的不同:
1 、 Struts1.X 就只有一个 Action ,它是单例的,因此它里面不能放置存储状态性的东西;
2 、 Struts2 在默认情况下,每发送过来一次请求,它都会生成一个 Action 实例,因此 Struts2 的请求之间是独立的互不干扰的,因此它是线程安全的。
所以在 Struts2 中只要类包含返回 string 类型的 execute 的无参方法,那么他就可以作为 Struts2 的 Action 。
模型驱动:
要想实现模型驱动,必须要实现 ModelDriven 接口
ModelDrivenAction 类的执行流程是:
1 、调用 getModel() 方法得到 User 对象
2 、根据 JavaBean 的原则将客户端传过来的属性,一个一个的 set 到 User 对象的属性中
3 、将属性全部 set 完之后,再执行 execute() 方法。
一般不推荐使用模型驱动,而使用属性驱动。
Demo :
ModelDrivenAction.java:
public class ModelDrivenAction implements ModelDriven { public String execute() throws Exception { return SUCCESS; } public Object getModel() { return new Gangster(); } }
Gangster.java
public class Gangster implements Serializable { private String name; private int age; private String description; private boolean bustedBefore; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public boolean isBustedBefore() { return bustedBefore; } public void setBustedBefore(boolean bustedBefore) { this.bustedBefore = bustedBefore; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Jsp:
<s:form action="modelDrivenResult" method="POST" namespace="/modelDriven"> <s:textfield label="Gangster Name" name="name" /> <s:textfield label="Gangster Age" name="age" /> <s:checkbox label="Gangster Busted Before" name="bustedBefore" /> <s:textarea cols="30" rows="5" label="Gangster Description" name="description" /> <s:submit /> </s:form>
Action Chaining
<package name="public" extends="struts-default"> <!-- Chain creatAccount to login, using the default parameter --> <action name="createAccount" class="..."> <result type="chain">login</result> </action> <action name="login" class="..."> <!-- Chain to another namespace --> <result type="chain"> <param name="actionName">dashboard</param> <param name="namespace">/secure</param> </result> </action> </package> <package name="secure" extends="struts-default" namespace="/secure"> <action name="dashboard" class="..."> <result>dashboard.jsp</result> </action> </package>
属性驱动 Demo :
UserAction.java
package org.lxh.action; import java.text.DateFormat; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; /** * @author xudongwang 2011-5-12 * */ public class UserAction { private String message; private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String hello() { message = "欢迎使用Struts2!!,Now is [" + DateFormat.getDateInstance().format(new Date())+"]"; return ActionSupport.SUCCESS; } public void execute() { System.out.println("***********" + userName); } }
说明:
execute 方法是 Action 默认的执行方法,在方法内调用业务逻辑,封装请求和视图结果数据,返回结果视图;
同时上面的 return ActionSupport.SUCCESS; 可以改为 return "success"; 的这里的 success 要与 Struts.xml 中的 result 中的 name 对应,所以是小写的,同时其他的值还有: ERROR ,错误、 INPUT ,输入、 LOGIN ,登陆、 NONE ,空、 SUCCESS ,成功;
注意上面的 return "success"; 中的 success 是可以任意定义的,只要和 Struts.xml 中的 result 中的 name 对应即可
Struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="user" extends="struts-default"> <action name="helloworld" class="org.lxh.action.UserAction" method="hello"> <result name="success" type="plainText">/hello_struts2.jsp</result> </action> </package> </struts>
index.jsp:
<a href="helloworld.action">Hello World</a>
hello_struts2.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>... <s:property value="message"/>
说明:
<s:property value="message"/> 中的 message 是从 valueStack 中拉数据,而在 action 中的属性是 javaBean 属性保存数据,而 return SUCCESS 是控制字符串将去选择结果 resulst
补充:
Action 中的可选接口
1 、 com.opensymphony.xwork2.Action;
此接口定义了 Action 的默认规则;
a 、 Action 类中默认存在 execute 方法
b 、并不要求 Action 类对此接口显示的 implements
c 、可以使用 <action> 标签的 method 属性指定其他的处理方法名
此接口还定义了常用结果视图的名称:
a 、 ERROR ,错误
b 、 INPUT ,输入
c 、 LOGIN ,登陆
d 、 NONE ,空
e 、 SUCCESS ,成功
2 、 com.opensymphony.xwork2.ActionSupport
Action 的辅助工具类
通常由 Action 类 extends 此工具类
为 Action 类提供 Struts2 的常用功能
getText :用于国际化,根据 key 从资源文件中加载文本
validate :在 Action 类中重写此方法以实现数据校验
addActionError :添加一个 Action 错误
addFieldError :添加一个表单项错误
3 、 com.opensymphony.xwork2.ActionContext
Action 上下文工具类
提供访问各个 web 作用域键值 Map 的能力
getContext() :静态方法,获得当前 Action 对应的 ActionContext 对象
getApplication(): 获取 application 作用域的 map
getSession(): 获取 session 作用域的 map
getParameters(): 获取 request 表单的 map
getValueStack(): 取得 OGNL ValueState ,它实际上是打对 request 作用域 map 的封装
4 、 org.apache.struts2.ServletActionContext
ServletContext 辅助工具类
通过一系列静态方法提供对 Servlet 对象的访问
getRequest(): 获取 HttpServletRequest 对象
getResponse(): 获取 HttpServletResponse 对象
getServletContext(): 获取 ServletContext 对象
getRequest().getSession: 获取 HttpSession 对象