5.2 使用Spring的Validator接口来进行数据校验
Spring 提供了Validator
接口用来进行对象的数据校验。Validator
接口在进行数据校验的时候 会要求传入一个Errors
对象,当有错误产生时会将错误信息放入该Errors
对象。
我们假设有这么一个数据对象:
public class Person {
private String name;
private int age;
// 省略getters和setters...
}
为了给Person
类提供校验行为我们可以通过实现org.springframework.validation.Validator
这个接口的两个方法来实现:
supports(Class)
- 判断该Validator
是否能校验提供的Class
的实例?validate(Object, org.springframework.validation.Errors)
- 校验给定的对象,如果有校验失败信息,将其放入Errors
对象
实现一个校验器是相当简单的,尤其是当你知道spring已经提供了一个ValidationUtils
工具类时。
public class PersonValidator implements Validator {
/**
* 这个校验器*仅仅*只校验Person实例
*/
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'
这个属性当它为null
或空字符串时。 你可以看看ValidationUtils
的javadocs,提前了解下除了例子中展示的功能外还有哪些好用的方法。
当校验一个复杂的对象时,自定义一个校验器类(封装嵌套对象的校验器类)比把校验逻辑分散到各个嵌套对象会更方便管理。 比如:现在有一个Customer
复杂对象,它有两个String
类型的属性(first and second name),以及一个Address
对象; 这个Address
对象和Customer
对象是毫无关系的,它还实现了AddressValidator
这样一个校验器。如果你想在Customer
校验器 类中重用Address
校验器的功能(这种重用不是通过简单的代码拷贝),你可以将Address
校验器的实例通过依赖注入的方式注入到 Customer
校验器中。 像下面所描述的这样:
public class CustomerValidator implements Validator {
private final Validator addressValidator;
public CustomerValidator(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;
}
/**
* 这个校验器校验Customer实例,同时也会校验Customer的子类实例
*/
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/>
标签 来提取校验错误信息,当然你也可以通过自己的方式来提取错误信息,这些方式可以通过阅读javadocs来获取更多的帮助。