验证器概述
一个健壮的Web应用程序必须确保用户输入是合法的。比如在注册用户的时候,将用处注册信息保存到数据库之前一般我们会判断用户输入的密码长度是否过短,或者用户的email地址格式是否正确。Strut2提供了一些内建的输入验证程序,通过使用他们,不需要变成即可实现对用户输入的校验,我们只需要在xml配置文件中做出声明就可以了,声明的内容包括,那么字段需要进行验证,在验证失败时应该把什么样的出错信息发送到浏览器等。
验证程序可以分为两大类别:字段验证器(Field validators)和非字段验证器(Non-field validator)。
字段验证程序与表单中的某个字段想关联,其验证行为发生在把一个值赋给一个动作属性之前。非字段验证程序(普通验证器)不与某个特定的字段相关联,他们用来测试某种特定的条件是否得到了满足。Struts2内建的验证器基本上都是字段验证器。Validation拦截器负责加载和执行已经注册的验证器,由于Validation拦截器是defaultStack拦截器栈中的一员,因此我们可以不用声明就可以直接使用内建的验证器(具体实现原理可以查看Validation拦截器源代码)。
使用验证器的步骤:
(1)确定那些Action需要使用输入验证(验证器)
(2)编译xml配置文件。命名格式如下:
ActionClass-validation.xml
ActionClass-ActionMethod-validation.xml
第一中格式比较常见。但是有时候我们的Action类中可能包含多个动作方法,而有时我们至于要对其中的一部分动作(方法)进行输入验证。比如我的User动作类包含add和edit两个动作方法,如果他们使用同样的输入校验规则,那么直接一个User-validation.xml就足够了,但是如果这两个动作方式使用的不是同一种验证策略,那么就需要我们为他们单独配置验证规则,User-add-validation.xml和User-edit-validation.xml。
(3)确定验证失败时应该把用户定向到什么地方,这需要我们在定义一个名为input的Result,可以是专门为动作定义或者是全局Result。否则在输入校验失败时将会抛出异常,提示找不到”input”结果。
注:字段验证器和非字段验证器在产生的错误消息级别上也有所差异。字段验证器产生的验证错误信息就会作为Actin的field level错误信息,而非字段验证器的错误信息将会作为Action level的错误信息。并且对于用一字段,非字段验证器的优先级比字符按验证器的优先级高(与在配置文件中声明的顺序无关),如果一个非字段验证器声明为short-circuited(短路)的,那么它验证失败后不会再去执行该字段的字段验证器。
验证器的配置
验证程序配置工作的核心任务就是编写验证器配置文件。验证器配置使用的xml文件,首先我们需要引用与验证器配置相关的dtd文件,这个文件可以在xwork-core-2.3.1.2.jar下找到(xwork-validator-1.0.3.dtd)其中包含了我们的xml的DOCTYPE语句的格式:
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
验证器配置文件的根元素是validators,<validators>元素可以有任意数量的<field>元素和<validator>元素。每一个<field>元素表示一个将被一个或多个字段验证器进行校验的表单字段。每个<validator>元素表示一个非字段验证器。下面我们动手做一个实例,使用验证器验证用户输入的用户名是否为空和验证用户输入的密码的长度。
UserAction.java
UserAction-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="userName">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>UserNamecannot be empty</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>passwordcannot be empty</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">6</param>
<param name="maxLength">10</param>
<message>the length ofpassword must between 6 and 10</message>
</field-validator>
</field>
</validators>
input.jsp
<body>
<s:if test="hasFieldErrors()">
<s:iterator value="fieldErrors">
<font color="#FF0000"><s:property value="value[0]"/></font><br>
</s:iterator>
</s:if>
<form action="user.action" method="post">
username : <input type="text" name="userName"/><br/>
password : <input type="password" name="password"/>
<input type="submit" value="submit"/>
</form>
</body>
测试:
内建的验证器
在上面的实例中,我们不需要编写任何代码就可以实现对表单字段的验证,都是使用了Struts2内建实现的验证器。当然,这些内建的验证器肯定都是有相应的实现类的。下面是Struts2内建验证器的声明:
<validators>
<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
<validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
<validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
<validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>
<validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>
<validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
<validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
<validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
<validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
<validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
<validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
<validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
<validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
<validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
<validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
<validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>
</validators>
我们可以看到,我们刚才使用的required验证器对应的实现类是com.opensymphony.xwork2.validator.validators.RequiredFieldValidator,我们查看该类的源代码;
public class RequiredFieldValidator extends FieldValidatorSupport {
public void validate(Object object) throwsValidationException {
String fieldName = getFieldName();
Object value = this.getFieldValue(fieldName, object);
if (value == null) {
addFieldError(fieldName, object);
}
}
}
其中只有一个validate方法,这个方式是每个验证器都有的方法,在这里我们可以清楚的看到这个验证器的实现。
其实只要实现了Validator接口的类都可以作为验证器,下面这张图显示了Struts2中验证器的继承层次:
关于内建验证器的使用,在上面的例子中已经学习了。如果是字段验证器,那么我们就需要在<field>元素中使用<field-validator>元素来声明一个字段验证器,每个验证器都必须具有一个<message>元素,里面的内容将会在验证失败时被呈现到表单输入界面。如果要给验证器传递参数,那么可以使用<param>子元素,需要注意的就是<param>元素的name属性需要和验证器实现类中定义的成员属性相对应,具体的可以在使用的时候查看手册。
对于非字段验证器,比如expression。配置的方式大致相同。我们在动手做一个实例吧,判断用户输入的两个数之间的大小关系。
NumberAction.java
NumberAction-validation.xml
<validators>
<validator type="expression">
<param name="expression">max > min</param>
<message>max must begreater than min</message>
</validator>
</validators>
input.jsp
<s:actionerror/>
<form action="number.action" method="post">
max: <input type="text" name="max"/><br/>
min: <input type="text" name="min"/>
<input type="submit" value="submit"/>
</form>
测试:
需要注意的就是,非字段验证器在验证失败时会产生一条Action级别错误消息,而不再是字段级别的错误消息。
其他的内建验证器的使用方法大致相同,就不一一演示了。visitor验证器稍微复杂点,但也差不了多少。用到的时候再去查手册就可以了。
注:一般情况下优先使用字段验证器。