ZetCode

Hibernate Validator

最后修改于 2024 年 1 月 27 日

在本文中,我们将展示如何使用 Hibernate validator 验证数据。验证从用户接收的输入以维护数据完整性是应用程序逻辑的重要组成部分。验证已纳入 Java Web 框架中,例如 Stripes、Ninja framework 或 Play framework。

Bean 验证

Bean Validation 是 Java EE 6 平台中引入的验证模型。Bean Validation 模型由约束支持,这些约束以注释的形式放置在 JavaBeans 组件的字段、方法或类上。也可以使用 XML 验证描述符。

Hibernate validator 定义

Hibernate Validator 是 Bean Validation 的参考实现。Hibernate Validator 允许表达和验证应用程序约束。默认的元数据源是注释,可以通过使用 XML 来覆盖和扩展。它不与特定的应用程序层或编程模型绑定,并且可用于服务器和客户端应用程序编程。

Hibernate validator 命令行应用程序

在下面的示例中,我们在一个简单的命令行应用程序中使用 Hibernate Validator。

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>HibernateValidation</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>2.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator-cdi</artifactId>
            <version>5.2.4.Final</version>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.8</version>
            <scope>provided</scope>
        </dependency>        
        
    </dependencies>
    
</project>

Maven pom.xml 包含 Hibernate Validator 和 Lombok 库的依赖项。 Lombok 用于减少一些样板代码。

Car.java
package com.zetcode.bean;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;

@Data
public class Car {
    
    private Long Id;
    
    @NotNull
    @Size(min=4, max=50)
    private String name;
        
    @Min(value = 1000)
    @Max(value = 5000000, message="There is no such expensive car")
    private int price;
    
    public Car() {}
    
    public Car(String name, int price) {
        
        this.name = name;
        this.price = price;
    } 
}

我们有一个 Car bean,我们在其中验证数据。

@Data
public class Car {

Car bean 使用 Lombok 的 @Data 注释进行修饰。 它自动创建 getter 和 setter 方法、equals 方法、toString 方法和 hashCode 方法。

@NotNull
@Size(min=4, max=50)
private String name;

@NotNull 注释表示 name 属性不能为 null@Size 注释设置属性的最小和最大大小。

@Min(value = 1000)
@Max(value = 5000000, message="There is no such expensive car")
private int price;

@Min 约束设置 price 属性的最小值。 message 元素用于创建错误消息。

ClientApp.java
package com.zetcode.client;

import com.zetcode.bean.Car;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

public class ClientApp {

    private static Validator validator;

    public static void main(String[] args) {

        Car car1 = new Car("Volvo", 29000);
        Car car2 = new Car("Skoda", 900);
        Car car3 = new Car(null, 29000);
        Car car4 = new Car("Cit", 21000);
        Car car5 = new Car("Bentley", 8000000);

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
        
        validate(car1);
        validate(car2);
        validate(car3);
        validate(car4);
        validate(car5);        
    }

    public static void validate(Car car) {

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

        for (ConstraintViolation<Car> cv : cvs) {
            System.out.println(cv.getPropertyPath() + ": " + cv.getMessage());
        }        
    }
}

在客户端应用程序中,我们创建五个 car 对象并验证它们。

Car car1 = new Car("Volvo", 29000);
Car car2 = new Car("Skoda", 900);
Car car3 = new Car(null, 29000);
Car car4 = new Car("Cit", 21000);
Car car5 = new Car("Bentley", 8000000);

创建了五个 car 对象。 四辆汽车的值未通过验证过程。 例如,Skoda 汽车的价格太低; 即低于最低 1000 值。

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();

验证工厂与 buildDefaultValidatorFactory 方法一起使用。 从工厂,我们使用 getValidator 方法获取验证器。 建议 缓存验证器工厂,因为创建它的成本很高。

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

使用验证器的 validate 方法验证汽车。

for (ConstraintViolation<Car> cv : cvs) {
    System.out.println(cv.getPropertyPath() + ": " + cv.getMessage());
}

我们打印约束违规的错误消息。

price: must be greater than or equal to 1000
name: may not be null
name: size must be between 4 and 50
price: There is no such expensive car

运行应用程序时,我们收到这些错误消息。

Hibernate validator Web 应用程序

在第二个示例中,我们在 Web 应用程序中利用 Hibernate Validator。 该应用程序部署在 Apache Tomcat 服务器上。 此应用程序的源代码可在作者的 Github 存储库中找到。

Project structure
图:项目结构

该图显示了 NetBeans 中的项目结构。

context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/HibernateValidation"/>

context.xml 文件包含应用程序的上下文路径。

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>HibernateValidation2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>HibernateValidation2</name>

 
    <dependencies>

        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>2.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator-cdi</artifactId>
            <version>5.2.4.Final</version>
        </dependency>        
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.8</version>
            <scope>provided</scope>
        </dependency>           
                        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>

                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Maven pom.xml 包含 Java EE Web API、Hibernate Validator 和 Lombok 库的依赖项。

index.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Validation</title>
    </head>
    <body>

