Hibernate Validator 中文操作指南

1. Getting started

本章将教您如何开始使用 Jakarta Bean 验证的参考实现 (RI) Hibernate 验证器。对于以下快速入门,您需要:

  1. A JDK 8

  2. Apache Maven

  3. Internet 连接(Maven 必须下载所有必需的库)

1.1. Project set up

要在 Maven 项目中使用 Hibernate 验证器,只需将以下依赖项添加到 pom.xml

示例 1.1:Hibernate Validator Maven 依赖项
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.1.Final</version>
</dependency>

这将瞬态提取到 Jakarta Bean 验证 API(jakarta.validation:jakarta.validation-api:3.0.2)的依赖项。

1.1.1. Unified EL

Hibernate Validator 需要一个@“7”的实现来评估约束违反消息中的动态表达式(请参阅@“9”)。当应用程序在 Jakarta EE 容器(例如 WildFly/JBoss EAP)中运行时,容器中已提供了 EL 实现。然而,在 Java SE 环境中,必须在 POM 文件中将实现作为依赖项添加。例如,可以添加以下依赖项以使用 Jakarta EL @“8”:

示例 1.2:Unified EL 参考实现的 Maven 依赖项
<dependency>
    <groupId>org.glassfish.expressly</groupId>
    <artifactId>expressly</artifactId>
    <version>5.0.0</version>
</dependency>

对于无法提供 EL 实现的环境,Hibernate Validator 提供一个 Section 12.10, “ParameterMessageInterpolator 。但是,使用此内插器不符合 Jakarta Bean Validation 规范。

1.1.2. CDI

Jakarta Bean Validation 定义了与 CDI 的集成点 ( Contexts and Dependency Injection for Jakarta EE)。如果你的应用程序在默认情况下不提供此集成的环境中运行,你可以使用 Hibernate Validator CDI 便携扩展,方法是向你的 POM 添加以下 Maven 依赖关系:

示例 1.3:Hibernate Validator CDI 可移植扩展 Maven 依赖项
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-cdi</artifactId>
    <version>8.0.1.Final</version>
</dependency>

请注意,对于在 Jakarta EE 应用服务器上运行的应用程序,通常不需要添加此依赖项。可以在“10”中了解更多关于 Jakarta Bean Validation 和 CDI 的集成情况。

1.1.3. Running with a security manager

Hibernate Validator 支持在启用 security manager 的情况下运行。为此,你必须为以下几个代码库分配多个权限:Hibernate 验证器、Jakarta Bean 验证 API、Classmate 和 JBoss Logging 以及调用 Jakarta Bean 验证的代码库。以下是通过 Java 默认策略实现处理的 policy file 实现此功能的方式:

示例 1.4:与安全管理器一起使用 Hibernate Validator 的策略文件
grant codeBase "file:path/to/hibernate-validator-8.0.1.Final.jar" {
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
    permission java.lang.RuntimePermission "accessDeclaredMembers";
    permission java.lang.RuntimePermission "setContextClassLoader";

    permission org.hibernate.validator.HibernateValidatorPermission "accessPrivateMembers";

    // Only needed when working with XML descriptors (validation.xml or XML constraint mappings)
    permission java.util.PropertyPermission "mapAnyUriToUri", "read";
};

grant codeBase "file:path/to/jakarta.validation-api-3.0.2.jar" {
    permission java.io.FilePermission "path/to/hibernate-validator-8.0.1.Final.jar", "read";
};

grant codeBase "file:path/to/jboss-logging-3.4.3.Final.jar" {
    permission java.util.PropertyPermission "org.jboss.logging.provider", "read";
    permission java.util.PropertyPermission "org.jboss.logging.locale", "read";
};

grant codeBase "file:path/to/classmate-1.5.1.jar" {
    permission java.lang.RuntimePermission "accessDeclaredMembers";
};

grant codeBase "file:path/to/validation-caller-x.y.z.jar" {
    permission org.hibernate.validator.HibernateValidatorPermission "accessPrivateMembers";
};

1.1.4. Updating Hibernate Validator in WildFly

WildFly application server 开箱即用地包含 Hibernate Validator。为了将 Jakarta Bean Validation API 和 Hibernate Validator 的服务器模块更新到最新版本,可以使用 WildFly 的修补机制。

你可以从 SourceForge 或 Maven Central 使用以下依赖项下载补丁文件:

示例 1.5:WildFly 27.0.0.Alpha4 补丁文件的 Maven 依赖项
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-modules</artifactId>
    <version>8.0.1.Final</version>
    <classifier>wildfly-27.0.0.Alpha4-patch</classifier>
    <type>zip</type>
</dependency>

我们还提供了 WildFly 的补丁:

示例 1.6:用于 WildFly 补丁文件的 Maven 依赖
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-modules</artifactId>
    <version>8.0.1.Final</version>
    <classifier>wildfly--patch</classifier>
    <type>zip</type>
</dependency>

下载补丁文件后,可以通过运行以下命令将其应用到 WildFly:

