JavaScud | Forum | JIRA | Blog |
  Dashboard > WebWork2文档中文化计划 > WebWork > Validation
  WebWork2文档中文化计划 Log In View a printable version of the current page.  
  Validation
Added by scud, last edited by scud on May 20, 2006  (view change)
Labels: 
(None)

WebWork依赖XWork的校验框架,在你的action被执行之前,来启用对你的action的输入数据的校验规则的运用.本章节仅提供了最基本的内容来让你上手,并集中精力在WebWork为了支持客户端校验对XWork的校验器的扩展上.

对于基于客户端的校验(JavaScript 和/或 AJAX) 还有一个选项,请浏览 客户端校验 了解更多信息.

示例

  1. 基本校验
  2. 客户端校验
  3. AJAX校验
  4. 使用字段校验器
  5. 使用非字段校验器
  6. 使用Visitor字段校验器

WebWork 里可用的校验器

注意

当使用一个字段校验器的时候,字段校验器语法一般回避使用普通的校验器语法更好,因为它更宜于按照字段对字段校验器进行分组.这是非常方便的,特别是一个字段需要有多个字段校验器的时候,而这种情况会经常发生.例如: validatortypes

 

  1. 必填校验器
  2. 必填字符串校验器
  3. 整数校验器
  4. 日期校验器
  5. 表达式校验器
  6. 字段表达式校验器
  7. 邮件校验器
  8. 网址校验器
  9. visitor校验器
  10. 转换校验器
  11. 字符串长度校验器
  12. 正则表达式校验器

注册校验器

校验规则是通过校验器来处理的,它们必须注册到 ValidatorFactory (使用 registerValidator 方法).最简单的方法就是添加一个文件名为 validators.xml 的文件在你的classpath (/WEB-INF/classes) 的根目录下,来声明所有你想使用的校验器.

这个列表声明了所有WebWork带来的校验器.

<validators>
    <validator name="required" class="com.opensymphony.xwork.validator.validators.RequiredFieldValidator"/>
    <validator name="requiredstring" class="com.opensymphony.xwork.validator.validators.RequiredStringValidator"/>
    <validator name="int" class="com.opensymphony.xwork.validator.validators.IntRangeFieldValidator"/>
    <validator name="double" class="com.opensymphony.xwork.validator.validators.DoubleRangeFieldValidator"/>
    <validator name="date" class="com.opensymphony.xwork.validator.validators.DateRangeFieldValidator"/>
    <validator name="expression" class="com.opensymphony.xwork.validator.validators.ExpressionValidator"/>
    <validator name="fieldexpression" class="com.opensymphony.xwork.validator.validators.FieldExpressionValidator"/>
    <validator name="email" class="com.opensymphony.xwork.validator.validators.EmailValidator"/>
    <validator name="url" class="com.opensymphony.xwork.validator.validators.URLValidator"/>
    <validator name="visitor" class="com.opensymphony.xwork.validator.validators.VisitorFieldValidator"/>
    <validator name="conversion" class="com.opensymphony.xwork.validator.validators.ConversionErrorFieldValidator"/>
    <validator name="stringlength" class="com.opensymphony.xwork.validator.validators.StringLengthFieldValidator"/>
    <validator name="regex" class="com.opensymphony.xwork.validator.validators.RegexFieldValidator"/>
</validators>

 
注意

validators.xml如果已经定义了,那么它应该在classpath中可以找到.然而如果不需要自定义的校验器,那么这不是必须的.WebWork会自动从发布包里的xwork jar文件中取得一个事先定义好的校验器集合(com/opensymphony/xwork/validator/validators/default.xml). 浏览ValidatorFactory的static块来了解详细信息.
 

 
警告