        <p>
            Enter your name and email:
        </p>

        <form method="post" action="Greet">

            Name: <input type="text" name="username"> <br>
            Email: <input type="text" name="email"> <br>

            <input type="submit" value="Submit"> 

        </form>


    </body>
</html>

index.jsp 是我们应用程序的入口点。 它包含一个带有两个字段的 HTML 表单:用户名和电子邮件。 输入到这些字段中的值将由应用程序验证。

<form method="post" action="Greet">
...
</form>

提交表单后,将调用 Greet servlet。

hello.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Greeting</title>
    </head>
    <body>
        Hello <c:out value="${param.username}"/>! <br>
        Your email is <c:out value="${param.email}"/>.
    </body>
</html>

当输入数据通过验证测试时,将显示 hello.jsp 页面。 它显示输入的数据。

valError.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Error</title>
    </head>
    <body>
        <p>
            <c:forEach var="err" items="${errMsg}">
                <c:out value="${err}"/>
                <br>
            </c:forEach>
        </p>
    </body>
</html>

如果验证失败,将显示 valError.jsp。 它显示存储在 errMsg 属性中的错误消息。 该属性在验证过程中设置。

User.java
package com.zetcode.bean;

import javax.validation.constraints.Pattern;
import lombok.Data;
import org.hibernate.validator.constraints.NotEmpty;

@Data
public class User {
    
    @NotEmpty
    private String name;
    
    @NotEmpty
    @Pattern(regexp="^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\\.[a-zA-Z.]{2,5}", 
            message="Please provide a valid email address")    
    private String email;
}

User bean 使用 Lombok 和 Hibernate Validator 注释进行修饰。

@NotEmpty
private String name;

@NotEmpty 注释导致用户名不能为空。

@NotEmpty
@Pattern(regexp="^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\\.[a-zA-Z.]{2,5}", 
        message="Please provide a valid email address")    
private String email;

电子邮件不能为空,并且必须与给定的模式匹配。 该模式使用 @Pattern 注释设置。

DoValidate.java
package com.zetcode.util;

import com.zetcode.bean.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

public class DoValidate {

    public static  List<String> validate(User user) {

        List<String> errors = new ArrayList();
        
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        Set<ConstraintViolation<User>> cvs = validator.validate(user);

        if (!cvs.isEmpty()) {

            for (ConstraintViolation<User> cv : cvs) {

                StringBuilder err = new StringBuilder();
                err.append(cv.getPropertyPath());
                err.append(" ");
                err.append(cv.getMessage());
                errors.add(err.toString());
            }
        }
        
        return errors;
    }
}

验证在 DoValidate 实用程序类中执行。

if (!cvs.isEmpty()) {

    for (ConstraintViolation<User> cv : cvs) {

        StringBuilder err = new StringBuilder();
        err.append(cv.getPropertyPath());
        err.append(" ");
        err.append(cv.getMessage());
        errors.add(err.toString());
    }
}

当存在约束违规时,我们创建一个错误消息列表。 getMessage 方法获取约束违规的错误消息。

return errors;

错误消息列表返回给调用者。 如果未检测到违规,则该列表为空。

Greeting.java
package com.zetcode.web;

import com.zetcode.bean.User;
import com.zetcode.util.DoValidate;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Greeting", urlPatterns = {"/Greet"})
public class Greeting extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, 
            HttpServletResponse response) 
            throws ServletException, IOException {
        
        response.setContentType("text/html;charset=UTF-8");

        String page = "/hello.jsp";
        
        String username = request.getParameter("username");
        String email = request.getParameter("email");

        User user = new User();
        user.setName(username);
        user.setEmail(email);

        List<String> errors = DoValidate.validate(user);

        if (!errors.isEmpty()) {

            request.setAttribute("errMsg", errors);

            page = "/valError.jsp";

        } else {

            request.setAttribute("user", user);
        }

        RequestDispatcher disp = getServletContext().getRequestDispatcher(page);
        disp.forward(request, response);
    }
}

Greeting servlet 检索请求数据并调用 DoValidate.validate 实用程序方法。 根据验证的结果,servlet 将调度到 hello.jspvalError.jsp 页面。

Error message
图:错误消息

如果电子邮件格式不正确,应用程序将响应错误消息。

来源

Hibernate Validator 文档

这是验证过滤器教程。 我们使用 Hibernate Validator、JSTL、JSP、Apache Tomcat 和 Maven 构建了一个控制台和 Web 应用程序。

作者

我叫 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有Java教程