示例 1.7:应用 WildFly 补丁
$JBOSS_HOME/bin/jboss-cli.sh patch apply hibernate-validator-modules-8.0.1.Final-wildfly-27.0.0.Alpha4-patch.zip

如果您想撤消补丁并返回服务器最初附带的 Hibernate Validator 版本,请运行以下命令:

示例 1.8:回滚 WildFly 补丁
$JBOSS_HOME/bin/jboss-cli.sh patch rollback --reset-configuration=true

你可以在 herehere 中详细了解 WildFly 修补基础设施。

1.1.5. Running on Java 11+

对 Java 11 和 Java Platform Module System (JPMS) 的支持目前处于初步阶段。没有提供 JPMS 模块描述符,但 Hibernate Validator 可用作自动模块。

以下是使用 Automatic-Module-Name 头声明的模块名称:

  1. Jakarta Bean Validation API: jakarta.validation

  2. Hibernate Validator core: org.hibernate.validator

  3. Hibernate Validator CDI 扩展: org.hibernate.validator.cdi

  4. Hibernate Validator 测试实用程序: org.hibernate.validator.testutils

  5. Hibernate 验证器注释处理器:org.hibernate.validator.annotationprocessor

这些模块名称是初步名称,并在未来版本中提供实际模块描述符时可能会更改。

1.2. Applying constraints

让我们直接深入了解一个示例,看看如何应用约束。

示例 1.9:用约束进行注释的 Car 类
package org.hibernate.validator.referenceguide.chapter01;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class Car {

    @NotNull
    private String manufacturer;

    @NotNull
    @Size(min = 2, max = 14)
    private String licensePlate;

    @Min(2)
    private int seatCount;

    public Car(String manufacturer, String licencePlate, int seatCount) {
        this.manufacturer = manufacturer;
        this.licensePlate = licencePlate;
        this.seatCount = seatCount;
    }

    //getters and setters ...
}

@NotNull@Size@Min 注释用于声明应应用于 Car 实例字段的约束:

  1. manufacturer 永远不能是 null

  2. licensePlate 永远不能是 null,且长度必须介于 2 到 14 个字符之间

  3. seatCount 必须至少为 2

你可以在 GitHub 上的 Hibernate Validator source repository 中找到本参考指南中所有示例的完整源代码。

1.3. Validating constraints

要验证这些约束,请使用 Validator 实例。让我们看一下 Car 的单元测试:

示例 1.10:展示验证示例的 CarTest 类
package org.hibernate.validator.referenceguide.chapter01;

import java.util.Set;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;

import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class CarTest {

    private static Validator validator;

    @BeforeClass
    public static void setUpValidator() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    @Test
    public void manufacturerIsNull() {
        Car car = new Car( null, "DD-AB-123", 4 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );

        assertEquals( 1, constraintViolations.size() );
        assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );
    }

    @Test
    public void licensePlateTooShort() {
        Car car = new Car( "Morris", "D", 4 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );

        assertEquals( 1, constraintViolations.size() );
        assertEquals(
                "size must be between 2 and 14",
                constraintViolations.iterator().next().getMessage()
        );
    }

    @Test
    public void seatCountTooLow() {
        Car car = new Car( "Morris", "DD-AB-123", 1 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );

        assertEquals( 1, constraintViolations.size() );
        assertEquals(
                "must be greater than or equal to 2",
                constraintViolations.iterator().next().getMessage()
        );
    }

    @Test
    public void carIsValid() {
        Car car = new Car( "Morris", "DD-AB-123", 2 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );

        assertEquals( 0, constraintViolations.size() );
    }
}

setUp() 方法中,Validator 对象是从 ValidatorFactory 中检索的。Validator 实例是线程安全的,并且可以多次重复使用。因此,可以将其安全地存储在静态字段中,并在测试方法中使用它来验证不同的 Car 实例。

validate() 方法返回一组 ConstraintViolation 实例,您可以遍历它们以查看发生的验证错误。前三个测试方法显示了一些预期的约束违反:

  1. @NotNullmanufacturer 的约束在 manufacturerIsNull() 中被违反

  2. @SizelicensePlate 的约束在 licensePlateTooShort() 中被违反

  3. @MinseatCount 的约束在 seatCountTooLow() 中被违反

如果对象验证成功,validate() 将返回一个空集,如 carIsValid() 中所示。

请注意,仅使用了来自 jakarta.validation 包的类。它们由 Bean Validation API 提供。没有直接引用 Hibernate Validator 的任何类,从而生成了可移植代码。

1.4. Where to go next?

这就结束了 Hibernate Validator 和 Jakarta Bean Validation 世界的 5 分钟游览。继续探索代码示例或查看 Chapter 14, Further reading 中引用的其他示例。

要了解更多有关 bean 和属性的验证,只需继续阅读 Chapter 2, Declaring and validating bean constraints 。如果您有兴趣使用 Jakarta Bean Validation 验证方法的前置条件和后置条件,请参阅 Chapter 3, Declaring and validating method constraints 。如果您的应用程序具有特定的验证要求,请查看 Chapter 6, Creating custom constraints