10.3 配置方式下实现用户输入验证

         前面所介绍的基于编码方式对用户输入数据进行验证,这种方式下当需要验证的字段较多,Action类的代码会变得臃肿。细细看来代码重复度较大。10.2种用户注册的验证规则写的也不完全,如果完整的进行编写这样的验证代码变成了体力活。Struts2框架中内置了验证框架。我们不必进行编码,可以利用配置的方式实现用户输入验证,从而减少编码量提高开发效率。
         默认情况下,Struts2的验证框架是开启的。该验证框架是由拦截器validation来调用的。defaultStack拦截器栈中已经包含该拦截器。因此,使用Struts2的验证框架无需额外配置。只需要提供正确的输入验证配置文件就可以进行验证。       
         本节仍然沿用10.2.1的用户登陆功能案例,如果在编写用户登陆功能时,添加用户输入验证。该验证内容包含:用户名不能为空;密码不能为空;密码长度必须在612位之间。如果用户输入验证错误,则在原页面上显示错误信息,如果用户输入验证正确,则跳转到登陆成功页面,并显示“xxx,您好”的信息,其中xxx为用户输入的用户名。此处用户输入验证使用配置文件实现。
         实现该功能程序结构图,本节中的代码实现与图10-1相比仅修改LoginAction类中的代码实现,并在类所在的包下增加LoginAction-validation.xml文件,该配置文件用于验证用户输入。
如下图所示:
Struts2用户输入验证(3)_完全
图10-5 配置方式下用户登陆代码结构
         修改后的LoginAction类,去掉了用户输入验证代码。具体代码如下图所示:
packagecom.study.erp.action;
importcom.opensymphony.xwork2.ActionSupport;
public class LoginActionextends ActionSupport{
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String execute(){
            return "success";
    }
}
         配置文件LoginAction-validation.xml文件用于用户输入验证,该文件的内容如下所示:
<!DOCTYPE validatorsPUBLIC
        "-//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">
            <message>用户名不能为空.</message>
        </field-validator>
    </field>
    <field name="password">
        <field-validator type="requiredstring">
            <message>密码不能为空.</message>
        </field-validator>
         <field-validator type="stringlength">
         <paramname="minLength">6</param>
            <param name="maxLength">12</param>
             <message>密码长度应在612位之间.</message>
        </field-validator>
    </field>
</validators>
    该配置文件的文件模板为,建议使用版本为xwork-validator-1.0.3.dtd的配置文件,其中:<validators>标记作为该文件的根标记。
<!DOCTYPE validatorsPUBLIC
        "-//Apache Struts//XWork Validator1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
……
</validators>
         上面的案例中使用了字段校验配置方式(具体的语法要求参考10.3.1中的说明),该方式的标记为<field>,本例中基于2个字段分别是:username,password进行了验证。验证中使用了requiredstringstringlength两种验证规则(参考10.3.2关于内置验证规则的说明)。<message>标记中的内容是当验证出现错误时,给用户的错误提示信息。

10.3.1 输入验证配置文件

编写输入验证配置文件的要求主要包括两个方面:
1.  位置:验证配置文件和Action类放在相同的包中
2.  命名:验证配置文件名可以为以下两种:
1)        ClassName-validation.xml文件
2)        ClassName-alias-validation.xml文件
其中ClassNameAction类名,alias表示在struts.xml文件中配置Action的名字。
ClassName-validation.xml配置文件对Action中的所有方法进行校验,而ClassName-alias-validation.xml文件只对Action中特定的方法进行校验。用于多方法的Action的输入校验。
程序员编写上述说明的输入验证配置文件时,所有的标记的约束结构由:http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd文件指定,具体嵌套合使用的标准如下图所示:
        
        
validators
field
validator
field-validator
param
message
param
message
 
         Validators标记内可以嵌套field标记用于字段校验器配置和validator标记用于普通校验器配置,field标记中可以嵌套field-validator标记,field-validator标记中可以嵌套param标记和message标记。validator标记中可以嵌套param标记和message标记
Struts2提供了2种验证器分别是:普通验证器也叫非字段验证器和字段验证器。大多数情况下普通验证器可以与字段验证器完成相同的功能。即可以互相替换使用。但是我们多将普通验证用于执行那些不针对特定字段的验证规则。例如:判断密码和确认密码是否一致。这两种验证器具体配置格式如下所示:
1.      普通验证器配置格式:
<validator type="校验器名">
          <paramname="fieldName">需要被校验的字段</param>
          <!--此处需要为不同校验器指定数量不等的校验规则-->        
