# 3.7. Java Bean 验证

Spring Framework 提供对 [Java Bean Validation](https://beanvalidation.org/) API 的支持。

**3.7.1. Bean 验证概述**

Bean Validation 通过约束声明和 Java 应用程序的元数据提供了一种通用的验证方式。要使用它，您可以使用声明性验证约束来注解域模型属性，然后由运行时强制执行。有内置约束，您也可以定义自己的自定义约束。

考虑以下示例，该示例显示了一个`PersonForm`具有两个属性的简单模型：

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

Bean Validation 允许您声明约束，如以下示例所示：

```java
public class PersonForm {

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

    @Min(0)
    private int age;
}
```

一个 Bean Validation 验证器然后根据声明的约束来验证这个类的实例。有关 API 的一般信息，请参阅[Bean 验证](https://beanvalidation.org/)。有关特定约束，请参阅[Hibernate Validator](https://hibernate.org/validator/)文档。要了解如何将 bean 验证提供程序设置为 Spring bean，请继续阅读。

**3.7.2. 配置 Bean 验证提供程序**

Spring 为 Bean Validation API 提供全面支持，包括将 Bean Validation 提供者引导为 Spring bean。这使您可以在应用程序中任何需要验证的位置注入一个 `javax.validation.ValidatorFactory`或`javax.validation.Validator`。

您可以使用 `LocalValidatorFactoryBean`将默认验证器配置为 Spring bean，如以下示例所示：

```java
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class AppConfig {

    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }
}
```

前面示例中的基本配置触发 bean 验证以使用其默认引导机制进行初始化。Bean Validation 提供程序，例如 Hibernate Validator，预计会出现在类路径中并且会被自动检测到。

**注入验证器**

`LocalValidatorFactoryBean`实现`javax.validation.ValidatorFactory`和`javax.validation.Validator`以及 Spring 的`org.springframework.validation.Validator`. 您可以将对这些接口中的任何一个的引用注入到需要调用验证逻辑的 bean 中。

如果您更喜欢直接使用 Bean Validation API，您可以注入一个引用`javax.validation.Validator`，如以下示例所示：

```java
import javax.validation.Validator;

@Service
public class MyService {

    @Autowired
    private Validator validator;
}
```

如果您的 bean 需要 Spring Validation API，您可以注入一个引用`org.springframework.validation.Validator`，如以下示例所示：

```java
import org.springframework.validation.Validator;

@Service
public class MyService {

    @Autowired
    private Validator validator;
}
```

**配置自定义约束**

每个 bean 验证约束由两部分组成：

* `@Constraint`声明约束及其可配置属性的注解。
* `javax.validation.ConstraintValidator`实现约束行为的接口的实现。

要将声明与实现相关联，每个`@Constraint`注解都引用相应的`ConstraintValidator`实现类。在运行时， `ConstraintValidatorFactory`当在域模型中遇到约束注解时，实例化引用的实现。

默认情况下，`LocalValidatorFactoryBean` 配置一个 `SpringConstraintValidatorFactory`，它使用 Spring 创建`ConstraintValidator` 实例。这可以让您的自定义`ConstraintValidators`像任何其他 Spring bean 一样从依赖注入中受益。

以下示例显示了一个自定义`@Constraint`声明，后跟一个使用 Spring 进行依赖注入的关联 `ConstraintValidator`实现：

```java
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
```

```java
import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

    @Autowired;
    private Foo aDependency;

    // ...
}
```

如前面的示例所示，`ConstraintValidator` 实现可以像任何其他 `Spring bean` 一样具有其依赖项 `@Autowired`。

**spring驱动的方法验证**

您可以通过 `MethodValidationPostProcessor` bean 定义将 Bean Validation 1.1（以及作为自定义扩展，也由 Hibernate Validator 4.3）支持的方法验证功能集成到 Spring 上下文中：

```java
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@Configuration
public class AppConfig {

    @Bean
    public MethodValidationPostProcessor validationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}
```

为了符合 Spring 驱动的方法验证的条件，所有目标类都需要使用 Spring 的`@Validated`注解进行注解，它还可以选择声明要使用的验证组。请参阅 [`MethodValidationPostProcessor`](https://docs.spring.io/spring-framework/docs/5.3.22/javadoc-api/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.html) Hibernate Validator 和 Bean Validation 1.1 提供程序的设置详细信息。

方法验证依赖于目标类周围的[AOP 代理，要么是接口上方法的 JDK 动态代理，要么是 CGLIB 代理。](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-introduction-proxies)使用代理有某些限制，其中一些在 [了解 AOP 代理](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-understanding-aop-proxies)中进行了描述。此外，请记住始终在代理类上使用方法和访问器；直接字段访问将不起作用。

**其他配置选项**

对于大多数情况，`LocalValidatorFactoryBean`默认配置就足够了。从消息插值到遍历解析，各种 Bean Validation 构造都有许多配置选项。有关这些选项的更多信息，请参阅 [`LocalValidatorFactoryBean`](https://docs.spring.io/spring-framework/docs/5.3.22/javadoc-api/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.html) javadoc。

**3.7.3. 配置`DataBinder`**

从 Spring 3 开始，您可以使用 `Validator` 配置 `DataBinder` 实例. 配置完成后，您可以通过调用`binder.validate()`来调用`Validator`. 任何验证 `Errors`都会自动添加到活页夹的`BindingResult`.

以下示例显示了如何在绑定到目标对象后以`DataBinder`编程方式调用验证逻辑：

```java
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.addValidators` 和 `dataBinder.replaceValidators` 配置具有多个 `Validator` 实例的 `DataBinder`。当将全局配置的 bean 验证与 `DataBinder` 实例上本地配置的 `Spring Validator` 相结合时，这非常有用。请参阅 Spring MVC 验证配置。

**3.7.4. Spring MVC 3 验证**

请参阅Spring MVC 章节中的[验证](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-config-validation)。
