Validator验证框架

 

Validator验证框架

一、Validator框架的优势

       Validator框架是一个Struts插件,最初由David Winterfeldt设计并实现。Validator框架从Struts 0.5时代就可以使用,但那时Validator框架只是被捐助的一个jar包。Apache组织为了使开发人员更方便地使用Validator框架,决定从Struts1.1开始,将Validator框架作为Struts的一部分同Struts一起发布。

Validator框架可以在XML文件中配置验证规则和验证对象。因此,使用Validator框架可以无需在ActionForm的子类中覆盖validate方法就可以很方便地验证客户端的提交数据。由于Validator框架内置了很多预定义的验证机制,如验证某个属性是否存在,验证EMail是否合法等。所以在一般情况下,只需要配置XML文件就可以满足我们的验证需求。

在使用Validator框架时,就会发现这种方式要比直接使用validate方法进行验证会给我们带来如下的好处:

1.  更容易维护。 由于验证信息可以被放置在同一个配置文件中,因此,我们可以更容易地来维护这些验证信息。

2.  标准化。由于很多简单的验证都是相同的。如用户名和密码都要求由字母、数字以及下划下组成。如果将这些验证都写在validate方法中,对这些验证进行标准化非常困难。而在Validator框架中的这些验证机制都是预先定义的,因此,标准化相同的验证对于Validator框架来说将是一件非常轻松的事。

3.  避免重造轮子。虽然一些验证很简单,但如果想正确实现它们也是非常困难的。一个典型的例子是验证EMail地址的格式。如果这个验证要想完美无缺,就必须按着RFC-2822规范的要求来验证EMail地址。而如果我们使用Validator框架,就无需再重造轮子来验证EMail地址了。

4.  减少重复代码的数量。由于Validator框 架提供了很多预定义的验证,因此,我们可以避免自己写很多重复的代码进行验证。当然,我们也可以将大量使用的验证封装在类的方法中,这些虽然可以避免大量的重复劳动,但这就意味着我们团队的新成员要使用这些被封装的验证方法之前必须先学习它们。而最糟糕的情况是很多开发人员可能会忘记使用这些由其他成员实 现的验证库,而自己重新编写具有同样功能的验证库。当然,这一切如果使用Validator框架就都可以得到解决。

    5.  客户端和服务端验证自动切换。我们只需要简单地在JSP页面中放一个单独的<html::javascript/>元素就可以将服务端的验证转换为客户端验证(基于JavaScript的验证)
   
虽然Validator框架的预定义验证已经可以满足大多数的验证需求了,但在某些特殊情况下,这些预定义验证就无法满足我们的需求了,为此,Validator框架也为开发人员提供了扩展验证机制的功能。这也使得Validator框架可以完成更复杂的验证工作。

二、配置和使用Validator框架

 1.  安装Validator框架

    由于ValidatorStruts的一个插件,因此,就需要在struts-config.xml文件中按着Struts插件的方式来安装Validator框架。打开struts-config.xml文件,在<struts-config>元素中加入一个<plug-in>子元素,如下面的代码所示:

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
    <set-property property="pathnames" value="/WEB-INF/validator-rules.xml, /WEB-INF/validator.xml" />
</plug-in>     

其中<set-property>元素设置了插件中使用的pathnames属性的值。在pathnames属性值中包含了两个xml文件。

1validator-rules.xml:在这个文件中声明了Validator框架的预定义验证。这个文件可以在Struts的发行包的lib目录中可以找到这个文件。在使用MyEclipseWeb工程添加Struts功能后,会自动将这个文件加到WEB-INF目录中。

2validator.xml:这个文件定义了要验证的对象。实际上,在这个文件中,包含了一个或多个ActionForm的子类及其要验证的属性和验证规则。因此,这个文件就相当于validate方法。在Validator框架中,可以有多个定义验证对象的xml文件(可以将不同的ActionForm的子类分散到不同的xml文件中),中间用逗号(,)隔开,如下面的代码所示:

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
    <set-property property="pathnames" value="/WEB-INF/validator-rules.xml, /WEB-INF/validator1.xml,
                                             /WEB-INF/validator2.xml, /WEB-INF/validator3.xml"
 />
</plug-in>     

2.  使用Validator框架的一个例子

   
在本节将举一个例子来演示如何使用Validator框架来验证数据。我们需要按着如下的六步来完成这个例子:

【第1步】建立FirstValidatorForm类(ValidatorForm的子类)