<param name="参数名">参数值</param>
          <!--校验失败后的提示信息,其中key指定国际化信息的key-->
          <messagekey="I18Nkey">校验失败后的提示信息</message>
          <!--校验失败后的提示信息:建议用getText("I18Nkey"),否则可能出现Freemarker template Error-->
</validator>
         2.字段校验器配置格式:
<field name="被校验的字段">
       <field-validator type="校验器名">
             <!--此处需要为不同校验器指定数量不等的校验规则-->
              <paramname="参数名">参数值</param>
                 ....................
               <!--校验失败后的提示信息,其中key指定国际化信息的key-->
                <messagekey="I18Nkey">校验失败后的提示信息</message>
                <!--校验失败后的提示信息:建议用getText("I18Nkey"),否则可能出现Freemarker template Error-->
      </field-vallidator>
        <!-- 如果校验字段满足多个规则,下面可以配置多个校验器-->
</field>
         对于这两种验证器如果均出现在配置文件中,他们执行顺序规则为:
1. 所有非字段校验风格的校验器优先于字段校验风格的校验器;
2. 所有非字段校验风格的校验器中,排在前面的会先执行;
3. 所有字段校验风格的校验器,排在前面的会先执行;
在项目中经常出现某些校验规则,前一种校验如果发现错误后面的某些甚至其余校验则不需要执行,这时候我们需要用到短路校验。短路校验器:只需在<validator><filed-validator>元素中添加short-circuit=”true”属性。
校验器的短路原则:
1. 所有非字段检验器时最优先执行的,如果某个非字段校验器校验失败了,则该字段上的所有字段校验器都不会获得校验机会;
2. 非字段校验校验失败,不会阻止其他非字段校验执行;
3. 如果一个字段校验器校验失败后,则该字段下且排在该校验失败后的检验器之后的其他字段校验器不会获得校验机会;
4. 字段校验器永远不会阻止非字段校验器的执行。
Struts2框架已经支持客户端的校验:将输入页面的表单元素改为使用struts2标签来生成表单,并且为该表单增加validate="true"属性即可。
 

10.3.2 内置校验器

         Struts2提供了16个内置校验器,这些校验器能满足用户的绝大部份需求。接下来我们来看一下这些内置校验器。
校验器名称
作用
required
必填校验器
requiredstring
必填字符串校验器
int
整型范围校验器
long
长整型范围校验器
short
短整型范围校验器
double
双精度浮点型范围校验器
date
日期型校验器
expression
表达式校验器
fieldexpression
字段表达式校验器
email
电子邮件校验器
url
网址校验器
visitor
Visitor校验器
conversion
转换校验器
stringlength
字符串长度校验器
regex
正则表达式校验器
conditionalvisitor
条件Visitor校验器
10- Struts2提供的内置校验器
下面就这些内置的校验器逐个进行说明:
l  必填验证器(required)
1.             作用:required验证器用来验证一个参数是否不为nullrequired验证器既可以用于字段验证器,又可以用于动作验证器。
2.             参数及其含义
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
3.             具体用法
<validators>
        <!- -普通校验器语法 -->
        <validator type="required">
            <param name="fieldName">username</param>
            <message>username must not be null</message>
        </validator>
        <!- -字段校验器语法 -->
        <field name="username">
            <field-validator type="required">
                 <message>usernamemust not be null</message>
            </field-validator>
        </field>
 </validators>
l  必填字符串验证器(requiredstring)
1.        作用:requiredstring验证器用来验证一个字符串参数是否非空,既不为null,且长度大于0。既可以用于字段验证器,又可以用于动作验证器。
2.        参数及其含义
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø  trim:去掉字段的前后空格,该属性默认值为true
3.        具体用法
<validators>
    <!- -普通校验器语法 -->
   <validator type="requiredstring">
       <param name="fieldName">username</param>
       <param name="trim">true</param>
       <message>username is required</message>
   </validator>
    <!- -字段校验器语法 -->
    <fieldname="username">
       <field-validatortype="requiredstring">
           <param name="trim">true</param>
           <message>username is required</message>
      </field-validator>
   </field>
</validators>
l  整数验证器(int)
1.        作用:用于验证字段的值必须在整数的某一范围内。
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø  min用来指定可接受范围的最小值
Ø  max用来指定可接收范围的最大值
3.        具体用法:
<validators>
           <!- -普通校验器语法 -->
          <validator type="int">
             <param name="fieldName">age</param>
             <param name="min">20</param>
             <param name="max">50</param>
             <message>Age needs to be between${min} and ${max}</message>
          </validator>
         <!- -字段校验器语法 -->
          <field name="age">
             <field-validator type="int">
                 <param name="min">20</param>
                 <param name="max">50</param>
                <!- -${min}${max}是引用param对应的参数值 -->
                 <message>Age needs to be between${min} and ${max}</message>
             </field-validator>
          </field>
     </validators>
