5.2 使用Spring的验证器接口进行验证

Spring具有一个Validator接口可以让你用于验证对象。Validator接口在工作时需要使用一个Errors对象,以便于在验证过程中,验证器可以将验证失败的信息报告给这个Errors对象。

让我们考虑一个小的数据对象:

public class Person {

    private String name;
    private int age;

    // the usual getters and setters...
}

通过实现org.springframework.validation.Validator的下列两个接口,我们打算为Person类提供验证行为:

  • support(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(..)被用于拒绝那些值为null或者空字符串的'name'属性。除了上面展示的例子之外,去看一看ValidationUtils的java文档有助于了解它提供的功能。

通过实现单个的Validator类来逐个验证富对象中的嵌套对象当然是有可能的,然而将验证逻辑封装在每个嵌套类对象自身的Validator实现中可能是一种更好的选择。Customer就是一个‘富’对象的简单示例,它由两个字符串属性(姓和名)以及一个复杂对象Address组成。Address对象可能独立于Customer对象使用,因此已经实现了一个独特的AddressValidator。如果你想要你的CustomerValidator不借助于复制粘贴而重用包含在AddressValidator中的逻辑,那么你可以通过依赖注入或者实例化你的CustomerValidator中的AddressValidator,然后像这样使用它:

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;
    }

    /**
     * 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/>标签来检查错误信息,不过当然你也可以自己检查错误对象。有关它提供的方法的更多信息可以在java文档中找到。