如果自定义的校验器被定义了而且创建了一个validators.xml文件并放在classpath中,记得复制所有其他你需要的预定义的校验器到validators.xml里,如果你不需要注册则不需要.一旦validators.xml在classpath里被检测到,缺省的 (com/opensymphony/xwork/validator/validators/default.xml)就不会被装载了.只有没发现自定义 validators.xml的时候才会装载.要小心.
 


 

打开校验

缺省的 validationWorkflowStack 已经包含了这个.
为了开启一个action的校验所有需要做的就是在action的拦截器ref中包含ValidationInterceptor (浏览 xwork.xml ),就像这样:

<interceptor name="validator" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>

注意: 缺省的 validationWorkflowStack 已经包含了这个拦截器.

校验器会话范围

字段校验器,就像名字暗示的那样,作用在通过action可以访问的单个字段上.一个校验器(译注:怀疑为 "一个非字段校验器" ),与字段校验器相反,是一个更普通的,能在全部的action上下文中进行校验,可以在校验规则中包含多于一个字段(甚至根本不是字段).大多数的校验可以基于每个字段的基础上定义.只要可能字段校验器相对非字段校验器都是首选的,字段校验器的信息是绑定到相关的字段上的,并会在对应的视图(页面)中显示在对应输入元素的周围.
 

非字段校验器仅会添加action级别的信息.非字段校验器经常是domain相关的因为经常是自定义的实现.XWork/WebWork提供的最重要的标准非字段校验器是 ExpressionValidator .
 

注意事项

非字段校验器优先于字段校验器,而不管在 *-validation.xml 里是如何定义的.如果一个非字段校验器是短路的,它会引发它的非字段校验器不会被执行.查看校验框架的文档了解更多信息.

定义校验规则

校验规则可以被指定:

  1. 每个Action类: 在一个 ActionName-validation.xml 文件中
  2. 每个Action的别名: 在一个 ActionName-alias-validation.xml 文件中
  3. Action类的继承层次关系和实现的接口: WebWork 搜索action的层次关系树来来查找action的父类和实现的接口的缺省校验

这是一个 SimpleAction-validation.xml 的例子:
 

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
       "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
  <field name="bar">
      <field-validator type="required">
          <message>You must enter a value for bar.</message>
      </field-validator>
      <field-validator type="int">
          <param name="min">6</param>
          <param name="max">10</param>
          <message>bar must be between ${min} and ${max}, current value is ${bar}.</message>
      </field-validator>
  </field>
  <field name="bar2">
      <field-validator type="regex">
          <param name="regex">[0-9],[0-9]</param>
          <message>The value of bar2 must be in the format "x, y", where x and y are between 0 and 9</message>
     </field-validator>
  </field>
  <field name="date">
      <field-validator type="date">
          <param name="min">12/22/2002</param>
          <param name="max">12/25/2002</param>
          <message>The date must be between 12-22-2002 and 12-25-2002.</message>
      </field-validator>
  </field>
  <field name="foo">
      <field-validator type="int">
          <param name="min">0</param>
          <param name="max">100</param>
          <message key="foo.range">Could not find foo.range!</message>
      </field-validator>
  </field>
  <validator type="expression">
      <param name="expression"> foo &gt; bar</param>
      <message>Foo must be greater than Bar. Foo = ${foo}, Bar = ${bar}.</message>
  </validator>
</validators>

 

这里我们可以看到SimpleAction类的校验器配置.校验器(和字段校验器)必须有一个type属性,指向在前面说的 ValidatorFactory 中注册的校验器的名字.validators元素还必须有<param>元素,带有name和value属性来设置校验器实例的任何需要设置的参数.浏览下面的文字来讨论message元素.

