validwhen主要用于关联验证,即为了验证某个域的值,可能会参考其它域的值来进行综合判断,以确定该域的值是否符合要求。
1. ValidWhen表达式及其注意事项
官档中这样描述:
The validwhen rule takes a single var field, called test. The value of this var is a boolean expression which must be true in order for the validation to success. The values which are allowed in the expression are:
-
Single or double-quoted string literals.
-
Integer literals in decimal, hex or octal format
-
The value null which will match against either null or an empty string
-
Other fields in the form referenced by field name, such as customerAge
-
Indexed fields in the form referenced by an explicit integer, such as childLastName[2]
-
Indexed fields in the form referenced by an implicit integer, such as childLastName[], which will use the same index into the array as the index of the field being tested.
-
Properties of an indexed fields in the form referenced by an explicit or implicit integer, such as child[].lastName, which will use the same index into the array as the index of the field being tested.
-
The literal *this, which contains the value of the field currently being tested
具体请看Struts官档中Designing Complex Validations with validwhen的描述。
大意为:输入给validwhen的是一个布尔型表达式(对该表达式的解析使用了antlr),其引用名为test,即形如:
test
expression
即,当expression为真(true)时,该域验证通过,其中,expression可以使用的元素包括:
1). 单/双引号的字符字面量
2). 十进制、十六进制或八进制的整型字面量
e.g. 一表单要求用户以英尺为单位输入他们的身高,假如少于60inches,将提示错误。
<field property="nbaPointGuard" depends="validwhen"> <arg0 key="careers.nbaPointGuard.label"/> <var> <var-name>test</var-name> <var-value>((heightInInches >= 60) or (*this* == null))</var-value> </var> </field>
3). NULL值将匹配NULL或空字符串""
4). 通过域名引用表单中的其它域,如客户年龄等
e.g. 有一个包含sendNewsletter和emailAddress的表单,且仅当sendNewsletter不为空时,emailAddress也不为空。可使用如下validwhen规则:
<field property="emailAddress" depends="validwhen"> <arg0 key="userinfo.emailAddress.label"/> <var> <var-name>test</var-name> <var-value>((sendNewsletter == null) or (*this* != null))</var-value> </var> </field>
这条规则解释为:假如sendNewsletter为空或emailAddress不为空时,此规则生效。
5). 通过整数直接引用表单中的索引域,如: childLastName[2]
6). 通过整数间接引用表单中的索引域,如:childLastName[], 这将使用同样的索引指向被测域的数组索引
7). 通过整数间接或直接引用表单中的属性索引域,如 child[].lastName, 这也将使用同样的索引指向被测域的数组索引
e.g. 假设有个带些输入行的表单允许用户输入他们想订购的零件编号和数量。一个称为orderLines的orderLine类的beans数组被用来存储录入的属性。假如你想验证每个输入行的零件编号和订购数量,可以像这样:
<field property="quantity" indexedListProperty="orderLines" depends="validwhen"> <arg0 key="orderform.quantity.label"/> <var> <var-name>test</var-name> <var-value>((orderLines[].partNumber == null) or (*this* != null))</var-value> </var> </field>
这条规则的意思是:这个域的值假如符合零件编号为null,或这域不为空,则此规则生效。
8). 字面量 *this, 它包含当前被测域的值; *this* 表正被验证的属性自身的变量引用
e.g. 下面表*this*引用当前userName变量:
<field property="userName" depends="validwhen"> <arg0 key="userinfo.userName"/> <var> <var-name>test</var-name> <var-value>(*this* != null))</var-value> </var> </field>
注意:
a. 所有比较必须存放于括号内;
b. 在使用and和or时,在同一级的逻辑运算中,同时只能存在一个逻辑运算符,要么是and,要么是or;
e.g. 下面的表达式是不合法的:xxx and yyy and zzz或者xxx or yyy or zzz或者xxx and yyy or zzz等等。为了让复杂的表达变得合法,可以让一个复杂的表达式变为多级的表达形式,每一级只有一个and或一个or就可以了,例如:
xxx and yyy and zzz是错误的,进行一下简单的变换:
(xxx and yyy) and zzz或者xxx and (yyy and zzz)等都是合法的。
c. 假如两个比较项转化为整数,将以数字方式进行比较,否则将以字符方式比较。
2. 错误消息的定制
无论是validwhen还是其它验证例程,都可以定制验证出错后的错误信息,定制消息有两种方式,即全局/本地方式。
1)全局方式
在validator-rules.xml中某个validator里面定义的消息,参数名为msg,例如:
<validator name="email" classname="org.apache.struts.validator.FieldChecks" method="validateEmail" methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.apache.struts.action.ActionMessages, org.apache.commons.validator.Validator, javax.servlet.http.HttpServletRequest" depends="" msg="errors.email"/>
其中,msg的值为resource bundle中的一个属性名。例如在resource bundle文件中存在如下定义:errors.email={0} is an invalid e-mail address.
<msg name="validatorName" resource="booleanValue" key="value"></msg>e.g.
<field property="endDate" depends="validwhen"> <msg name="validwhen" key="date.validwhen"/> <arg0 key="start time" resource="false"/> <arg1 key="end time" resource="false"/> <var> <var-name>test</var-name> <var-value>((*this* != null) and (*this* > startDate))</var-value> </var> </field>
如果全局已经定义了 msg的信息,而且本地的 msg的 key与全局的 msg的 key相同,那么在该 field的验证中,本地的 msg将覆盖全局的 msg。
<arg0></arg0>到<arg4></arg4>的属性中也有name属性,即该arg参数所应用的验证例程,例如: <arg0 name="date" key="label.startDate"></arg0>,该参数用于date验证的出错信息。
约束:日期格式为:年(四位数)-月(两位数)-日(两位数),而且终止日期大于起始日期。
<field property="startDate" depends="date"> <arg0 key="form.date.start"/> <var> <var-name>datePatternStrict</var-name> <var-value>yyyy-MM-dd</var-value> </var> </field> <field property="endDate" depends="validwhen,date"> <msg name="validwhen" key="date.validwhen"/> <arg0 name="validwhen" key="form.date.start"/> <arg1 name="validwhen" key="form.date.end"/> <arg0 name="date" key="form.date.end"/> <var> <var-name>test</var-name> <var-value>((*this* != null) and (*this* > startDate))</var-value> </var> <var> <var-name>datePatternStrict</var-name> <var-value>yyyy-MM-dd</var-value> </var> </field>
form.date.end=终止日期
date.validwhen= {0}不能大于{1}!