注意1conversion验证器验证的是参数能不能被正确转化为整数,int验证器是在参数已经被正确的转化为整数之后,再考察它的范围。例如:如果想限制年龄文本框填入整数类型的数字,并且在18岁以上,需要先引用conversion验证器检查用户填入的是否是一个整数,然后再引用int验证器来检查用户填入的年龄是否大于等于18
注意2:如果用户未输入数据,在提交后却会看到该表单域的值为0。因此在实际编程中,建议Action的属性类型写为Integer
l  long 长整型,short短整型范围校验器
short验证器和long验证器与int验证器非常相似,都是用来验证参数是否在指定范围之内,就不去赘述了。
l  double      双精度浮点型范围校验器
1.        作用:用于验证一个双精度浮点型参数是否在指定的范围内。如果一个已经被成功转换为double的属性不在验证器指定的范围内,double验证器就会报错。double验证器既可以用于字段验证器,又可以用于动作验证器。
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø  minInclusive用来指定可接受范围的最小值,包含给定值。
Ø  maxInclusive用来指定可接收范围的最大值,包含给定值。
Ø  minExclusive用来指定可接受范围的最小值,不包含给定值。
Ø  maxExclusive用来指定可接收范围的最大值,不包含给定值
3.        具体用法:
<validators>
          <!- -普通校验器语法 -->
          <validator type="double">
             <param name="fieldName">percentage</param>
             <param name="minInclusive">20.1</param>
             <param name="maxInclusive">50.1</param>
             <message>Age needs to be between${minInclusive} and
axInclusive} (inclusive)</message>
          </validator>
          <!- -字段校验器语法 -->
          <field name="percentage">
             <field-validator type="double">
                 <param name="minExclusive">0.123</param>
                 <param name="maxExclusive">99.98</param>
                 <message>Percentageneeds to be between ${minExclusive}
 ${maxExclusive} (exclusive)</message>
             </field-validator>
          </field>
     </validators>
l  date 日期型校验器
1.        作用:date验证器用来验证一个日期型参数是否在指定的范围内。如果一个已经被成功转换为date的属性不在验证器指定的范围内,date验证器就会报错。
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø  min用来指定可接受范围的最小值
Ø  max用来指定可接收范围的最大值。
3.        具体用法:
<validators>
    <!-—普通校验器语法 -->
    <validatortype="date">
      <paramname="fieldName">birthday</param>
         <param name="min">01/01/1990</param>
         <param name="max">01/01/2000</param>
         <message>Birthday must be within ${min} and ${max}</message>
        </validator>
      <!-—字段校验器语法-->
     <field name="birthday">
         <field-validator type="date">
             <paramname="min">01/01/1990</param>
              <paramname="max">01/01/2000</param>
             <message>Birthday must be within ${min} and ${max}</message>
         </field>
     </field>
</validators>
注意:指定日期范围的时候,需要使用统一的格式,比如用MM/DD/YYYY的格式等。
l  expression        表达式校验器
1.        作用:表达式验证器,是一个非字段校验器。
2.        参数及其含义:
Ø  expressionOGNL表达式,该表达式结果必须是一个Boolean类型值。
3.        具体用法:
<!-—普通校验器语法 -->
<validators>
      <validator type="expression">
         <param name="expression"> .... </param>
         <message>Failed to meet Ognl Expression  .... </message>
      </validator>