每个Validator 或者 Field-Validator 元素必须在validator元素体内定义一个message元素.这个message元素有一个属性,key,它不是必填的.message标签的body会被当作缺省的信息,如果校验失败它会被添加到Action中.Key用来在Action的资源包里作为寻找一个信息的主键,如果Action实现了LocaleAware接口(ActionSupport已经实现了这个接口),那么会使用getText()来获取本地化信息.这个功能基于用户发起请求的Locale(或者任何你设置到实现了LocaleAware的Action中的Locale)来提供本地化信息.在不管是使用Key值从资源包中获取信息还是使用缺省的信息,当前的校验器被推送ValueStack中,然后消息被解析来处理其中的 \${...} 部分, \${ 和 } 中间的部分会被求值然后替换相应的部分.这允许你使用校验器,Action或者两者兼有的值来参数化你的信息.

如果校验器失败了,校验器会被推送到ValueStack中,信息也会,不管是缺省的还是本地化的信息(如果key属性被指定,而且存在对应的信息),消息被解析来处理其中的 \${...} 部分, \${ 和 } 中间的部分会被求值然后替换相应的部分.这允许你使用校验器,Action或者两者兼有的值来参数化你的信息.

注意
因为校验规则是在一个XML文件里,你必须要转义特殊字符.例如,注意上面的expression校验器规则,我们使用 ">" 来代替">".参考一个XML相关的文档来了解必须转义的字符的全部列表.最常使用的必须转义的字符是: & (使用 &amp; ), > (使用 &gt; ) 和 < (使用 &lt; ).

这是一个参数化信息的例子:

这会把 IntRangeFieldValidator 的 min和max参数以及Action中的bar的值设置到信息里.

bar must be between ${min} and ${max}, current value is ${bar}.

 
为了给一个Action定义校验规则,在Action相同的包下面创建一个 ActionName-validation.xml 的文件.你也可能需要创建一个别名特定的校验规则,它会添加在ActionName-validtion.xml里面定义的缺省校验规则,只要在相同的目录下创建一个ActionName-aliasName-validation.xml名称的文件就可以.( 译注:此段翻译的可能有点问题.使用别名校验时也会使用缺省的校验规则校验 ) 在两种情况下,ActionName都是Action类的名字,aliasName是在Action的配置文件里xwork.xml里面定义的Action的别名.

框架也会搜索Action的层次关系树来查找Action的父类或者实现的接口的校验规则.当联合使用 ModelDriven Action和 VisitorFieldValidator 时这特别强大.这是一个校验规则如何发现的例子.给出下面的类结构:

  • 接口 Animal;
  • 接口 Quadraped 扩展了 Animal;
  • 类 AnimalImpl 实现了 Animal;
  • 类 QuadrapedImpl 扩展了 AnimalImpl 实现了 Quadraped;
  • 类 Dog 扩展了 QuadrapedImpl;

如果Dog要被校验,框架方法会查找下面的配置文件:

  • Animal
  • Animal-aliasname
  • AnimalImpl
  • AnimalImpl-aliasname
  • Quadraped
  • Quadraped-aliasname
  • QuadrapedImpl
  • QuadrapedImpl-aliasname
  • Dog
  • Dog-aliasname

这个过程类似XWork的本地化框架查找信息时的过程,也有一些小小的不同.最重要的区别时校验规则是自上而下的.

注意: 按照上面的类层次关系的定义,子节点的 *-validation.xml 会覆盖父接口 *-validation.xml .

校验器风味(Flavour)

XWork发布包提供的校验器(以及你可能自己编写的任何校验器)分为两种风味:

  1. 普通校验器 /非字段校验器
  2. 字段校验器

简单的校验器(例如ExpressionValidator)执行校验检查不是绑定到单一的指定的字段上的.当你在你的 -validation.xml 文件中声明一个简单的校验器时,你不需要把一个fieldname属性和它关联(你应该避免使用下面描述的语法来使用简单校验器).

字段校验器(例如EmailValidator)设置用来在一个单一字段上进行校验检查.它们要求你在你的 -validation.xml 文件中执行一个fieldname属性.有两种不同的XML语法(但是等效)你可以用来声明字段校验器(浏览下面的 " Vs " 的语法).

