Struts中使用Validator框架
每个应用程序都有责任确保它们插入到后台资料库的数据是合法有效的,毕竟,如果这些应用程序所依赖的数据一旦遭到了破坏,那将是灾难性的,那应用程序还能拿什么来使自己正常运转呢?比如说,使用正规关系数据库的一个应用程序,数据库中的每个字段都有自己一定的规则和约束,来保证存储在其中的数据在一定程度上的正确性。任何要使用后台资料库数据的应用程序都有责任保护它们提交的数据的完整性。
任何试图插入或更新不符合标准的数据的操作都有可能被发现并拒绝。这种检测可能遍布在整个应用程序的每个角落,在表现层可能进行一些验证,在业务逻辑层,商业逻辑对象一般也有商业逻辑的验证,还有在后台资料库也要对数据进行检查。
任何试图插入或更新不符合标准的数据的操作都有可能被发现并拒绝。这种检测可能遍布在整个应用程序的每个角落,在表现层可能进行一些验证,在业务逻辑层,商业逻辑对象一般也有商业逻辑的验证,还有在后台资料库也要对数据进行检查。
不幸的是,由于这种验证在应用程序中无处不在,造成了应用程序在一定程度上的验证数据的代码冗余。这并不是应用程序所希望的,因为这种在多处的重复劳动,使得应用程序的部署和维护要花去更多的时间。如果在整个应用程序中,这些验证规则可以重复使用,将使得应用程序更加富有弹性,换句话说就是,部署更快捷,定制更容易,程序更灵活。
Jakarta Commons
项目
Validator
框架简介
Validator
是由
David Winterfeldt
创建的开源项目,它也是
Jakarta Commons
的一个子项目。
Commons
项目主要是提供一些像
Validator
这样的一些可重用组件。其他著名的
Commons
组件还有如
BeanUtils,Digester,Logging
框架等。
Validator 1.0
版本发布于
2002
年
11
月初。
使用
Validator
的好处
.
使用
Validator
框架比一般的在应用程序的代码中定义验证规则有好多优点,如:
. 可以在一处为应用程序定义验证规则;
. 验证规则和应用程序是松耦合的;
. 服务器端和客户端的验证规则可以在同一处定义;
. 配置新验证规则或修改已有验证规则变得更加简单;
. 支持国际化;
. 支持正则表达式;
. 可以用于 Web 应用程序也可用于标准的 Java 应用程序;
. 采用声明的方法实现而不是编程实现;
. 可以在一处为应用程序定义验证规则;
. 验证规则和应用程序是松耦合的;
. 服务器端和客户端的验证规则可以在同一处定义;
. 配置新验证规则或修改已有验证规则变得更加简单;
. 支持国际化;
. 支持正则表达式;
. 可以用于 Web 应用程序也可用于标准的 Java 应用程序;
. 采用声明的方法实现而不是编程实现;
除了之外,
Validator
最大的特征就是自身支持可插性(
pluggability
)。在文章的后面你将会看到使用
Validator
框架内置的验证规则来更好地完成你的工作,而更重要的是,
Validator
框架允许你自定义验证程序,并插入到框架中。
Struts
和
Validator
的关系
应该指出的是
Validator
框架本身是因
Struts
框架而建立的。
Validator
的创建者
David Winterfeldt
在使用
Struts
的过程中发现,在许多
ActionForm
类中需要反复使用同一个验证规则,这样造成了大量的代码冗余。于是他决定创建
Validator
框架来消除这种冗余,这样
Validator
就诞生了。
尽管
Validator
架构最初是为
Struts
架构而生,但它还是被设计和构造成了可以独立于
Struts
架构而单独使用。这一个特征使得你可以在任何的应用程序中使用这个框架,不必管它是不是
Struts
架构的。并不会因为你不使用
Struts
框架而影响
Validator
架构对你的应用程序作用。事实上,这就是为什么
Validator
是
Jakarta Commons
项目的一部分而不直接是
Struts
项目的一部分。
现在,我们来将这个框架整合应用到像基于
Struts
构架这样的
Web
应用程序上。在文章的最后中我们再介绍如何把它应用到其他类型的应用程序中,如基于
EJB
的应用程序。
Validator
组件概述
Validator
架构有下面这些组件组成:
Validators ;
配置文件;
资源绑定;
JSP 自定义标签;
Validator Form 类;
Validators ;
配置文件;
资源绑定;
JSP 自定义标签;
Validator Form 类;
什么是
Validators?
一个
Validator
就是,执行一个验证规则时
Validator
框架调用的一个
Java
类。框架根据配置文件中定义的方法签名来调用这个
Validaotor
类。一般情况下,每个
Validator
类提供一个单独的验证规则,然后这些规则可以组合成更复杂的规则集。
注意:有时出于方便,一个
Validator
类也可以定义多个验证规则,而每个规则是一个静态方法且并不包含任何客户端状态信息。
框架提供了
14
种默认的验证规则,有时候这些规则也被称为
Validator
框架的
“
基本规则
”
,这些基本规则如表一:
名称
描述
byte,short,integer,long,float,double 检验值是否能被转换成对应的基本数据类型
creditCard 检验输入域是否是一个合法的信用卡号码
date 检验输入域是否是一个合法日期
email 检验输入是否是一个合法 Email 地址
mask 检验输入域是否能成功匹配一个正则表达式
maxLength 检验值的长度是否小于等于给定的最大长度
minLength 检验值的长度是否大于等于给定的最小长度
range 检验值的范围是否在最大值和最小值之间
required 检验输入域是否为不为空,或不包含空格值的长度是否大于零
byte,short,integer,long,float,double 检验值是否能被转换成对应的基本数据类型
creditCard 检验输入域是否是一个合法的信用卡号码
date 检验输入域是否是一个合法日期
email 检验输入是否是一个合法 Email 地址
mask 检验输入域是否能成功匹配一个正则表达式
maxLength 检验值的长度是否小于等于给定的最大长度
minLength 检验值的长度是否大于等于给定的最小长度
range 检验值的范围是否在最大值和最小值之间
required 检验输入域是否为不为空,或不包含空格值的长度是否大于零
正像你在表一中看到的, Validator 框架提供了 Web 应用程序需要的大多数的验证规则。你可以使用这些现有的验证规则来创建自己验证配置文件。尽管这样,也正如我们前面提到的,和后面要讲到的,你可以根据你的需要随意的增加更多的 Validator 。
现在,让我们来讨论如何在一个基于
Struts
架构的应用程序中配置使用这些基本的
Validator
。
使
Validator
框架具有弹性的原因在于所有的验证规则和其具体细节都是通过在外部文件中配置声明实现的。你的应用程序并不必要知道这些具体的验证规则。这一特征使得规则集的发生扩展和修改时,你并不用去动你应用程序的源代码。这一点对你要进行每次的个性化安装或当需求发生变化时来说是非常重要的。
如果你使用
Struts1.1
的
Validator
框架,你会用到这样两个配置文件,一个叫
validator- rules.xml
,另一个叫
validation.xml
;其实你也可以随意的给他们命名,甚至可以把它们合并成一个
XML
文件。但是,你还是最好把它们分开,因为它们各有各的用途。
注意:如果你从
Jakarta
网站上下载
Validator
,并不包含这两个文件。只有在包含的
Validator
框架的
Struts
的下载中才可以找到这两个文件。
validator-rules.xml
文件
validator-rules.xml
文件定义应用程序可以使用的
Validator
。
validator-rules.xml
充当模板的作用,定义所有应用程序可能要用到的
Validator
。
注意:这个
xml
文件和我们下面要讨论的另一个
xml
文件都应该放到类加载器可以找得到的地方。当我们在
Web
应用程序中使用
Validator
框架时,正确的位置应该是在
WEB-INF
下。
validator-rules.xml
文件服从
validator- rules_1_1.dtd
的管理,
validator- rules_1_1.dtd
可以在
jakarta.apache.org/struts/dtds/validator- rules_1_1.dtd
下载到。我们并不想花太多的时间放在研究这个文件的具体细节上,我们在这儿只作一些基本的介绍。
validator-rules.xml
文件中最重要的元素包含在元素中,例如,例一:
例一:一个简单的
validator-rules.xml
文件
<form-validation>
<global>
<validator
name="required"
classname="org.apache.struts.util.StrutsValidator"
method="validateRequired"
methodparams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
msg="errors.required"/>
<global>
<validator
name="required"
classname="org.apache.struts.util.StrutsValidator"
method="validateRequired"
methodparams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
msg="errors.required"/>
<validator name="minlength"
classname="org.apache.struts.util.StrutsValidator"
method="validateMinLength"
methodparams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
depends="required"
msg="errors.minlength"/>
</global>
</form-validation>
classname="org.apache.struts.util.StrutsValidator"
method="validateMinLength"
methodparams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
depends="required"
msg="errors.minlength"/>
</global>
</form-validation>
应用程序使用的每个
Validator
对应一个元素。在例一中给大家展示了两个
Validator
,一个是请求
Validator
,另一个是最小长度
Validator
。元素支持许多属性。这些属性是必要的,用于告知框架这个
Validator
应当调用哪个正确的类和方法。例如,例一中的请求
Validator
元素表明这个
Validator
将调用
org.apache.struts.util.StrutsValidator
类的
validateRequest()
方法。
Validator
也可能要依赖另一个
Validator,
如例一中的最小长度的
Validator
就是这样一个例子,它包含一个
depends
属性,用它来表示这个
Validator
将依赖于请求
Validator
。
msg
属性用一个键值指定一个资源绑定,框架将用它来生成正确的错误信息。资源绑定的使用有益于错误信息的本地化。
元素还支持子元素,允许你指定一个客户端运行的
javascript
函数。这样服务器端和客户端验证可以在同一处指定,这使应用程序的维护变得简单。
validation.xml
文件
Validator
框架的第二个配置文件就是这个叫
validation.xml
的文件。其实你可以随意把它命名为你喜欢的任何名字,也可以把它放到
validator-rules.xml
文件中。
validation.xml
用于把你在
validator-rules.xml
中定义的各个
Validator
和你的应用程序中的组件映射起来。由于我们在这里讨论的是在
Struts
中使用
Validator
框架,那么在这里
validation.xml
就是把这些
Validator
和
Struts
的
ActionForm
类建立映射。
ActionForm
类其实是一个类似
JavaBean
一样的类,在
Struts
中用于捕捉用户输入并帮助传输这些输入到下一级应用程序组件。
ActionForm
也提供了在用户输入被传到业务逻辑层之前验证这些输入的便利场所。例二是一个简单的
validation.xml:
例二:一个简单的
validation.xml
文件
<form-validation>
<formset>
<form name="checkoutForm">
<field
property="firstName"
depends="required">
<arg0 key="label.firstName"/>
</field>
<formset>
<form name="checkoutForm">
<field
property="firstName"
depends="required">
<arg0 key="label.firstName"/>
</field>
<field
property="lastName"
depends="required">
<arg0 key="label.lastName"/>
</field>
</form>
</formset>
</form-validation>
property="lastName"
depends="required">
<arg0 key="label.lastName"/>
</field>
</form>
</formset>
</form-validation>
例二向大家展现了一个
name
属性叫
checkoutForm
的一个
form
元素。
checkoutForm
是一个在
Struts
配置文件中定义的一个
ActionForm Bean
。所以,例二的
XML
文件就是把这个
ActionForm Bean
和请求
Validator
建立映射,
Bean
的
firstName
和
lastName
属性分别对应
XML
文件中相应的
firstName
和
lastName field
元素。
其实它还有许多其它作用,如可以在
validation.xml
中定义常量和全局变量,用于在整个文件中使用,当你想使时可以方便的反复使用。对于
validation.xml
的元素和属性更详细的解释,可以下载
jakarta.apache.org/struts/dtds/validation_1_1.dtd
参阅。
资源绑定
对于
Validator
框架,当验证规则失败的时候,可以从资源绑定中创建错误信息。
Validator
框架提供几种默认消息,同一般的应用程序消息资源放在一起。如下:
#
Normal
resource bundle messages
label.firstName=First Name
label.lastName=Last Name
label.firstName=First Name
label.lastName=Last Name
#Error messages used by the Validator
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
...
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
...
当一个验证规则失败时,这个验证规则创建一个错误信息。框架将自动给消息插入参数。比如说,我们使用例一和例二的验证规则,当
checkoutForm
的
firstName
属性为空时,我们会看到这样的错误信息:
First Name is required.
你也可以修改绑定或配置文件来显示你喜欢的消息。
“
挂
”Validator
到
Struts
上
现在我们已经了解了
Validator
框架,感觉蛮不错吧!下面我们将快速的讲一下我们是如何轻松地在
Struts
框架中使用
Validator
框架的。
首先要做的就是让
Struts
框架认识
Validator
框架。你可以使用
Struts1.1
的
Plug-in
新特性来实现它。只要在
Struts
配置文件中增加下面代码即可:
<plug-in classname="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
这样
Struts
就可以自动识别
Validator
框架了。
另外一个必需的步骤就是创建
ActionForm Bean
(标准的或是动态的)和确保
Validator
框架的配置文件是可用的,这样就搞定了。并不需要作一些调用验证规则或做其他具体的事情,
Struts
框架会自动完成这些工作,这就是所谓的基于声明的配置。然后当验证规则失败的时候,你就可以用
JSP
标签看到显示的错误信息了。
创建自己的
Validator
尽管
Validator
框架已为大家提供了
Web
应用程序需要的大多数验证规则,但有时我们还是需要创建一些自己的验证规则。幸运的,
Validator
框架的扩展性相当好,为你提供了这种便利,而这样做对程序造成的影响相当小的。
创建自己的
Validator
并不是一件难事,只要创建一个实现这个规则的
Java
类即可。比如,(在国外)要去超市买二锅头,要验证顾客是否达到合法饮酒年龄。你可以使用已有的验证规进行验证,但我们觉得创建一个验证规则进行验证要更加直截了一些。验证饮酒年龄规则
Validator Java
代码如下
:
例三:自定义验证规则
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorUtil;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.util.StrutsValidatorUtil;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorUtil;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.util.StrutsValidatorUtil;
public class NewValidator implements Serializable{
public static boolean validateDrinkingAge( Object bean,
ValidatorAction va,
Field field,
ActionErrors errors, HttpServletRequest request) {
ValidatorAction va,
Field field,
ActionErrors errors, HttpServletRequest request) {
String value = null;
if (isString(bean)) {
value = (String) bean;
} else {
value =
ValidatorUtil.getvalueAsString(bean, field.getProperty());
}
String sMin = field.getVarvalue("drinkingAge");
if (isString(bean)) {
value = (String) bean;
} else {
value =
ValidatorUtil.getvalueAsString(bean, field.getProperty());
}
String sMin = field.getVarvalue("drinkingAge");
if (!GenericValidator.isBlankOrNull(value)) {
try {
int ivalue = Integer.parseInt(value);
int drinkingAge = Integer.parseInt(sMin);
try {
int ivalue = Integer.parseInt(value);
int drinkingAge = Integer.parseInt(sMin);
if ( ivalue < drinkingAge ){
errors.add(field.getKey(),
StrutsValidatorUtil.getActionError(request, va, field));
return false;
}
} catch (Exception e) {
errors.add(field.getKey(),
StrutsValidatorUtil.getActionError(request, va, field));
return false;
}
}
return true;
}
errors.add(field.getKey(),
StrutsValidatorUtil.getActionError(request, va, field));
return false;
}
} catch (Exception e) {
errors.add(field.getKey(),
StrutsValidatorUtil.getActionError(request, va, field));
return false;
}
}
return true;
}
private static boolean isString(Object o) {
if (o == null) {
return (true);
}
return (String.class.isInstance(o));
}
}
if (o == null) {
return (true);
}
return (String.class.isInstance(o));
}
}
你创建完新的
Validator
之后,你只要把他加到现存的
Validator
框架的
validator-rules.xml
的列表中,你就可以像使用基本验证规则一样使用你自己创建的验证规则。
在非
Struts
应用程序中使用
Validator
框架
正像我们在前面谈到的,
Validator
框架最初是为在
Struts
框架中使用而设计的。可是,
Validator
框架设计的相当灵活,并没有直接把它耦合在
Struts
框架中,这样你就可以在普通的应用程序中也可以使用
Validator
框架来进行验证。但是,你必须执行一些必需的步骤。
你可以利用像在
Web
应用程序中一样使用配置文件。这也是使用
Validatoe
框架的另一个优点。你可以在
Struts
框架使用插件的方式来定位和装载这些文件。而在非
Struts
应用程序中你必须人为地手动的定位和装载这些配置文件。下面就是应用程序在启动时一般要调的方法:
...
ValidatorResources resources = new ValidatorResources();
ValidatorResources resources = new ValidatorResources();
InputStream rules =
ValidateExample.class.getResourceAsStream("validator-rules.xml");
ValidateExample.class.getResourceAsStream("validator-rules.xml");
ValidatorResourcesInitializer.initialize(resources, in);
InputStream forms =
ValidateExample.class.getResourceAsStream("validation.xml");
ValidateExample.class.getResourceAsStream("validation.xml");
ValidatorResourcesInitializer.initialize(resources, forms);
...
这段代码片断创建了一个
ValidatorResources
实例,并根据两个配置文件进行了初始化。然后你就可以在你应用程序使用这个
ValidatorResources
对象验证你配置的
JavaBean
了。
例四向你展示如何使用已初始化的
ValidatorResources
对象来验证一个
Person Bean
。
例四:如何使用
Validator
验证你的
Bean
。
//
假设我们已经创建和装配了一个
CheckoutForm Bean
对象
CheckoutForm form = new CheckoutForm();
// 使用 chekoutForm 创建一个 Validator
Validator validator = new Validator(resources, "checkoutForm");
// 告诉 Validator 要验证哪个 Bean
validator.addResource(Validator.BEAN_KEY, form);
// 验证 checkoutForm 对象并存储验证结果
ValidatorResults results = validator.validate();
CheckoutForm form = new CheckoutForm();
// 使用 chekoutForm 创建一个 Validator
Validator validator = new Validator(resources, "checkoutForm");
// 告诉 Validator 要验证哪个 Bean
validator.addResource(Validator.BEAN_KEY, form);
// 验证 checkoutForm 对象并存储验证结果
ValidatorResults results = validator.validate();
在例四中,我们看到我们把
checkoutForm JavaBean
的名字传给
Validator
类的构造器,这是为了告诉
Validator
实例使用哪套验证规则来验证这个
Bean
。
正如你看到的一样,在非
Struts
应用程序中使用
Validator
框架显得有点不自动化,但是它还是提供了比较灵活的解决方案。使用
Validator
框架的另一个好处就是把验证从源代码中分离到外部的配置文件中。这使我们可以把更多的时间放在我们的业务逻辑开发上。
客户端
VS
服务器端
Validator
最后我们简单的阐述一下
Validator
框架对
javascript
的支持。因为有些应用程序需要执行一些客户端验证,在某些时候使用
javascript
进行一些客户端的验证是很有必要的。这里的客户端我们一般特指
Web
浏览器。
Validator
框架提供使用配置文件中的规则动态和自动生成
javascript
验证规则的支持。对于每个元素,它可以有一个子元素和包含一些
javascript
代码。当包含一些自定义标签的
JSP
页面被解释时,
javascript
也被解释,并当表单提交时执行这些验证规则。这些叫
javascriptValidatorTag
的标签被包含在
Struts
的标签集中。这些标签可以像这样进行使用:
笔者认为在需要时使用一定的
javascript
是可以接受的。当你需要执行一些客户端的验证时,使用
Validator
框架标签是也是一种不错的选择,而且支持根据用户的区域进行本地化。
结束语
到此为止,我给大家简单地介绍了
Validator
框架,这些其实是框架的一些表面的东西。这个框架的内容深不可测,仅正则表达式就可以写一本小册子。
像任何一个框架一样,
Validator
框架为大家提供的是一个基础的架构,你可以根据你的需求对其进行扩展和个性化。使用像
Validator
的框架的最重要的一点就是它们是经过千锤百炼,是技术的精华。你并不需重蹈前人失败的覆辙,你可以节省下时间把更多的精力集中在对业务逻辑的开发上。