<samples工程目录>\src\actionform目录中建立一个FirstValidatorForm.java文件,代码如下:

  package actionform;
  
import org.apache.struts.validator.ValidatorForm;
  
public class FirstValidatorForm extends ValidatorForm  // 必须从ValidatorForm继承
  {
      
private String name;
      
private String age;
      
private String email;
      
public String getName()
      {
          
return name;
      }
      
public void setName(String name)
      {
          
this.name = name;
      }
      
public String getEmail()
      {
          
return email;
      }
      
public void setEmail(String email)
      {
          
this.email = email;
      }
      
public String getAge()
      {
          
return age;
      }
      
public void setAge(String age)
      {
          
this.age = age;
      }
  }

    要注意的是,要想使用Validator框架验证数据,Form类就必须从ValidatorForm继承,而不能从ActionForm继承。这是因为ValidatorForm类是从ActionForm继承的,在ValidatorForm类中已经覆盖了validate方法来自动进行验证工作,因此,我们在ValidatorForm的子类中就不用写validate方法了。

【第2步】建立ValidatorAction类(Action的子类)
   
<samples工程目录>\src\action目录中建立一个ValidatorAction.java文件,代码如下:

  package action;
  
import javax.servlet.http.*;
  
import org.apache.struts.action.*;
  
