Valang 是 Validation Language 的缩写,Valang Validator 的字面含义就是“使用验证语言的验证器”,是一种支持声明的验证器。本文详细的介绍了 ValangValidator 的使用和相关所需的配置。作为一种新型的验证工具,它提供的验证语言(valang)具有简单、易学,易扩展等特点。
Valang 是 Validation Language 的缩写,Valang Validator 的字面含义就是“使用验证语言的验证器”,它是一种支持声明的验证器。作为新出的验证工具,它拥有不同于现有其它相似工具的特点:
- 基于声明的验证工具包,大多数情况下可以避免手工书写代码。
- 提供了一套精巧的 DSL(Domain Specific language),支持表达式语言。语法非常简洁,且支持扩展方便。
- 配置精简,可读性高、易维护。
- 包含在 Spring Module 中,简化了 Spring Framework 的 Validator 使用。
- 支持 JavaScript,对于 Web 应用,支持客户端的验证。
本文将带领读者对以上特点一一寻访,在进一步阅读本文之前,请确保读者具有 Spring Framework 的使用经验,如果有 Spring MVC 的经验更佳。
Valang Validator 属于 Spring Module 的 Validation 模块。Spring Module 是一组扩展 Spring Framework 功能的工具集,当前的版本是 0.6。它作为独立于 Spring Framework 的项目而存在,其目的非常单纯:方便 Spring Framework 与其它框架的集成,避免为此修改 Spring Framework 的核心。
使用 Valang Validator 必须先了解它的两个重要组件:
- valang,即验证语法,使用者使用它将约束定义转化为 ValangValidator 能解析的验证规则。
- ValangValidator,它是 Spring Validator 接口的具体实现。负责验证规则解析,完成实际的验证工作。
了解了这些关于 Valang Validator 的信息之后,不妨从一个例子来了解它的使用。本例使用的环境:JDK 1.5、Spring Framework2.0 和 Spring Module 0.6。
为了尽可能的体现 Valang Validator 的特点,例子中需要验证的对象有意地被设计得稍微有些复杂:首先,属性是最常见的 3 种类型,而且其中还有一个是在 Java 中有些烦人的Date;其次,它还包含了一个成员类属性。关于类结构和相关的约束如下表:
类结构 | 约束 |
---|---|
public class User { private String name; private int age; private Date birthday; private Address address; …… } public class Address { private String state; private String town; private String street; …… } | name,必填,且长度不超过 50。 age,非必填,必须大于等于 0,小于等于 60。 birthday,非必填,必须在 2000-01-01 之后。 address.state,必填,长度不超过 50。 address.town,必填,长度不超过 50。 address.street,必填,长度不超过 200。 |
实现 Valang Validator 就是要完成两部分工作:定义 valang 描述和 Validator 创建。Validator 的创建可以使用 Java 代码进行,也可使用 Spring DI 完成。本例采用后一种方法,Bean 定义如下(文件名:valang.xml):
<bean id="userValidator" class="org.springmodules.validation.valang.ValangValidator"> <property name="valang"> <value> <![CDATA[ { name : ? is not null and ? has text and length(?)<= 50 : 'Name is empty or too long.'} { age : ? between 0 and 60 : 'Age should between 0 and 60.'} |-------10--------20--------30--------40--------50--------60--------70--------80--------9| |-------- XML error: The previous line is longer than the max of 90 characters ---------| { birthday : ? is null or ? >[20000101] : 'Birthday should be after 2000-01-01.'} { address : ? is not null : 'Address is empty.'} { address.state : address is null or ( ? is not null and ? has text and length(?)<=50 ) : 'state is empty or too long.'} { address.town : address is null or ( ? is not null and ? has text and length(?)<=50 ) : 'town is empty or too long.'} { address.street : address is null or ( ? is not null and ? has text and length(?)<=50 ) : 'street is empty or too long.'} ]]> </value> </property> <property name="dateParsers"> <map> <entry key="^\\d{8}$" value="yyyyMMdd" /> </map> </property> </bean> |
瞧,没有一行 Java 代码,居然完成了一个 Validator 的定义。这其中的秘密就是 valang 属性,它定义了验证规则。再看看它的语法,是不是很酷?!另一个属性 dateParsers 定义了日期转换的格式。关于它们的解释在后面有详细的介绍。
技巧:
如果 Adress 对象被多个对象引用,且对于 Address 的验证约束相同,那么以上的 address 相关的约束规则就需要重复书写。这样,既繁且不利于维护。此时,可以将 address 相关的约束组织成一个 validator,实现约束的复用。具体步骤:
a) 抽取 Address 的约束到 addressValidator。
<bean id="addressValidator" class="org.springmodules.validation.valang.ValangValidator"> <property name="valang"> <value> <![CDATA[ { state : ? is not null and ? has text and length(?)<=50 : 'state is empty or too long.'} { town : ? is not null and ? has text and length(?)<=50 : 'town is empty or too long.'} { street : ? is not null and ? has text and length(?)<=50 : 'street is empty or too long.'} ]]> </value> </property> </bean> |
b) 实现继承 ValangValidator 的 UserValidator,包含 addressValidator:
public class UserValidator extends ValangValidator { private Validator addressValidator; public void setAddressValidator(Validator addressValidator) { this.addressValidator = addressValidator; } public void validate(Object target, Errors errors){ super.validate( target, errors); Address address= ((User)target).getAddress(); // address 为 null 时,不进行进一步的验证。 if( |