</validators>
l  fieldexpression         字段表达式校验器
1.        作用:指定字段表达式验证器,是一个非字段校验器。表达式验证器(expression)与字段表达式验证器(fieldexpression)类似
2.        参数及其含义:
Ø  expressionOGNL表达式,该表达式结果必须是一个Boolean类型值。
3.        具体用法:
<validators>
<!-—普通校验器语法 -->
    <validator type="fieldexpression">
       <param name="fieldName">myField</param>
       <param name="expression"><![CDATA[#myCreditLimit >#myGirfriendCreditLimit]]></param>
       <message>My credit limit should be MORE than mygirlfriend</message>
    <validator>
    <!-—字段校验器语法 -->
    <field name="myField">
        <field-validator type="fieldexpression">
            <param name="expression"><![CDATA[#myCreditLimit >#myGirfriendCreditLimit]]></param>
            <message>My credit limit should be MORE than mygirlfriend</message>
        </field-validator>
    </field>
</validators>
注意:<![CDATA[…]]>用于某表达式包含xml的限定字符,直接使用可能会导致错误。
l  email        电子邮件校验器
1.        作用:用来验证一个参数是否为邮箱地址。
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
3.        具体用法:
<validators>
<!-—普通校验器语法 -->
    <validator type="email">
        <param name="fieldName">myEmail</param>
        <message>Must provide a valid email</message>
    </validator>
<!-—字段校验器语法 -->
<fieldname="myEmail">
   <field-validatortype="email">
      <message>Mustprovide a valid email</message>
   </field-validator>
</field>
</validators>
l  url    网址校验器
1.        作用:用来验证一个参数是否为合法的URL
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
3.        具体用法:
<validators>
         <!-—普通校验器语法 -->
        <validator type="url">
            <param name="fieldName">myHomePage</param>
            <message>Invalid homepage url</message>
        </validator>
    <!-—字段校验器语法 -->
        <field name="myHomepage">
            <message>Invalid homepage url</message>
        </field>
   </validators>
l  Visitor校验器
1.        作用:用来验证Action中的复合属性,可以直接把验证信息放到域对象中去注册,这样就使得同包内的不同Action在验证同一个域对象时,不用注册重复的验证信息。
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø  context:引用的域对象验证信息文件上下文名。
Ø  appendPrefix:是否在错误信息中添加<message>元素指定的前缀。
3.        具体用法:
<validators>
       <!-—普通校验器语法 -->
      <validator type="visitor">
          <param name="fieldName">user</param>
          <param name="context">myContext</param>
          <param name="appendPrefix">true</param>
      </validator>
<!-—字段校验器语法 -->
      <field name="user">
         <field-validator type="visitor">
            <param name="context">myContext</param>
            <param name="appendPrefix">true</param>
         </field-validator>
      </field>
 </validators>
l  conversion        转换校验器
1.        作用:conversion验证器用来验证类型转换时是否出错。例如一个类型为int的参数接到了“18a”这个字符串,conversion验证器就会报错。
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
3.        具体用法:
<validators>
   <!-—普通校验器语法 -->
<validator type="conversion">
         <paramname="fieldName">myField</param>
        <message>Conversion Error Occurred</message>
</validator>
   <!-—字段校验器语法 -->
   <field name="myField">
      <field-validator type="conversion">
          <message>ConversionError Occurred</message>
      </field-validator>
   </field>
</validators>
l  stringlength     字符串长度校验器
1.        作用:用来验证一个字符串的长度是否在指定范围内。
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø  maxLength:字符串长度的最大值。
Ø  minLength:字符串长度的最小值。
Ø  trim:是否去掉字符串两边的空白,默认为true
3.        具体用法:
<validators>
          <!-—普通校验器语法 -->
          <validator type="stringlength">
              <param name="fieldName">myPurchaseCode</param>
              <param name="minLength">10</param>
              <param name="maxLength">10</param>
               <param name="trim">true</param>
              <message>Your purchase code needs tobe 10 characters long</message>
           </validator>
           <!-—字段校验器语法 -->
           <field name="myPurchaseCode">
              <field-validator type="stringlength">
                   <param name="minLength">10</param>
                   <param name="maxLength">10</param>
                   <param name="trim">true</param>
                   <message>Your purchase code needs tobe 10 characters long</message>
              </field-validator>
           </field>
     </validators>
l  regex        正则表达式校验器
1.        作用:用来验证一个字符串是否符合一个正则表达式的要求。
2.        参数及其含义:
Ø fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø expression:必填参数,正则表达式。
Ø caseSensitive:是否检查大小写。
Ø trim:是否去掉字符串两边的空白,默认为true
3.        具体用法:
<validators>
    <!-—普通校验器语法 -->
    <validator type="regex">
        <param name="fieldName">myStrangePostcode</param>
        <param name="expression">
<![CDATA[([aAbBcCdD][123][eEfFgG][456])]]>
</param>
    </validator>
    <!-—字段校验器语法 -->
    <field name="myStrangePostcode">
        <field-validator type="regex">
           <param name="expression">
<![CDATA[([aAbBcCdD][123][eEfFgG][456])]]>
</param>
        </field-validator>
    </field>
</validators>
l  conditionalvisitor     条件Visitor校验器
1.        作用:要求指定字段满足Visitor校验器的要求
2.        参数及其含义:
Ø  fieldname : 字段名,如果使用字段校验器则不需要该属性
Ø  expressionOGNL表达式,该表达式结果必须是一个Boolean类型值。

10.3.3 自定义校验器

         虽然Struts2验证框架提供了丰富的验证器,但是有时候仍然不能满足项目的需求。Struts2框架允许开发人员自定义验证器。
         开发自定义校验器需要完成如下两步操作:
1.                 开发自定义校验类,需要实现validate接口,如果要编写字段校验器,该类可以通过继承自FieldValidatorSupport类,并重写validate方法来实现。如果要编写普通校验器可以通过继承自ValidatorSupport类,并重写validate方法来实现。具体的验证规则的代码写在该方法中实现。
2.                 注册自定义校验器,即编写配置文件名为validators.xml,该文件位于源文件的根目录下(即工具的src目录下)。该配置文件的模板如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator Config 1.0//EN"
"http://struts.apache.org/dtds/xwork-validator-config-1.0.dtd">
<validators>
<validator name="自定义校验器名称" class="自定义校验类"/>
……
</validators>
每增加一个自定义校验器,则在配置文件中增加一个< validator >标记,该标记包含两个属性。name属性的属性值由用户自己命名,该值作为自定义校验器的名称,class属性值为自定义校验类完整的包名和类名。
用户登录功中,对于密码的检查除非空字符串的验证外,还包括了长度必须在612位之间的验证。下面我们把长度验证自定义一个字段校验器验证规则来实现,该功能的代码结构图如下图所示:
Struts2用户输入验证(3)_用户_02
图 用户登录使用自定义验证规则程序结构图
         编写该功能时用户需要编写和创建的文件:
文件名
说明
备注
Login.jsp
用户登陆页面
视图
LoginSuccess.jsp
用户登陆成功页面
视图
LoginAction
Action
控制器
ValidationPasswordValidator
自定义校验器类
校验器类
struts.xml
Struts2框架的配置文件
配置文件
validators.xml
注册自定义校验器类的配置文件
配置文件
LoginAction-validation.xml
基于配置方式的用户输入验证
配置文件
web.xml
项目的部署描述文件
配置文件
         上述功能完成时,重点涉及到ValidationPasswordValidator类的代码编写,validators.xml文件的配置,LoginAction-validation.xml文件的配置。下面逐个介绍和说明各个文件的具体内容:
1.自定义校验器类ValidationPasswordValidator的代码如下所示:
package com.study.erp.validator;
import com.opensymphony.xwork2.validator.ValidationException;
importcom.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public class ValidationPasswordValidator extends FieldValidatorSupport{
    @Override
    public void validate(Objectobject) throws ValidationException {
        String fieldName = getFieldName();
        String value =getFieldValue(fieldName, object).toString();
        if(value.trim().length()<6|| value.trim().length()>12){
            addFieldError(fieldName,object);
        }
    }
}
上述代码,必须重写父类的validate方法,具体的验证规则代码作为该方法的方法体。其中String fieldName = getFieldName();用于获取被验证的字段的名字,String value=getFieldValue(fieldName, object).toString();用来获取该字段用户输入的内容。如果出现错误则调用addFieldError(fieldName, object);方法设置对应的字段级的错误信息。
2.   注册自定义校验器类的配置文件validators.xml的内容如下:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//ApacheStruts//XWork Validator Config 1.0//EN"
       "http://struts.apache.org/dtds/xwork-validator-config-1.0.dtd">
<validators>
   <validator name="password" class="com.study.erp.validator.ValidationPasswordValidator"/>
</validators>
   上述代码中class的值为ValidationPasswordValidator类的完整的包名和类名,name属性的值可以由程序员自己定义,但是注意不要和已有的验证规则重名。虽然用户自定义了验证规则,但是框架提供的验证规则仍然有效,这两部分内容是叠加的。
3.   在验证配置文件中使用自定义的验证规则,使用方式与使用Struts2框架提供的验证规则是一样的。基于配置方式的用户输入验证LoginAction-validation.xml文件的内容如下所示:
<!DOCTYPE validators PUBLIC
        "-//ApacheStruts//XWork Validator 1.0.3//EN"
       "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
    <fieldname="username">
        <field-validatortype="requiredstring">
            <message>用户名不能为空.</message>
        </field-validator>
    </field>
    <fieldname="password">
        <field-validatortype="requiredstring" short-circuit="true">
            <message>密码不能为空.</message>
        </field-validator>
         <field-validatortype="password">
             <message>密码长度应在6到12位之间.</message>
        </field-validator>
    </field>
</validators>