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来获取更多的帮助。

results matching ""

    No results matching ""