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 注解的处理流程上基本一致,只是多了分组的校验。

相关推荐
用户83562907805115 分钟前
C# 从 PDF 提取图片教程
后端·c#
L2ncE40 分钟前
高并发场景数据与一致性的简单思考
java·后端·架构
武昌库里写JAVA40 分钟前
使用 Java 开发 Android 应用:Kotlin 与 Java 的混合编程
java·vue.js·spring boot·sql·学习
小指纹41 分钟前
河南萌新联赛2025第(六)场:郑州大学
java·开发语言·数据结构·c++·算法
叶~璃44 分钟前
云计算:企业数字化转型的核心引擎
java
码luffyliu1 小时前
MySQL:MVCC机制及其在Java秋招中的高频考点
java·数据库·mysql·事务·并发·mvcc
程序员鱼皮1 小时前
这套 Java 监控系统太香了!我连夜给项目加上了
java·前端·ai·程序员·开发·软件开发
水涵幽树1 小时前
MySQL 时间筛选避坑指南:为什么格式化字符串比较会出错?
数据库·后端·sql·mysql·database
岁忧1 小时前
(nice!!!)(LeetCode 每日一题) 1277. 统计全为 1 的正方形子矩阵 (动态规划)
java·c++·算法·leetcode·矩阵·go·动态规划
ERP老兵_冷溪虎山1 小时前
从ASCII到Unicode:"国际正则"|"表达式"跨国界实战指南(附四大语言支持对比+中医HIS类比映射表)
后端·面试