public class ValidatorAction extends Action
  {
      
public ActionForward execute(ActionMapping mapping, ActionForm form,
              HttpServletRequest request, HttpServletResponse response)
      {
          response.setCharacterEncoding("GBK");
          
try
          {
              response.getWriter().println("
验证成功!");
          }
          
catch (Exception e)
          {
          }
          
return null;
      }
  }

        ValidatorAction类是一个空的Struts动作类(除了输出一行“验证成功!”字符串)。这个动作是为了正常运行含有Struts元素的JSP程序所编写的。在以后的代码中会经常使用到这个Struts动作类。

【第3步】配置struts-config.xml文件

    配置FirstValidatorFormValidatorAction的代码如下所示

<form-bean name="firstValidatorForm" type=" actionform.FirstValidatorForm" />
<action name="firstValidatorForm" path="/firstValidator" scope="request" type=" action.ValidatorAction"  input="/firstValidator.jsp"/>       

其中firstValidator.jsp是用户录入信息的界面,也是显示错误信息的界面。

【第4步】建立firstValidator.jsp
   
Web根目录建立一个firstValidator.jsp文件,代码如下:

  <%@ page pageEncoding="GBK"%>
  
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
  
<html>
    
<head>
      
<title>第一个Validator程序</title>
    
</head>
    
<body>
      
<html:form action="firstValidator" >
         
  名:
<html:text property="name" />&nbsp;&nbsp;<font color="red"><html:errors property="name"/></font><p>
         
  龄:
<html:text property="age"/>&nbsp;&nbsp;<font color="red"><html:errors property="age"/></font><p>
       EMail

<html:text property="email"/>&nbsp;&nbsp;<font color="red"><html:errors property="email"/></font><p>
              
<html:submit value="提交"/>
      
</html:form>  
    
</body>
  
</html>

    firstValidator.jsp中可以看出,不管是否使用Validator框架进和验证,对于JSP代码来说是完全一样的。仍然是使用<html:errors>元素来显示错误信息。但要注意,在使用Validator框架时,<html:errors>标签的property属性的值就是所对应ValidatorForm的子类的属性名。

【第5步】配置validator.xml文件
   
在本例中只使用了一个XML文件(validator.xml)来配置要验证的对象。validator.xml的代码如下:

  <?xml version="1.0" encoding="GBK" ?>
  
<!DOCTYPE form-validation PUBLIC
   "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
            "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"
>
  
<form-validation>
      
<formset>
          
<form name="firstValidatorForm">
              
<field property="name" depends="required,maxlength,minlength,mask">
                  
<msg name="required" key="error.name.blank" />
                  
<msg name="minlength" key="error.name.minLength" />
                  
<msg name="maxlength" key="error.name.maxLength" />
                  
<msg name="mask" key="error.name.alphanum" />
  
                  
<arg name="minlength" key="${var:minlength}" position="0" resource="false" />
                  
<arg name="maxlength" key="${var:maxlength}" position="0" resource="false" />
                  
<var>
                      
<var-name>minlength</var-name>
                      
<var-value>5</var-value>
                  
</var>
                  
<var>
                      
<var-name>maxlength</var-name>
                      
<var-value>10</var-value>
                  
</var>
                  
<var>
                      
<var-name>mask</var-name>
                      
<var-value>^[a-zA-Z0-9]*$</var-value>
                  
</var>
              
</field>
              
<field property="age" depends="required,integer,intRange">
                  
<msg name="required" key="error.age.blank" />
                  
<msg name="integer" key="error.age.integer" />
                  
<msg name="intRange" key="error.age.intRange" />
  
                  
<arg name="intRange" key="${var:min}" position="0" resource="false" />
                  
<arg name="intRange" key="${var:max}" position="1" resource="false" />
                  
<var>
                      
<var-name>min</var-name>
                      
<var-value>18</var-value>
                  
</var>
                  
<var>
                      
<var-name>max</var-name>
                      
<var-value>60</var-value>
                  
</var>  
              
</field>
              
<field property="email" depends="required,email">
                  
<msg name="required" key="error.email.blank" />
                  
<msg name="email" key="error.email.invalid" />
              
</field>
          
</form>
      
</formset>
  
</form-validation>

        validator.xml文件中的所有配置都放到<form-validation>元素中。在<form-validation>元素中有一个<formset>子元素,这个元素可以定义多个<Form>元素,这个元素用来定义要验证的ValidatorForm类的子类。其中name属性值就是<form-bean>元素中的name属性值。

<field>元素用来定义某个属性的约束条件,如第一个<field>元素定义了name属性必须存在(required)、必须要满足最小长度(minlength)和最大长度(maxlength)以及还要通过mask所指的正则表达式的验证。

<msg>元素用来定义出错信息在属性文件中的Key(所有的出错信息都在属性文件中)。<arg>元素用来向出错信息中的参数传递参数值。<var>元素用来定义变量名和变量值。

详解:

 

<!--
     验证规则配置文件的DTD,版本 1.1.3
     允许你开始处的DOCTYPE元素之后(当然DOCTYPE元素要在"xml"声明之后),
     使用XML来配置你的验证文件:
     <!DOCTYPE form-validation PUBLIC
      "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
      " http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
     $Id: validator_1_1_3.dtd,v 1.1.2.2 2004/04/06 22:20:36 rleland Exp $
-->
 
<!--
      "form-validation" 元素是配置文件结构的根元素,
      并且包含了所有其他内嵌配元素及其配置。
-->
<!ELEMENT form-validation (global*, formset*)>

<!--
     在"global"元素中定义的元素都是全局的。可以在文件
     其他地方被引用
-->
<!ELEMENT global (validator*, constant*)>

<!--
      "validator"元素用来定义验证器,这些验证器可以被在formset元素中
      field元素所引用。
      元素:
        validator          定义一个新的验证器
        javascript         在客户端验证使用的javascript源代码
      属性:
          name             验证(器)的名称
          classname        处理服务器端验证的类的类名
          method           服务器端处理验证的方法名
          methodParams     要传递到服务器端验证方法的参数,多个参数用逗号分开
          msg              验证失败时在消息资源中绑定的消息资源key。
                          如果不希望使用默认的key,可以重写它的值以指向所需的消息资源。
          depends          在调用证之前所需要调用的其他验证的列表,多个用逗号分隔。
                          如果想要进行当前验证,那么列表中的所有验证必须成功。
          jsFunctionName   返回某一类型所有字段的JavaScript函数的函数名。
          jsFunction       被传递到对表单进行表单验证的JavaScript函数的函数名。
-->
<!ELEMENT validator (javascript?)>
<!ATTLIST validator name CDATA #REQUIRED>
<!ATTLIST validator classname CDATA #REQUIRED>
<!ATTLIST validator method CDATA #REQUIRED>
<!ATTLIST validator methodParams CDATA #REQUIRED>
<!ATTLIST validator msg CDATA #REQUIRED>
<!ATTLIST validator depends CDATA #IMPLIED>
<!ATTLIST validator jsFunctionName CDATA #IMPLIED>
<!ATTLIST validator jsFunction CDATA #IMPLIED>

<!--
      "javascript"元素定义了客户端执行验证的JavaScript函数.
-->
<!ELEMENT javascript (#PCDATA)>

<!--
      "constant"元素定义了可以在"field"元素中替代参数的静态常量值。
      "constant-name"和"constant-value"元素定义了常量引用id和替代值。
-->
<!ELEMENT constant (constant-name, constant-value)>
<!ELEMENT constant-name   (#PCDATA)>
<!ELEMENT constant-value (#PCDATA)>

<!--
       "formset"定义了一个本地表单集合。如果对于指定的地区(国际化用),那么就只能重写
       相应字段的验证。因为本地化是随地区而定的,所以如果需要本地化,就要改动language或
       country属性或者两者都改。
-->
<!ELEMENT formset (constant*, form+)>
<!ATTLIST formset language CDATA #IMPLIED>
<!ATTLIST formset country CDATA #IMPLIED>
<!ATTLIST formset variant CDATA #IMPLIED>

<!--
      "form"元素定义了一个需要验证的字段集。name属性与web应用中表单
      的相应字段名相同。
-->
<!ELEMENT form (field+)>
<!ATTLIST form name CDATA #REQUIRED>

<!--
      "field"元素定义了需要验证的属性。在一个web应用中,一个字段会对应
      一个在HTML表单中的空间。为了验证这些属性,验证器以JavaBean的方式
      工作。field元素接受如下
      属性:
      property         对应于此field元素的JavaBean(通常为ActionForm)中需要验证的属性。
      depends          在调用证之前所需要调用的其他验证的列表,多个用逗号分隔。
                      如果想要进行当前验证,那么列表中的所有验证必须成功。
      page             与当前表单相应的JavaBean(通常为ActionForm)可能包含一个
                      page属性。只有字段中的"page"属性值等于或者小于表单中的
                      值时框架才会处理JavaBean。如果是使用带有"wizard"(向导)
                      来完成一个大型表单的话,这个属性会非常有用,因为它可以
                      防止某些页面被无意中跳过。
       [0]——默认值。
      indexedListProperty
                      "indexedListProperty"即可以返回一个数组或者Collection类
                      方法名。可以通过此方法得到一个列表然后通过这个列表的循环访问
                      ,执行对字段的验证。
-->
<!ELEMENT field (msg|arg|arg0|arg1|arg2|arg3|var)*>
<!ATTLIST field property CDATA #REQUIRED>
<!ATTLIST field depends CDATA #IMPLIED>
<!ATTLIST field page CDATA #IMPLIED>
<!ATTLIST field indexedListProperty CDATA #IMPLIED>

<!--
      "msg"元素定义了一个自定义消息key,当验证字段失败时,使用此消息key。
      当当前的字段验证失败且msg元素没有指定值时,每个验证器都会使用自身
      默认的消息属性。应用到字段的每个验证器可以有自己的msg元素。
      msg元素接受如下的属性
       name         指定对应此msg元素的验证器(验证规则)的名称。
     
       bundle       指明包含key属性所指名称的消息资源绑定。
       key          消息资源绑定中返回消息模版的key。
       resource     如果设置为"false", 表示直接在key属性中设置文本。如果为
             "true"则使用消息资源绑定中的值。
                   [true]——默认值。
-->
<!ELEMENT msg EMPTY>
<!ATTLIST msg key CDATA #REQUIRED>
<!ATTLIST msg name CDATA #REQUIRED>
<!ATTLIST msg bundle CDATA #IMPLIED>
<!ATTLIST msg resource CDATA #IMPLIED>
 
<!--
      "arg"元素为使用它的验证器或者field定义了消息替换模版。
      arg元素接受如下属性。
       name         与msg元素对应的验证器的名称。
             如果没有指定这个属性,则适用于所有的验证规则,
             并取代position中指定的位置的参数。
           
       bundle       指明包含key属性所指名称的消息资源绑定。
       key          消息资源绑定中返回消息模版的key。
       resource     如果设置为"false", 表示直接在key属性中设置文本。如果为
             "true"则使用消息资源绑定中的值。
                   [true]——默认值。
                 
       position     在消息中替换参数的未知。
             例如,position="0"就是第一个参数。
             [0]——默认值
-->
<!ELEMENT arg EMPTY>
<!ATTLIST arg key CDATA #REQUIRED>
<!ATTLIST arg bundle CDATA #IMPLIED>
<!ATTLIST arg name CDATA #IMPLIED>
<!ATTLIST arg resource CDATA #IMPLIED>
<!ATTLIST arg position CDATA #IMPLIED>
 
<!--
  “特别不建议”通过使用<arg position="0"/>来替代arg0元素!
      "arg0"元素为使用它的验证器或者field定义了消息替换模版中的第一个
      替换参数的值。
      arg0元素接受以下属性。
       name         与msg元素对应的验证器的名称。
     
       key          消息资源绑定中返回消息模版的key。
       resource     如果设置为"false", 表示直接在key属性中设置文本。如果为
             "true"则使用消息资源绑定中的值。
                   [true]——默认值。
-->
<!ELEMENT arg0 EMPTY>
<!ATTLIST arg0 name CDATA #IMPLIED>
<!ATTLIST arg0 key CDATA #IMPLIED>
<!ATTLIST arg0 resource CDATA #IMPLIED>

<!--
  “特别不建议”通过使用<arg position="1"/>来替代arg1元素!
      "arg1"元素为使用它的验证器或者field定义了消息替换模版中的第二个
      替换参数的值。
      arg1元素接受以下属性。
       name         与msg元素对应的验证器的名称。
     
       key          消息资源绑定中返回消息模版的key。
       resource     如果设置为"false", 表示直接在key属性中设置文本。如果为
             "true"则使用消息资源绑定中的值。
                   [true]——默认值。
-->
<!ELEMENT arg1 EMPTY>
<!ATTLIST arg1 name CDATA #IMPLIED>
<!ATTLIST arg1 key CDATA #IMPLIED>
<!ATTLIST arg1 resource CDATA #IMPLIED>

<!--
  “特别不建议”通过使用<arg position="2"/>来替代arg2元素!
      "arg2"元素为使用它的验证器或者field定义了消息替换模版中的第三个
      替换参数的值。
      arg2元素接受以下属性。
       name         与msg元素对应的验证器的名称。
     
       key          消息资源绑定中返回消息模版的key。
       resource     如果设置为"false", 表示直接在key属性中设置文本。如果为
             "true"则使用消息资源绑定中的值。
                   [true]——默认值。
-->
<!ELEMENT arg2 EMPTY>
<!ATTLIST arg2 name CDATA #IMPLIED>
<!ATTLIST arg2 key CDATA #IMPLIED>
<!ATTLIST arg2 resource CDATA #IMPLIED>

<!--
  “特别不建议”通过使用<arg position="3"/>来替代arg3元素!
      "arg3"元素为使用它的验证器或者field定义了消息替换模版中的第四个
      替换参数的值。
      arg3元素接受以下属性。
       name         与msg元素对应的验证器的名称。
     
       key          消息资源绑定中返回消息模版的key。
       resource     如果设置为"false", 表示直接在key属性中设置文本。如果为
             "true"则使用消息资源绑定中的值。
                   [true]——默认值。
-->
<!ELEMENT arg3 EMPTY>
<!ATTLIST arg3 name CDATA #IMPLIED>
<!ATTLIST arg3 key CDATA #IMPLIED>
<!ATTLIST arg3 resource CDATA #IMPLIED>

<!--
      "var"元素设置一个参数,使得field元素把它传递给相应的验证器,
      例如,在一个最小或者最大值的范围验证中的值。这些参数同样也可
      被一个arg?所引用,但是必须通过使用shell语法:${var:var-name}
      才行。
-->
<!ELEMENT var (var-name, var-value, var-jstype?)>
 
<!--
      需要提交给字段验证器的变量的名称。
-->
<!ELEMENT var-name   (#PCDATA)>
 
<!--
      需要提交给字段验证器的变量的值。
-->
<!ELEMENT var-value (#PCDATA)>
<!--
      JavaScript类型,可选值 [int| string | regexp]
-->
<!ELEMENT var-jstype (#PCDATA)>

 

 

【第6步】ErrorDescription.properties文件中添加错误信息

   
打开ErrorDescription.properties文件,在文件的后面添加如下的内容:

  error.name.blank = 姓名不能为空
  error.name.minLength = 
姓名的长度不能小于{0}
  error.name.maxLength = 
姓名的长度不能大于{0}
  error.name.alphanum = 
姓名必须由字母和数字组成
  error.age.blank = 
年龄不能为空
  error.age.integer = 
年龄必须为数字
  error.age.intRange = 
年龄必须在{0}{1}之间

  启动Tomcat,在IE中输入如下的URL来测试程序:

   
http://localhost:8080/samples/%20firstValidator.jsp

   
在输入一些错误信息后,点击“提交”按钮,将出现类似下图的效果。

将会按着depends属性中的约束来验证items属性的每一个值。我们还可以将propertyindexedListProperty配合使用,如下面代码所示:

  <field indexedListProperty="items"  property="employee.age"  depends=>  </field>

    Validator框架将根据上述的配置代码来验证items属性中的每一项的employee.age属性。

二、使用常量和变量

1. 常量

   
Struts1.x系列教程(10):Validator验证框架入门》一文中的name属性使用了mask进行验证。这个mask实际上代表了一个正则表达式。但如果在validator.xml文件中有很多个地方需要用到这个正则表达式,那就它就会在很多地方重复。为此,我们可以使用常量来避免这种事情发生。   

常量分为全局常量和局部常量。

1)全局常量

全局常量可以被用在validator.xml中定义的所有form中。我们可以使用<global>元素来配置全局常量。为了配置全局常量,将如下的内容放到第一个<formset>元素的前面。

  <global>
      
<constant>
          
<constant-name>mask</constant-name>
          
<constant-value> ^[a-zA-Z0-9]*$ </constant-value>
      
</constant>
  
</global>
  
<formset>

2)局部常量
   
局部常量需要放到<formset>元素的开始位置(根据DTD的定义,局部常量只能放到这里,而全局常量可以放在第一个<formset>元素的前面,也可以放到<formset>的后面)。如下面的代码所示:

  <formset>
      
<constant>
          
<constant-name>mask</constant-name>
          
<constant-value> ^[a-zA-Z0-9]*$ </constant-value>
      
</constant>
      
<form name="firstValidatorForm"> 
       
  
</formset>

 我们可以编写如下的代码来使用mask常量:

<var>
    <var-name>mask</var-name>
    <var-value> ${mask}</var-value>
</var>


2. 变量
    Validator
框架通过<var>元素来定义变量。变量将作为<field>的子元素被使用。主要向depends属性值 (如mask)以及<msg>的错误信息传递数据。如下面的代码通过变量required姓名传递给了错误信息的第一个参数{0}

<field property="name"  depends="required ">
    <msg name="required" key="error.name.blank" />
    <arg name="required" key="${var:required}" position="0" resource="false" />
    <var>
        <var-name>required</var-name>
       
<var-value>姓名</var-value>
   
</var>
</field>

三、客户端验证

 使用Validator框架的好处之一就是可以很容易地将服务端验证变为客户端验证(JavaScript验证)。为了完成这一转换,我们只需要修改两个地方。现在就拿Struts1.x系列教程(10):Validator验证框架入门》中的firstValidator.jsp为例来说明要修改什么。
   
首先,在firstValidator.jsp中的任何地方(当然,任何地方指的是客户端代码区,并不包括<%...%><%--... --%>所包含的内容)添加如下的<html:javascript>标签:

  <html:javascript formName="firstValidatorForm"/>

然后在<html:form>标签中加入如下的属性:

  onsubmit="return validateFirstValidatorForm(this);"

    现在再运行firstValidator.jsp,如果输入错误,IE就会直接弹出错误信息对话框。我们查看客户端源代码就会发现,在源代码中多了很多JavaScript代码。实际上,当加入<html:javascript>标签后,在运行JSP页面时,Servlet引擎就会将Validator框架中JavaScript版本的预定义验证代码连同HTML代码都发送到客户端。这些JavaScript代码中有一个入口函数,这个函数的名称前缀为validate,后面是首字母大写的Form名。在<html:form>标签中的onsubmit事件中调用这个入口函数就可以通过JavaScript代码来验证客户端录入的数据了。

下面列出了Validator框架的预定义验证(Struts的版本号为1.2.9)。

Validator

变量

引发条件

required

字段只有空格

validwhen

test

test条件失败(详见下一节)

minlength

minlength

字段的字符数小于minlength

maxlength

maxlength

字段的字符数大于maxlength

mask

mask

字段值不匹配mask所指的个正则表达式

byteshortintegerlongfloatdouble

字段值无法转换为这些数据类型

date

datePattern

datePatternStrict

字值值不能按着指定的格式转换为日期类型

intRangefloatRangedoubleRange

minmax

字段值不在指定的范围内

creditCard

字段值不是一个信誉卡号

email

字段值不是一个合法的email

url

allowallschemes

allow2slashes

nofragments

schemes

字段不是一个URL

关于Validator框架标准验证的详细信息,读者可以访问如下的URL  

http://struts.apache.org/1.2.9/userGuide/dev_validator.html

    下面来举一个validwhen验证的例子。
    validwhen
可以验证当前属性和其他属性的关系,如在验证密码时,要保证两次输入的密码一致,验证代码如下:

<field property="password1" depends="validwhen">
    <msg name="validwhen" key="error.password1.confirmation" />
   
<var>
       
<var-name>test</var-name>
       
<var-value>
            (password1!= null) and (*this* == password)
       
</var-value>
   
</var>
</field>


   
使用validwhen也可以验证嵌套和索引属性,如下面的代码所示:

<field property="field1" depends="validwhen">
    <msg name="validwhen" key="error.field.message" />
   
<var>
       
<var-name>test</var-name>
       
<var-value>
            (*this* == field2.name) and (*this* != field3[1])
       
</var-value>
   
</var>
</field>

    其中*this*表示当前属性的值。

====================================================================

一、动态Form简介

    虽然ActionForm功能强大,但有些时候使用起来有些麻烦。如每建立一个用户录入界面(JSP页面),就得建立一个ActionForm子类来和这个页面对应。当然,我们可以采用嵌套属性从一定程度上弥补这个问题。但是在建立新的用户录入界面时,仍不可避免地要建立新的ActionForm子类。

    Struts1.2.6及以后的Struts版本中提供了一种动态Form的技术。使得不用再建立新的ActionForm就可以封装用户提交的数据。实际上,这种技术将定义ActionForm子类的工作变成了编写XML文件的工作。

    每定义一个动态Form,就要在struts-config.xml中加一个<form-bean>元素,并使用<form-property>子元素来定义动态Form的属性。

    在本章的最后还会介绍一个LazyValidatorForm类,通过这个类甚至可以不定义动态Form的属性就可以使用动态Form。这将大大简化开发人员的工作量。    

二、声明动态Form 

    声明一个动态Form非常简单,只需要在struts- config.xml<form-beans>元素中加入一个<form-bean>子元素,并使用<form- property>元素来定义动态Form的属性。我们可以定义的属性类型有简单属性(如String)、索引属性(如数组)、映射属性(如 HashMap)以及嵌套属性(属性类型是另一个类)。
   
对于动态Form来说,Form的类型必须是org.apache.struts.action.DynaActionForm或其子类。声明一个动态Form的代码如下:

<form-bean name="dynamicForm"  type="org.apache.struts.action.DynaActionForm">
    <!-- 声明一个简单属性 -->
    <form-property name="simpleProp" type="java.lang.String" initial="bill"/>
    <!-- 声明一个索引属性 -->
    <form-property name="indexedProp" type="java.lang.String[]" />
    <!-- 声明一个映射属性 -->
    <form-property name="mappedProp" type="java.util.HashMap" />
    <!-- 声明一个嵌套属性 -->
    <form-property name="nestedProp" type="com.bean.MyBean" />
</form-bean>

三、动态Form的属性类型

    下面列出了动态Form支持的简单属性的所有类型:

  • java.math.BigDecimal
  • java.math.BigInteger
  • java.lang.Boolean
  • java.lang.Byte
  • java.lang.Character
  • java.lang.Class
  • java.lang.Double
  • java.lang.Float
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Short
  • java.lang.String
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp 

实际上,上面的数据类型就是Java中提供了简单数据类型。它们用在动态Form中和在Java中代表的数据类型是完全一样的。我们还可以使用<form-property>元素的initial属性为动态Form的简单属性指定一个默认值。如在例程6-11name属性的默认值为“bill”。

对于索引属性的类型来说,可以是数组,也可以是java.util.List接口的类(如ArrayList)。我们还可以为动态Form的属性指定实现java.util.Map接口的类作为数据类型(也就是映射属性)。但遗憾的是,如果使用动态Form,就无法使用泛型进行自动类型转换了。

四、访问动态Form

    我们可以使用DynaActionForm类的getter方法来读取动态Form中的属性值。DynaActionForm类的getter方法有三个重载形式,分别用来读取简单属性、索引属性和映射属性。这三个getter方法的定义如下:

  public Object get(String name) ;   // 读取简单属性
  public Object get(String name, int index) ;  // 读取索引属性
  public Object get(String name, String key);  // 读取映射属性

   
   
下面的代码演示了如何通过getter方法获得动态Form的属性值:

DynaActionForm dForm = (DynaActionForm)form;
String name = (String)dForm.get("name");
String[] hobbies = (String[])dForm.get(“hobbies”);
String value1 = (String)dForm.get(“myMap”, “key1”);

    除了上述的get方法外,DynaActionForm还提供了getStringgetString方法,分别用来读取StringString[]类型的属性值,这两个方法的定义如下:

public String getString(String name) ;  
public String[] getStrings(String name) ;

    下面的代码演示了如何通过getStringgetStrings方法获得动态Form的属性值:

String name = dForm.getString(“name”);  // 相当于String name = (String)dForm.get("name");
String[] hobbies = dForm.getStrings(“hobbies”);  // 相当于String[] hobbies = (String[])dForm.get(“hobbies”);

    在使用getStringgetStrings方法时应注意,这两个方法只能读取StringString[]类型的属性,读取其他类型的属性将会抛出异常。  

五、一个动态Form的例子

    我们在这一部分来实现一个完整的动态Form的例子,在这个例子中的动态Form有四个属性,三个是简单数据类型,一个是数组类型。完成这个例子需要如下四步:

【第1步】配置动态Form
   
打开struts-config.xml,在<form-beans>元素中加入如下的内容:

<form-bean name="dynamicForm" type="org.apache.struts.action.DynaActionForm">
    <form-property name="name" type="java.lang.String" />
    <form-property name="age" type="java.lang.Short" />
    <form-property name="salary" type="java.lang.Float" />
    <form-property name="hobby" type="java.lang.String[]" />
</form-bean>

【第2步】编写Struts Action
   
这个Struts Action类负责从动态Form中获得属性值,并输出到客户端浏览器。在<samples工程目录>"src"action目录中建立一个DynamicAction.java文件,代码如下:

  package chapter6.action;
  
  
import javax.servlet.http.*;
  
import org.apache.struts.action.*;
  
import java.io.*;
  
  
public class DynamicAction extends Action
  {
      
public ActionForward execute(ActionMapping mapping, ActionForm form,
              HttpServletRequest request, HttpServletResponse response)
      {
          
try
          {
              DynaActionForm dForm = (DynaActionForm) form;
              String name = (String) dForm.get("name");
              Short age = (Short) dForm.get("age");
              Float salary = (Float) dForm.get("salary");
              
// 获得数组类型字段值的数组长度
              int hobbyCount = ((String[]) dForm.get("hobby")).length;
              PrintWriter out = response.getWriter();
              out.println("name: " + name + "<p/>");
              out.println("age: " + age + "<p/>");
              out.println("salary: " + salary + "<p/>");
              
for (int i = 0; i < hobbyCount; i++)
                  out.println("hobby" + (i + 1) + ": " + dForm.get("hobby", i) + "<p/>");
          }
          
catch (Exception e)
          {
          }
          
return null;
      }
  }

【第3步】配置Struts Action     

    打开struts-config.xml文件,在<action-mappings>元素中加入如下的内容:

  <action name="dynamicForm" path="/dynamic" scope="request" type="action.DynamicAction" />


【第4步】编写用户录入数据的JSP页面

    Web根目录中建立一个dynamic.jsp文件,代码如下:

  <%@ page pageEncoding="GBK"%>
  <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
  
<html>
    
<head>
      
<title>测试动态Form</title>
      
<html:base/>
    
</head>
    
<body> 
      
<html:form action="dynamic"  >
         
  名:<html:text property="name" />&nbsp;&nbsp;<p>
         
  龄:<html:text property="age" />&nbsp;&nbsp;<p>
         
  资:<html:text property="salary" />&nbsp;&nbsp;<p>
         
爱好1<html:text property="hobby"  value=""/>&nbsp;&nbsp;<p>
         
爱好2<html:text property="hobby" value=""/>&nbsp;&nbsp;<p>
         
爱好3<html:text property="hobby" value=""/>&nbsp;&nbsp;<p>
                
<html:submit value="提交" />
      
</html:form>  
    
</body> 
  
</html>


   
启动Tomcat后,在IE中输入如下的URL来测试程序:

http://localhost:8080/samples/dynamic.jsp

六、验证动态Form

有两种方法可以验证动态Form

1. DynaActionForm的子类中覆盖validate方法。

2. 如果要使用Validator框架来验证动态Form,需要用DynaActionForm的子类org.apache.struts.validator. DynaValidatorForm或其子类来作为动态Form的类型。

在使用DynaValidatorForm的了类时,要想使用Validator框架的验证机制,需要在DynaValidatorForm子类的validate方法的开始位置使用 super.validate()语句来调用DynaValidatorForm中的validate方法

你可能感兴趣的:(Validator验证框架)