spring2.0
Validator接口
Method Summary
boolean |
supports(Classclazz) Can this Validator validate instances of the supplied clazz ? |
void |
validate(Objecttarget, Errorserrors) Validate the supplied target object, which must be of a Class for which the supports(Class) method typically has (or would) return true . |
<!-- ============ METHOD DETAIL ========== --><!-- -->
Method Detailboolean supports(Classclazz)
Validator
validate
instances of the supplied
clazz
?
This method is typically implemented like so:
return Foo.class.isAssignableFrom(clazz);(Where
Foo
is the class (or superclass) of the actual object instance that is to be
validated
.)
clazz
- the
Class
that this
Validator
is being asked if it can
validate
true
if this
Validator
can indeed
validate
instances of the supplied
clazz
void validate(Objecttarget, Errorserrors)
target
object, which must be of a
Class
for which the
supports(Class)
method typically has (or would) return
true
.
The supplied errors
instance can be used to report any resulting validation errors.
target
- the object that is to be validated (can be
null
)
errors
- contextual state about the validation process (never
null
)
ValidationUtils
<!-- ========= END OF CLASS DATA ========= -->spring中文开发文档
1. 简介
对是否把校验当作业务逻辑这个问题,存在着正和反两种意见,而Spring提供的验证模式(和数据绑定)的设计对这两种意见都不排斥。特别是,校验应该不应该被强制绑定在Web层,而且应该很容易本地化并且可以方便地加入新的验证逻辑。基于上述的考虑,Spring提供了一个Validator接口。这是一个基础的接口并且适用于应用程序的任何一个层面。
数据绑定(Data binding)非常有用,它可以动态把用户输入与应用程序的域模型(或者你用于处理用户输入的对象)绑定起来。Spring针对此提供了所谓的DataBinder来完成这一功能。由Validator和DataBinder组成的validation验证包,主要被用于Spring的MVC框架。当然,他们同样可以被用于其他需要的地方。
BeanWrapper作为一个基础组件被用在了Spring框架中的很多地方。不过,你可能很少会需要直接使用BeanWrapper。由于这是一篇参考文档,因而我们觉得对此稍作解释还是有必要的。我们在这一章节里对BeanWrapper的说明,或许到了你日后试图进行类似对象与数据之间的绑定这种与BeanWrapper非常相关的操作时会有一些帮助。
Spring大量地使用了PropertyEditor(属性编辑器)。PropertyEditor的概念是JavaBean规范的一部分。正如上面提到的BeanWrapper一样,由于它与BeanWrapper以及DataBinder三者之间有着密切的联系,我们在这里同样对PropertyEditor作一番解释。
2. 使用Spring的Validator接口进行校验
你可以使用Spring提供的validator接口进行对象的校验。Validator接口与Errors协同工作,在Spring做校验的时候,它会将所有的校验错误汇总到Errors对象中去。
来看这个简单的数据对象:
public class Person {
private String name;
private int age;
// the usual getters and setters...
}实现org.springframework.validation.Validator接口中的两个方法,我们将为对Person类加上校验行为:
supports(Class):表示这个Validator是否支持该Class的实例?
validate(Object, org.springframework.validation.Errors):对提供的对象进行校验,并将校验的错误注册到传入的Errors 对象中。
实现一个Validator也比较简单,尤其是当你学会了Spring所提供的ValidationUtils以后。我们一起来看一下如何才能创建一个校验器。
public class PersonValidator implements Validator {
/**
* This Validator validates just Person instances
*/
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
}
如你所见,我们使用了ValidationUtils中的一个静态方法rejectIfEmpty(..)来对name属性进行校验,假若'name'属性是 null 或者空字符串的话,就拒绝验证通过 。请参照ValidationUtils相关的JavaDoc,查看一下除了例子中介绍过的之外其他的一些功能。
对复杂对象来说,实现Validator类来验证其内置的属性类当然也是可行的,但是为每个内置类的示例实现Validator可能是个更好的主意。关于这样的一个'rich'这样的例子是Customer类,它包含两个String属性(first name 和second name),还有一个复杂的Address对象。Address对象可能独立于Customer对象,因此独立实现了一个AddressValidator。假若你希望你的CustomerValidator重用AddressValidator内部的逻辑,但是又不想通过拷贝粘贴来实现,你可以在你的CustomerValidator中依赖注入AddressValidator对象,或者创建一个。然后这样用:
public class CustomerValidator implements Validator {
private final Validator addressValidator;
public UserValidator(Validator addressValidator) {
if (addressValidator == null) {
throw new IllegalArgumentException("The supplied [Validator] is required and must not be null.");
}
if (!addressValidator.supports(Address.class)) {
throw new IllegalArgumentException(
"The supplied [Validator] must support the validation of [Address] instances.");
}
this.addressValidator = addressValidator;
}
/**
* This Validator validates Customer instances, and any subclasses of Customer too
*/
public boolean supports(Class clazz) {
return Customer.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
Customer customer = (Customer) target;
try {
errors.pushNestedPath("address");
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
} finally {
errors.popNestedPath();
}
}
}验证错误会被报告到传来的Errors对象中。在Spring Web MVC中,你可以使用<spring:bind/>标签来检查错误信息,当然你也可以自行处理错误。可以在它的Javadoc中找到它提供的方法的描述。
3. 从错误代码到错误信息
我们已经讨论了数据绑定和校验。最后我们来讨论一下与校验错误相对应的错误信息输出。在先前的示例中,我们对name和age字段进行了校验并发现了错误。如果我们想用MessageSource来输出错误信息,当某个字段校验出错时(在这个例子中是name和age)我们输出的是错误代码。无论你直接或者间接使用示例中的ValidationUtils 类来调用Errors接口中rejectValue方法或者任何一个其它的reject方法,底层的实现不仅为你注册了你传入的代码,还同时为你注册了许多额外的错误代码信息。而你使用的MessageCodesResolver将决定究竟注册什么样的错误代码。默认情况下,将会使用DefaultMessageCodesResolver。回到前面的例子,使用DefaultMessageCodesResolver,不仅会为你注册你提供的错误代码信息,同时还包含了你传入到reject方法中的字段信息。所以在这个例子中,你通过rejectValue("age", "too.darn.old")来注册一个字段校验错误。Spring不仅为你注册了too.darn.old这个代码,同时还为你注册了too.darn.old.age和too.darn.old.age.int来分别表示字段名称和字段的类型。这种是现实为了方面开发者来定位错误信息。
更多有关MessageCodesResolver的信息以及默认的策略可以在线访问相应的JavaDocs: MessageCodesResolver 和 DefaultMessageCodesResolver .