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

相关推荐
無限進步D1 小时前
Java 运行原理
java·开发语言·入门
難釋懷1 小时前
安装Canal
java
是苏浙1 小时前
JDK17新增特性
java·开发语言
不光头强1 小时前
spring cloud知识总结
后端·spring·spring cloud
GetcharZp4 小时前
告别 Python 依赖!用 LangChainGo 打造高性能大模型应用,Go 程序员必看!
后端
阿里加多4 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
likerhood5 小时前
java中`==`和`.equals()`区别
java·开发语言·python
小小李程序员5 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai