Java Validate 参数验证

前言

讲到 Validate API 你应该不陌生,尤其是在 web 应用中,作为前后端接口的参数校验,通过注解可以非常方便的校验参数的类型、长度、参数值等。

你是否还在对 Java Bean Validation 与 Hibernate validate,@Valid 与 @Validated 概念模糊?本文带你一同理清这些概念以及最基本的使用方式。

Java Bean Validation

Java Bean Validation(JSR 380)是一个标准的Java规范,用于对Java Bean进行验证。

这个规范定义了一组注解和一些API,可以用来对Java Bean的属性进行约束定义和验证。

注意:JSR 380 只是定义了标准,如果要使用还需要找到相关实现该标准的组件。

目前使用比较多的实现 Hibernate Validator,当然也有其他的实现,如Apache BVal。

使用案例:

1、引用包:

xml 复制代码
<dependencies>
    <!-- javax validation-api -->
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>

    <!-- hibernate validator -->
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.17.Final</version>
    </dependency>
</dependencies>

当然,大部分场景不需要你手动添加,当你引用 spring-boot-starter-web 包之后,默认就已经引入了,如:

2、定义字段约束:

java 复制代码
import javax.validation.constraints.*;

public class User {

    @NotNull(message = "Name cannot be null")
    private String name;

    @Min(value = 18, message = "Age should not be less than 18")
    @Max(value = 150, message = "Age should not be greater than 150")
    private int age;

    @Email(message = "Email should be valid")
    private String email;

    // getters and setters...
}

3、验证:

java 复制代码
import javax.validation.*;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        User user = new User();
        user.setName(null);
        user.setAge(17);
        user.setEmail("invalid");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        for (ConstraintViolation<User> violation : violations) {
            System.out.println(violation.getMessage());
        }
    }
}

当有字段属性不满足字段约束时,通过 validator.validate(user) 方法验证时会检测出来,即 violations 结果集不为空,则说明存在字段不满足约束条件。

还需要自己定义 Validator 验证器,并且手动调用 validate 方法进行验证,看起来显得很麻烦?

手动使用的常见也比较多,比如内部参数验证excel上传数据时参数验证等。

当然,对于 web 接口,在 Spring 环境下,我们也可以通过注解的方式,让接口参数能够自动触发约束校验,我们继续看下文~

@Valid

@Valid 是来自 Java Bean Validation 的标准注解,可以用于触发对方法参数(如Controller方法参数)的验证。

它可以用在任何需要验证的对象上,包括嵌套的对象和集合。但是,它不能用于分组验证。

在 Spring 场景下,这也是最常使用的方式之一,在接口验证的参数前加上 @Valid 注解即可生效:

基本使用

还是使用上文定义的 User 实体类(对字段进行了约束定义),我们继续定义接口使用:

java 复制代码
import javax.validation.Valid;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public String createUser(@Valid @RequestBody User user) {
        // 创建用户...
        return "success";
    }
}

加上 @Valid 注解后,Spring 会自动使用 java validate 实现类的校验能力,即:基于字段上的约束条件进行校验。

如果 User 对象违反了任何约束,Spring 将抛出一个 MethodArgumentNotValidException 异常。

你也可以定义全局的异常处理,使用@ExceptionHandler 注解来处理这个特殊异常,并向客户端返回一个有用的错误消息。

小知识:Spring处理 @Valid 注解的基本步骤:

  1. 数据绑定:当一个HTTP请求到达一个Spring MVC控制器方法时,Spring首先尝试将请求参数绑定到方法参数。

  2. 验证:如果方法参数上有@Valid注解,Spring将触发对这个参数的验证。验证通过Java Bean Validation API的实现进行。

  3. 处理验证结果:如果有任何验证错误,Spring将抛出一个MethodArgumentNotValidException。

@Validated

@Validated 是 Spring 的特有注解,就常见的使用能力上看,和 @Valid 差别不大,不过,它提供了一种分组验证的功能,这是 @Valid 注解所不具备的。

@Validated 可以用在类型、方法和方法参数上。当用在方法参数上时,@Validated 和 @Valid 的功能是一样的。

我们看一个简单的例子:

java 复制代码
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public String createUser(@Validated @RequestBody User user) {
        // 创建用户...
        return "success";
    }
}

这种方式和使用 @Valid 没啥区别。

再看一个分组验证的例子:

java 复制代码
import javax.validation.groups.Default;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    public interface NewUserGroup {}

    @PostMapping
    public String createUser(@Validated(NewUserGroup.class) @RequestBody User user) {
        // 创建用户...
        return "success";
    }
}

public class User {

    @NotNull(groups = {Default.class, NewUserGroup.class})
    private String name;

    // getters and setters...
}

在这个例子中,NewUserGroup 是一个空接口,用作分组验证的标记。createUser 方法接受一个 User 对象作为参数,并指定只验证 NewUserGroup 组。

User 类的 name 属性上的 @NotNull 注解指定了它应该在 Default 组和 NewUserGroup 组中进行验证。因此,当调用 createUser 方法时,Spring 将验证 name 属性是否不为 null。

小知识:Spring 处理 @Validated 注解的基本步骤:

  1. 数据绑定:当一个 HTTP 请求到达一个 Spring MVC 控制器方法时,Spring 首先尝试将请求参数绑定到方法参数。

  2. 验证 :如果方法参数上有 @Validated 注解,Spring 将触发对这个参数的验证,验证通过 Java Bean Validation API 的实现进行。如果 @Validated 注解指定了一个或多个组,Spring 将只验证那些指定了相同组的约束。

  3. 处理验证结果:如果有任何验证错误,Spring将抛出一个MethodArgumentNotValidException

可以发现,和 @Valid 注解的处理流程上基本一致,只是多了分组的校验。

相关推荐
王桑.1 分钟前
WebSocket---一种用于实时传输的网络协议
java·websocket·spring·java-ee
帝吃藕和2 分钟前
类加载和对象创建的执行顺序+例子
java·java笔试
骑着bug的coder2 分钟前
第3讲:增删改查实战——搞定80%日常需求
后端·mysql
CoderYanger6 分钟前
递归、搜索与回溯-综合练习:28.不同路径Ⅲ
java·算法·leetcode·深度优先·1024程序员节
鱼丸花生7 分钟前
Java 数组详解
java
ldwqh07 分钟前
Spring data jpa 系列指南笔记 (二) 实体继承
后端
用户84913717547167 分钟前
Tomcat 为什么要“造反”?深度解析 Java 类加载机制的“守”与“破”
java·jvm
用户3458482850512 分钟前
java中的tomicInteger/AtomicLong介绍
前端·后端
jiayong2313 分钟前
Elasticsearch Java 开发完全指南
java·大数据·elasticsearch
技术不打烊14 分钟前
3步吃透 Go 标准库 HTTP/TLS,让你的 Web 服务器直接起飞
后端