Action
简介
Action
在
MVC
模式中担任控制部分的角色
,
在
WebWork
中使用的最多
,
用于接收页面参数,起到对
HttpRequest
判断处理作用。每个请求的动作都对应于一个相应的
Action
,一个
Action
是一个独立的工作单元和控制命令,它必需要实现
XWork
里的
Action
接口,实现
Action
接口的
execute()
方法。
Action
接口的代码如下:
package com.opensymphony.xwork;
import java.io.Serializable;
public interface Action extends Serializable {
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";
public String execute() throws Exception;
}
excute()
方法是
Action
类里最重要的部分,它执行返回
String
类型的值,代表在页面执行完后的结果,在
Action
中返回的值一般使用它上面定义的标准静态字符常量。它有五种状态:
1
.
SUCCESS
:
Action
正确的执行完成,返回相应的视图;
2
.
NONE
:表示
Action
正确的执行完成,但并不返回任何视图;
3
.
ERROR
:表示
Action
执行失败,返回到错误处理视图;
4
.
INPUT
:
Action
的执行,需要从前端界面获取参数,
INPUT
就是代表这个参数输入的界面,一般在应用中,会对这些参数进行验证,如果验证没有通过,将自动返回到该视图;
5
.
LOGIN
:
Action
因为用户没有登陆的原因没有正确执行,将返回该登陆视图,要求用户进行登陆验证。
下面我们将以一个用户注册的例子详细介绍
Action
的原理:
功能描述:一个用户注册页面
register.jsp
,用户可以在这个页面里输入用户注册的基本信息(例如:姓名、密码、
Email
等),输入完成提交表单,执行用户注册的
Action
,执行成功返回成功提示的页面(
register-result.jsp
)并将注册的信息输出。
流程如下:
模型:
User.java
控制:
RegisterAction.java
视图:
register.jsp
、
register-result.jsp
配置:
xwork.xml
User.java
:
package register;
public class User {
private String username;
private String password;
private String email;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
……
public int getAge() {
return age;
}
public int setAge(int age) {
this.age = age;
}
public String toString(){
return "username=" + username
+ ";password=" + password
+ ";email=" + email
+ ";age=" + age;
}
}
模型
User
是一个普通的
JavaBean
,它包含了用户注册的字段信息,并对每个字段提供相应的
set
和
get
方法。下面我们来看看进行用户注册动作的
RegisterAction.java
:
package
example.register;
import
com.opensymphony.xwork.Action;
/**
*@authorbabydavic-qac
* achqian@yahoo.com.cn
*/
public
class
RegisterAction
implements
Action
{
privateUseruser=newUser();
public User getUser(){
returnthis.user;
}
publicStringexecute(){
System.out.println("Start execute
。。。。。。。。。。。。。
"
);
System.out.println("User="+user);
//
在这里调用用户注册的业务逻辑,比如:将注册信息存储到数据库
returnSUCCESS;
}
}
这个
Action
是不是特清爽?用户注册就这么几行代码搞定,当然,我们提倡在
Action
里最好不要实现业务代码,业务代码编写在
service.java
里面,
Action
的主要功能是提供从请求中取得参数的值,转化成相应的模型,再将模型传递给执行业务操作的对象,比如:将注册的用户信息存储到数据库中,由业务对象执行业务操作,再返回执行的结果。为了简化我们省去了注册的业务逻辑执行步骤
再看看我们注册信息输入的页面:
register.jsp
<html>
<head><title>Register Example</title></head>
<body>
<table border=0 width=97%>
<tr><td align="left">
<form name="register" action="register.action" method="post">
Username:<input type="text" name="user.username"><br>
Password:<input type="text" name="user.password"><br>
Email:<input type="text" name="user.email"><br>
Age:<input type="text" name="user.age"><br>
<input type="submit" name="Submit"><br>
</form>
</td></tr>
</table>
</body>
</html>
register.jsp
页面其实只是一个普通的
HTML
页面,它提供了一个表单,用来接受用户输入的注册信息,它唯一特殊的部分就是
input
输入框定义的
name
部分,例如:用户姓名用的是“
user. username
”。这种命名方式代表什么含义?它是必需的吗?后面我们将会给出答案。
RegisterAction
正确执行完成之后,会将执行的结果返回到
register-result.jsp
页面,由它来显示用户在前面页面输入的注册信息。
register-result.jsp
代码如下
:
<%@ taglib prefix="ww" uri="webwork" %>
<html>
<head><title>Register result</title></head>
<body>
<table border=0 width=97%>
<tr>
<td align="left">
Congratulation,your register success!<p>
Username:<ww:property value="user.username"/><br>
Password:<ww:property value="user.password"/><br>
Email:<ww:property value="user.email"/><br>
Age:<ww:property value="user.age"/><br>
</td>
</tr>
</table>
</body>
这个
Jsp
页面使用了
WebWork
的标签库
<ww:property />
,记得
HelloWorld
里的
greetings.jsp
吗?它也使用了这个标签库。我们看这个:
<ww:property value="user.username"/>
它是一个普通的使用标签库语句,查看这个标签库的源程序,见包
com.opensymphony.webwork.views.jsp
里的
PropertyTag.java
文件,你会发现这个类会根据
value
后面赋予的表达式值,去
OgnlValueStack
里查找这个表达式值所对应的操作。执行这个语句
OgnlValueStack
会根据
value
的值(一个表达式)“
user.username
”去分别调用
RegisterAction
类的
getUser()
和
User
类的
getUsername()
方法,即:
getUser().getUsername()
,取得的数据就是前面注册页面输入的用户名。
我们把“
user.username
”这样的语句叫做表达式语言(
Expression Language
,简称为
EL
)。它由
XWork
框架提供,
XWork
表达式语言的核心是
OGNL
(
Object Graph Notation Language
),
OGNL
是一种功能强大,技术成熟,应用广泛的表达式语言,将在下面的章节有详细介绍。
我们在回到前面介绍的
register.jsp
,
Input
输入框
<input type="text" name="user.username">
里用的“
user.username
”,现在我们可以明白,它不是随意设置的,它是一个表达式语言,有着特殊的功能。看到这里,不知道你心中是否有一个疑问:我们的
RegisterAction
是如何取得用户注册页面输入的数据呢?如果你做过
Web
开发,你一定会想到
RegisterAction
里必需有一些从客户端请求中获取参数的语句,例如:
类似:
String username = request.getParameter(“user. username”)
的语句(
request
是
HttpServletRequest
的对象),去从
request
请求里面获取用户输入的参数值。可是我们这个
Action
里面只有
User
对象简单的
get
方法,并没有其它的代码。
Xwork
框架的
Action
是如何去实现了与
Web
无关?
request
请求的参数是怎么传递到我们
Action
的模型
User
中呢?
在回答答案之前,我们先看一看
Xwork
的配置文件
xwork.xml
:
<action
name=
"register"
class=
"example.register.RegisterAction"
>
<resultname="success"type="dispatcher">
<paramname="location">/register-result.jsp</param>
</result>
<interceptor-refname="params"/>
</action>
看了前面的介绍,这段配置文件应该不难理解。用户通过注册页面
register.jsp
输入自己的注册信息,提交表单到动作
register.action
,它将有
ServletDispatcher
调度,从配置文件
xwork.xml
里查找与“
register
”匹配的
Action
名字,即上面配置的
Action
。通过这个名字
XWork
框架找到这个
Action
的类:
example.register.RegisterAction
,
XWork
框架会负责去创建这个
Action
类的对象并调用
execute()
方法进行用户注册操作。正确执行
execute()
方法返回
String
类型数据“
success
”之后,它会请求再派遣到
register-result.jsp
页面。
在这段配置文件里,你一定注意到了它特殊的一句:
<interceptor-ref name="params"/>
,
interceptor-ref
标签设置这个
Action
用到的拦截器
(Interceptor)
,“
params
”引用的是配置文件中的
<interceptor name="params" class="
com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
,这个拦截器将在
RegisterAction
的
execute()
方法执行之前调用,作用是将
request
请求的参数值通过表达式语言设置到相应
RegisterAction
的模型里。例如:
register.jsp
里的
<input type="text" name="user.username">
,它输入的值会由
RegisterAction
类的
getUser()
和
User
类的
setUserName(“…”)
设置到这个
User
模型里。假设你在注册页面输入用户名“
babydavic
”,提交表单
ParametersInterceptor
就会下面的操作:首先从请求中取得参数的名字和名字对应的值,分别为:“
user.username
”和“
babydavic
”,根据这个名字,从
OgnlValueStack
中取得堆栈最上面的
getUser().setUsername(“babydavic”)
操作,即取得
RegisterAction
对象的
User
模型,并设置
username
属性的值为“
babydavic
”。
原来,我们的
Action
是通过
XWork
的拦截器
ParametersInterceptor
从提交的表单中取得请求的参数和值,再通过
OgnlValueStack
来执行表达式,调用
Action
和模型里相应的
ge
或
set
方法,将从请求中取得的值设置到模型中去。
register.jsp
中
Input
输入框的
name="user.username"
是必需要遵守
OGNL
的命名规则。也正是很多拦截器的使用,使得我们的
Action
类和
Web
实现了完全的解耦,让我们的
Action
能如此的简单、优雅,拦截器的原理后面章节我们也将会有详细的介绍。
Action
根据
FormBean
的不同可以分为二类,
一类是
Field-Driven
(字段驱动的)
Action
Action
将直接用自己的字段来充当
FormBean
的功能,我们的例子就是使用这种方式。它一般用在页面表单比较简单的情况使用,而且可以直接用域对象作为
Action
的字段,这样就不用在另写
FormBean
,减少了重复代码。
另一类是
Model-Driven
(模型驱动的)
Action
它很像
Struts
的
FormBean
,但在
WebWork
中,只要普通
Java
对象就可以充当模型部分。
Model-Driven
(模型驱动的)
Action
要求我们的
Action
实现
com.opensymphony.xwork. ModelDriven
接口,它有一个方法:
Object getModel();
,我们用这个方法返回我们的模型对象就可以了。
我们可以将前面的
RegisterAction.java
改为
Model-Driven
(模型驱动的)
Action
:
package
example.register;
import
com.opensymphony.xwork.Action;
import
com.opensymphony.xwork.ModelDriven;
/**
*@authormoxie-qac
* achqian@yahoo.com.cn
*
*/
public
class
RegisterActionModel
implements
Action,ModelDriven{
privateUseruser=newUser();
publicStringexecute()throwsException{
System.out.println("Start execute......
。。。。。。。。。。。。。。
"
);
System.out.println("User="+user);
//
在这里调用用户注册的业务逻辑,比如:将注册信息存储到数据库
returnSUCCESS;
}
public Object getModel() {
return user;
}
}
这时我们输入信息的页面也有了变化:
register-model.jsp
<html>
<head><title>Register Example</title></head>
<body>
<table border=0 width=97%>
<tr><td align="left">
<form name="register" action="registerModel.action" method="post">
Username:<input type="text" name="username"><br>
Password:<input type="text" name="password"><br>
Email:<input type="text" name="email"><br>
Age:<input type="text" name="age"><br>
<input type="submit" name="Submit"><br>
</form>
</td></tr>
</table>
</body>
</html>
我们发现,输入框里的命名发生了变化。它们都少了“
user.
”这部分信息。
当我们采用
Model-Driven
(模型驱动的)
Action
时,它将取得模型对象保存在值堆栈中。“
name="username"
”就是代表直接调用模型对象的
setUsername()
方法。
我们
Action
的在配置文件中,也要给它指定一个拦截器
model-driven
,
它的作用就是将模型对象保存到值堆栈中。关于拦截器的介绍请看下面的章节。
配置文件如下:
<action
name=
"registerModel"
class=
"example.register.RegisterActionModel"
>
<resultname="success"type="dispatcher">
<paramname="location">/register-result-model.jsp</param>
</result>
<interceptor-ref name="model-driven"/>
<interceptor-refname="params"/>
</action>