5.8 Spring验证

Spring 3对验证支持引入了几个增强功能。首先,现在全面支持JSR-303 Bean Validation API;其次,当采用编程方式时,Spring的DataBinder现在不仅可以绑定对象还能够验证它们;最后,Spring MVC现在已经支持声明式地验证@Controller的输入。

5.8.1 JSR-303 Bean Validation API概述

JSR-303对Java平台的验证约束声明和元数据进行了标准化定义。使用此API,你可以用声明性的验证约束对领域模型的属性进行注解,并在运行时强制执行它们。现在已经有一些内置的约束供你使用,当然你也可以定义你自己的自定义约束。

为了说明这一点,考虑一个拥有两个属性的简单的PersonForm模型:

public class PersonForm {
    private String name;
    private int age;
}

JSR-303允许你针对这些属性定义声明性的验证约束:

public class PersonForm {

    @NotNull
    @Size(max=64)
    private String name;

    @Min(0)
    private int age;

}

当此类的一个实例被实现JSR-303规范的验证器进行校验的时候,这些约束就会被强制执行。

有关JSR-303/JSR-349的一般信息,可以访问网站Bean Validation website去查看。有关默认参考实现的具体功能的信息,可以参考网站Hibernate Validator的文档。想要了解如何将Bean验证器提供程序设置为Spring bean,请继续保持阅读。

5.8.2 配置Bean验证器提供程序

Spring提供了对Bean Validation API的全面支持,这包括将实现JSR-303/JSR-349规范的Bean验证提供程序引导为Spring Bean的方便支持。这样就允许在应用程序任何需要验证的地方注入javax.validation.ValidatorFactory或者javax.validation.Validator

LocalValidatorFactoryBean当作Spring bean来配置成默认的验证器:

<bean id="validator"
    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

以上的基本配置会触发Bean Validation使用它默认的引导机制来进行初始化。作为实现JSR-303/JSR-349规范的提供程序,如Hibernate Validator,可以存在于类路径以使它能被自动检测到。

注入验证器

LocalValidatorFactoryBean实现了javax.validation.ValidatorFactoryjavax.validation.Validator这两个接口,以及Spring的org.springframework.validation.Validator接口,你可以将这些接口当中的任意一个注入到需要调用验证逻辑的Bean里。

如果你喜欢直接使用Bean Validtion API,那么就注入javax.validation.Validator的引用:

import javax.validation.Validator;

@Service
public class MyService {

    @Autowired
    private Validator validator;

如果你的Bean需要Spring Validation API,那么就注入org.springframework.validation.Validator的引用:

import org.springframework.validation.Validator;

@Service
public class MyService {

    @Autowired
    private Validator validator;

}

配置自定义约束

每一个Bean验证约束由两部分组成,第一部分是声明了约束和其可配置属性的@Constraint注解,第二部分是实现约束行为的javax.validation.ConstraintValidator接口实现。为了将声明与实现关联起来,每个@Constraint注解会引用一个相应的验证约束的实现类。在运行期间,ConstraintValidatorFactory会在你的领域模型遇到约束注解的情况下实例化被引用到的实现。

默认情况下,LocalValidatorFactoryBean会配置一个SpringConstraintValidatorFactory,其使用Spring来创建约束验证器实例。这允许你的自定义约束验证器可以像其他Spring bean一样从依赖注入中受益。

下面显示了一个自定义的@Constraint声明的例子,紧跟着是一个关联的ConstraintValidator实现,其使用Spring进行依赖注入:

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

    @Autowired;
    private Foo aDependency;

    ...
}

如你所见,一个约束验证器实现可以像其他Spring bean一样使用@Autowired注解来自动装配它的依赖。

Spring驱动的方法验证

被Bean Validation 1.1以及作为Hibernate Validator 4.3中的自定义扩展所支持的方法验证功能可以通过配置MethodValidationPostProcessor的bean定义集成到Spring的上下文中:

<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>

为了符合Spring驱动的方法验证,需要对所有目标类用Spring的@Validated注解进行注解,且有选择地对其声明验证组,这样才可以使用。请查阅MethodValidationPostProcessor的java文档来了解针对Hibernate Validator和Bean Validation 1.1提供程序的设置细节。

附加配置选项

对于大多数情况,默认的LocalValidatorFactoryBean配置应该足够。有许多配置选项来处理从消息插补到遍历解析的各种Bean验证结构。请查看LocalValidatorFactoryBean的java文档来获取关于这些选项的更多信息。

5.8.3 配置DataBinder

从Spring 3开始,DataBinder的实例可以配置一个验证器。一旦配置完成,那么可以通过调用binder.validate()来调用验证器,任何的验证错误都会自动添加到DataBinder的绑定结果(BindingResult)。

当以编程方式处理DataBinder时,可以在绑定目标对象之后调用验证逻辑:

Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());

// bind to the target object
binder.bind(propertyValues);

// validate the target object
binder.validate();

// get BindingResult that includes any validation errors
BindingResult results = binder.getBindingResult();

通过dataBinder.addValidatorsdataBinder.replaceValidators,一个DataBinder也可以配置多个Validator实例。当需要将全局配置的Bean验证与一个DataBinder实例上局部配置的SpringValidator结合时,这一点是非常有用的。

5.8.4 Spring MVC 3 验证

请查看Spring MVC章节的Section 18.16.4 “Validation”