两种风味的校验器有两个地方有重要的区别需要记住:

  1. 当选择xml语法用来声明一个校验器 (或者)
  2. 当使用 short-circuit 特性

注意: 注意你不需要在你的 -validation.xml 文件里声明你使用了那种 "风味",你仅仅需要声明要使用的校验器的名字,WebWork会知道它是一个普通的校验器还是一个字段校验器,这通过查看校验器编写者选择实现的校验类来实现.

非字段校验器 Vs 字段校验器

有两种方法你可以在你的 -validation.xml 文件里定义校验器:

  1. <validator>
  2. <field-validator>

无论使用那种语法都要记住后面的内容:

非字段校验器 <validator>元素允许你声明两种校验器的任何一种(普通校验器或者字段相关的字段校验器).

 

<!-- Declaring a plain Validator using the 
 <validator> syntax: -->

   <validator type="expression>
         <param name="expression">foo &gt; bar</param>
         <message>foo must be great than bar.</message>
   </validator>

 

<!-- Declaring a field validator using the 
 <validator> syntax; -->

   <validator type="required">
        <param name="fieldName">bar</param>
        <message>You must enter a value for bar.</message>
   &lt/validator>

字段校验器 <field-validator> 元素基本和<validator>元素相同,除了它们从封闭的<field>元素集成了fieldName属性. 使用一个 <field-validator> 元素定义的字段校验器的fieldName属性会自动被它们的父节点<field>元素的fieldName属性填充.这个结构的理由事方便地为一个特定的字段在一个元素下对校验器进行分组,否则fieldName属性会必须被重复,一次又一次,在每个单独的<validator>上.

提示: 在一个<field>标签内定义字段校验器比使用带有一个fieldName参数的<validator>标签好的多,而且xml代码本身也清晰的多(字段分组更清晰了)

注意: 注意你应该在一个块内仅使用一个字段校验器(不是普通校验器).一个<field>内的普通校验器是不允许的,解析xml的时候就会发生错误,因为它在定义的dtd (xwork-validator-1.0.2.dtd) 内是不允许的.

使用<field-validator>语法来声明一个字段校验器:

<field name="email_address">
  <field-validator type="required">
      <message>You cannot leave the email address field empty.</message>
  </field-validator>
  <field-validator type="email">
      <message>The email address you entered is not valid.</message>
  </field-validator>
</field>

