Map.Entry entry = (Map.Entry) iterator.next();
stack.setValue(
⑷
entry.getKey().toString(), entry.getValue());
} }
} finally {
invocationContext.put(
InstantiatingNullHandler.CREATE_NULL_OBJECTS, Boolean.FALSE);
invocationContext.put(
XWorkMethodAccessor.DENY_METHOD_EXECUTION, Boolean.FALSE);
invocationContext.put(
XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.FALSE);
} } } }
ParametersInterceptor 扩 展 了 抽 象 类 AroundInterceptor 。 并 在 其 预 处 理 方 法
(before)中实现了数据的转换。
数据转换的过程并不复杂:
⑴ 首先由 ActionContext 获得 Map 型的参数集 parameters。
⑵ 由 ActionContext 获得值栈(OgnlValueStack)。
⑶ 遍历 parameters 中的各项数据。
⑷ 通过 OgnlValueStack,根据数据的键值,为 Model 对象填充属性数据。
OgnlValueStack 是 http://www.ognl.org6提供的一套可读写对象属性的类库(功能上有点类似 Jakarta Commons BeanUtils,以及 Spring BeanWrapper)。
OgnlValueStack 使用非常简单,下面这段示例代码将 User 对象的 name 属性设为“erica”。 OgnlValueStack stack = new OgnlValueStack();
stack.push(new User());//首先将欲赋值对象压入栈中
stack.setValue("name","erica");//为栈顶对象的指定属性名赋值
上面的代码中并没有发现将Model对象入栈的部分,是由于ActionInvocation在初始化的时候 已经预先完成了这个工作,如DefaultActionInvocation.init方法中代码所示:
6
OGNL=Object-Graph Navigation Language。提供基于表达式的对象属性访问功能。在许多项目中得到使用,
如 Webwork、Apache Tapestry 等。Spring Framework 1.2 版本中也将引入。
private void init() throws Exception {
Map contextMap = createContextMap();createAction();
if (pushAction) {
stack.push(action);}
……
}
输入校验
Web 应用开发中,我们常常面临如何保证输入数据合法性的头痛问题。实现输入数据 校验的方法无外乎两种:
1. 页面 Java Script 校验
2. 服务器端、执行逻辑代码之前进行数据校验
Struts、Spring MVC 均为服务器端的数据校验提供了良好支持。
对于客户端的校验,大多 MVC 框架力所不逮。
而 WebWork 则在提供灵活的服务器端数据校验机制的基础上,进一步提供了对页面 Java Script 数据校验的支持。这也可算是 WebWork 中的一个亮点。
与 Spring MVC 类似,XWork 也提供了一个 Validator 接口,所有数据校验类都必须实 现这个接口。
XWork 发 行 时 已 经 内 置 了 几 个 常 用 的 数 据 校 验 类 ( 位 于 包 com.opensymphony.xwork.validator.validators),同时也提供了 Validator 接口的几个抽象实现
(抽象类),以便于用户在此基础上进行扩展(如 FieldValidatorSupport)。
服务器端数据合法性校验的动作,发生在 Action 被调用之前。回忆之前关于 Xwork 拦 截器体系的讨论,我们自然想到,通过 Interceptor 在 Action 运作之前对其输入参数进行校 验是一个不错的思路。事实的确如此。WebWork 中提供了一个 ValidationInterceptor,它将 调用指定的 Validator 对输入的参数进行合法性校验。
对 这 一 细 节 感 兴 趣 的 读 者 可 参 考 Xwork 中 的 ActionValidatorManager 和 ValidationInterceptor 的实现代码。
下面我们将首先讨论 Validator 的使用,之后再完成一个针对特定需求的 Validator 实现。
为“用户登录”示例加入数据合法性校验:
1. 首先,为 Action 配置用于数据校验的 Interceptor:
<xwork>
<include file="webwork-default.xml" />
<package name="default" extends="webwork-default">
<action name="login"
class="net.xiaxin.webwork.action.LoginAction">
<result name="success" type="dispatcher">
<param name="location">/main.jsp</param>
</result>
<result name="loginfail" type="dispatcher">
<param name="location">/index.jsp</param>
</result>
<interceptor-ref name="params" />
<interceptor-ref name="model-driven" />
<interceptor-ref name="validationWorkflowStack" />
</action>
</package>
</xwork>
这 里 我 们 并 没 有 直 接 引 用 ValidationIncepteror 。 而 是 引 用 了 validationWorkflowStack,webwork-default.xml 中对其定义如下:
<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
这表明 validationWorkflowStack 实际上是三个 Interceptor 的顺序组合。
为什么要引用这样一个 Interceptor 组合,而不是直接引用 validation Inceptor?
这与我们的实际需求相关,在 Web 应用中,当输入数据非法时,一般的处理方式 是返回到输入界面,并提示数据非法。而这个 Interceptor 组合则通过三个 Interceptor 的协同实现了这一逻辑。由此也可见 Webwork 中拦截器体系设计的精妙所在。
2. 在 Class Path 的根目录(如 WEB-INF/classes)创建一个 validators.xml 文件,此 文件中包含当前应用中所有需要使用的 Validator。
Webwork 发行包中提供了一个 validators.xml 示例(\bin\validators.xml)可供参 考,一般而言,我们只需根据实际需要在此文件上进行修改即可。
对于我们的登录示例而言,需要校验的有两个字段,用户名和密码,校验逻辑 分别为:
1. 用户名不可为空
2. 密码不可为空,且长度必须为 4 到 6 位之间
这 里 , 我 们 通 过 Xwork 提 供 的 RequiredStringValidator 和 StringLengthFieldValidator 来实现这一校验逻辑。
<validators>
<validator name="required"
class="com.opensymphony.xwork.validator.validators.Requ iredStringValidator" />
<validator name="length"
class="com.opensymphony.xwork.validator.validators.Stri ngLengthFieldValidator" />
</validators>
配置非常简单,只需指定此 Validator 的实现类和及其名称。下面的数据校验 配置文件中,将通过此 Validator 名称,对实际的 Validator 实现类进行引用。
3. 针对页面表单字段配置对应的 Validator。
在我们的登录页面中,共有两个字段 model.username 和 model.password。为其 建立一个配置文件:LoginAction-validation.xml:
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.d td">
<validators>
<field name="model.username">
<field-validator type="required">
<message>Please enter Username!</message>
</field-validator>
</field>
<field name="model.password">
<field-validator type="length">
<param name="minLength">4</param>
<param name="maxLength">6</param>
<message>
Password length must between ${minLength} and
${maxLength} chars!
</message>
</field-validator>
</field>
</validators>
配置文件有两种命名约定方式:
1. Action 类名-validation.xml
如上面的 LoginAction-validation.xml 2. Action 类名-Action 别名-validation.xml
如 LoginAction-login-validation.xml
其中 Action 别名就是 xwork.xml 中我们申明 Action 时为其设定的名称。
配置文件必须放置在与对应 Action 实现类相同的目录。
配置文件格式非常简单,结合 validators.xml,我们可以很直观的看出字段的
4. 修改 LoginAction,使继承 ActionSupport 类。
public class LoginAction extends ActionSupport implements
Action, ModelDriven{
……
}
ActionSupport 类实现了数据校验错误信息、Action 运行错误信息的保存传递功 能。通过扩展 ActionSupport,LoginAction 即可携带执行过程中的状态信息,这 为之后的错误处理,以及面向用户的信息反馈提供了基础数据。
5. 修改页面,增加数据合法性校验错误提示:
<%@ page pageEncoding="gb2312"
contentType="text/html;charset=gb2312"%>
<%@ taglib prefix="ww" uri="webwork"%>
<html>
<style type="text/css">
.errorMessage {
color: red;
}
</style>
<body>
<form action="/login.action">
<ww:if test="hasFieldErrors()">
<span class="errorMessage">
<b>Errors:</b><br>
<ww:iterator value="fieldErrors">
<li><ww:property value="value[0]"/></li>