选择权在你手里.仅使用没有任何元素的校验器并且为它们的每一个设置fieldName属性是完全合法的.(It's perfectly legal to only use elements without the elements and set the fieldName attribute for each of them. ) 下面的两种方式是等效的:

<field name="email_address">
  <field-validator type="required">
      <message>You cannot leave the email address field empty.</message>
  </field-validator>
  <field-validator type="email">
      <message>The email address you entered is not valid.</message>
  </field-validator>
</field>
<validator type="required">
  <param name="fieldName">email_address</param>
  <message>You cannot leave the email address field empty.</message>
</validator>
<validator type="email">
  <param name="fieldName">email_address</param>
  <message>The email address you entered is not valid.</message>
</validator>

 

短路校验器

从XWork 1.0.1开始(绑定在WebWork 2.1内),短路一堆校验器变为可能.这是另外一个示例配置文件,包含了从XWork的测试用例里面的校验规则:注意一些 <field-validator> 和<validator> 元素具有 short-circuit属性并设置为true.

<!DOCTYPE validators PUBLIC 
        "-//OpenSymphony Group//XWork Validator 1.0.2//EN" 
        "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
  <!-- Field Validators for email field -->
  <field name="email">
      <field-validator type="required" short-circuit="true">
          <message>You must enter a value for email.</message>
      </field-validator>
      <field-validator type="email" short-circuit="true">
          <message>Not a valid e-mail.</message>
      </field-validator>
  </field>
  <!-- Field Validators for email2 field -->
  <field name="email2">
     <field-validator type="required">
          <message>You must enter a value for email2.</message>
      </field-validator>
     <field-validator type="email">
          <message>Not a valid e-mail2.</message>
      </field-validator>
  </field>
  <!-- Plain Validator 1 -->
  <validator type="expression">
      <param name="expression">email.equals(email2)</param>
      <message>Email not the same as email2</message>
  </validator>
  <!-- Plain Validator 2 -->
  <validator type="expression" short-circuit="true">
      <param name="expression">email.startsWith('mark')</param>
      <message>Email does not start with mark</message>
  </validator>
</validators>

短路和校验器风味

简单校验器优先字段校验器.它们首先按照它们定义的顺序被校验,然后字段校验器按照它们定义的顺序来校验.如果某个被标记为短路的校验器失败了,将会阻止其他后续的校验器的进行,然后一个错误(action错误或者字段错误,取决于校验器的类型)将会被添加到被校验的对象的ValidationContext中.

在上面的例子中,实际的校验器执行是这样的:

  1. Plain Validator 1
  2. Plain Validator 2
  3. email字段的字段校验器
  4. email2字段的字段校验器

因为普通校验器2是短路的,如果它的校验失败,它会导致email字段的校验器和email2字段的校验器不会被执行.

有用的信息: 更复杂的校验也许应该在action自己的validate()方法中进行(假定action实现了Validatable接口,ActionSupport已经实现了)

一个普通校验器(非字段校验器)如果被短路会完全打短校验过程,没有其他校验器会被执行,而普通校验器优先于字段校验器意味着普通校验器会按照它们定义的顺序被执行,会在字段校验器按照它们定义的顺序执行之前被执行.

短路校验和校验器风味

一个字段校验器如果被短路了仅会阻止其他相同字段的字段校验器被执行. Note that this "same field" behavior applies regardless of whether the or syntax was used to declare the validation rule. 例如,给出这个 -validation.xml文件:

<validator type="required" short-circuit="true">
  <param name="fieldName">bar</param>
  <message>You must enter a value for bar.</message>
</validator>

<validator type="expression">
  <param name="expression">foo gt bar</param>
  <message>foo must be great than bar.</message>
</validator>

两个校验器都会执行,甚至 "required" 校验器被短路. "required" 校验器是一个字段校验器,不会短路普通校验器,因为字段校验器仅会短路相同字段上的其他校验器.因为普通校验器不是字段特定的,它不会被短路.

如何发现一个Action的校验器

正如上面所提到的,框架会搜索action的层次关系树来查找Action实现的接口和父类的缺省校验.如果你使用了短路属性,并高度依赖层次关系树中的缺省校验器, make sure you don't accidentally short-circuit things higher in the tree that you really want!

AJAX Validation (WebWork2文档中文化计划)
Basic Validation (WebWork2文档中文化计划)
Client Side Validation (WebWork2文档中文化计划)
Client Validation (WebWork2文档中文化计划)
conversion validator (WebWork2文档中文化计划)
date validator (WebWork2文档中文化计划)
email validator (WebWork2文档中文化计划)
expression validator (WebWork2文档中文化计划)
fieldexpression validator (WebWork2文档中文化计划)
int validator (WebWork2文档中文化计划)
regex validator (WebWork2文档中文化计划)
required validator (WebWork2文档中文化计划)
requiredstring validator (WebWork2文档中文化计划)
stringlength validator (WebWork2文档中文化计划)
url validator (WebWork2文档中文化计划)
Using Field Validators (WebWork2文档中文化计划)
Using Non Field Validators (WebWork2文档中文化计划)
Using Visitor Field Validator (WebWork2文档中文化计划)
visitor validator (WebWork2文档中文化计划)

我认为"短路校验和校验器风味"部分的英文对应部分,提出一下问题
Note that this "same field" behavior applies regardless of whether the or syntax was used to declare the validation rule. 这里英文有点问题,在"whether the or" 中的or前后丢了东西,应该是<validator 和<field ,就是字段验证器可以使用的两种语法

还有它气候举的那个例子,根本不能说明字段验证器的短路是将添加在同一个字段上的字段验证器给阻止掉,expression是普通验证器,它优先执行了,怎么会被字段验证器短路呢

所以我觉得英文文档在这里是有点小问题的,不能怪中文翻译。

不对之处,请多指教

Posted by Anonymous at Oct 20, 2006 12:00 | Reply To This

确实是这样。文档有挺多错误的——他们直接从API文档里拷贝过来的。
不仅如此,我还发现:
在服务器校验里,不管是否使用短路,效果都是短路。
在客户端校验里,不管是否设置短路,效果都是不短路。

如有不同意之处,请指出!

by yeeku.H.lee

Posted by Anonymous at May 30, 2007 10:00 | Reply To This

原文 注意: 按照上面的类层次关系的定义,子节点的 *-validation.xml 会覆盖父接口 *-validation.xml .
英文也是这样的意思.可是我发现实际并非这样,无论从源代码还是效果测试,都发现不是override,而是add up.
详细解释可以看http://forums.opensymphony.com/thread.jspa?threadID=46962&tstart=0

sunfy

Posted by Anonymous at Oct 20, 2006 15:38 | Reply To This

你说的很对,我发现Struts2的文档这个地方也是错的。

测试后,确实添加,而不是覆盖。

Posted by Anonymous at May 30, 2007 09:58 | Reply To This

发现一个WEBWORK2的一个问题,是关于客户段验证的,个人觉得不是很友好
客户端的验证的时候,如果验证到哪个字段不对,比如:一个input不能为空,它知识提示了信息,不能把鼠标指针定位到input里面,
当FORM里面加入validation="true",第一次进入page也会跳出验证提示,有点让人不能理解

Posted by Anonymous at Oct 31, 2006 12:26 | Reply To This

有人作过变数表单域的验证吗
比如在html上

<input name="persons[0].name />
<input name="persons[1].name />
<input name="persons[2].name />
.....

<input name="persons[n].name />
这个n每次都不确定,是客户根据自己的需要添加的,不知道webwork验证有没有这方面的功能
验证配置文件怎么配置

Posted by Anonymous at Mar 19, 2008 17:06 | Reply To This

<input name="persons[0].name /> 的验证有些文档说可以通过persons[*].name来实现,我没成功,但是用collection校验是可以的
<field name="persons">
<field-validator type="collection">
<param name="property">persons.name</param>
<param name="validatorRef">required</param>
<param name="validatorParams['trim']">true</param>
<message> amount require </message>
</field-validator>
<field-validator type="collection">
<param name="property">persons.id</param>
<param name="validatorRef">required</param>
<param name="validatorParams['defaultMessage']">Must be filled in</param>
<message> frequency require </message>
</field-validator>

Posted by Anonymous at Mar 24, 2008 16:42 | Reply To This

<input name="persons[0].name /> 的验证有些文档说可以通过persons[*].name来实现,我没成功,但是用collection校验是可以的
<field name="persons">
<field-validator type="collection">
<param name="property">persons.name</param>
<param name="validatorRef">required</param>
<param name="validatorParams['trim']">true</param>
<message> amount require </message>
</field-validator>
<field-validator type="collection">
<param name="property">persons.id</param>
<param name="validatorRef">required</param>
<param name="validatorParams['defaultMessage']">Must be filled in</param>
<message> frequency require </message>
</field-validator>
==============================================================================
这个是可以,但是如何给每个字段添加多个验证器呢
<param name="validatorRef">required</param>
这个是否只能指定一个验证器,如果多个如何配置

Posted by Anonymous at Apr 25, 2008 15:52 | Reply To This
Site running on a free Atlassian Confluence Open Source Project License granted to WebWork China. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.3 Build:#808 May 29, 2007) - Bug/feature request - Contact Administrators