Spring Validation 校验 ( 一 )

Spring Validation 是 Spring Framework 的一部分,它提供了一种简单的方式来验证 Java 对象的数据。Spring Validation 基于 JSR 303/JSR 349(也称为 Bean Validation)规范,允许开发者使用注解来定义对象的约束条件,从而简化了验证逻辑的编写。

1.导入依赖

xml 复制代码
    <!-- Spring Boot Starter Web  依赖web环境 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Starter Validation -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>8.0.1.Final</version>
    </dependency>

spring-boot-starter-validationhibernate-validator 在 Spring Boot 中扮演着不同的角色,但它们紧密相关。下面是两者之间的主要区别:

  • spring-boot-starter-validation 提供了 Spring Boot 中 Bean Validation 的自动配置和支持。它还提供了对 Spring MVC 控制器中验证的支持,例如通过 @Valid@Validated 注解来验证请求体和方法参数。
  • hibernate-validator 是一个具体的 Bean Validation 实现,它提供了验证逻辑和标准的验证注解。它提供了所有标准的验证注解(如 @NotNull, @Size, @Pattern 等)的实现。支持创建自定义验证注解和相应的验证器实现。
  • 通常情况下,只需要添加 spring-boot-starter-validation 即可,因为它会自动包含 Hibernate Validator 或其他 Bean Validation 实现。

2.标准注解

2.1.常用注解

  1. @Null : 指定字段必须为 null
  2. @NotNull : 指定字段不得为 null
  3. @NotBlank : 指定字符串必须不为空,且不全是空白字符。
  4. @NotEmpty : 指定字符串、数组、集合、Map 或其他可迭代类型必须不为空。
  5. @AssertFalse : 指定布尔值必须为 false
  6. @AssertTrue : 指定布尔值必须为 true
  7. @Min(value) : 指定数值必须大于等于指定的最小值。
  8. @Max(value) : 指定数值必须小于等于指定的最大值。
  9. @DecimalMin(value) : 指定数值必须大于等于指定的小数值。
  10. @DecimalMax(value) : 指定数值必须小于等于指定的小数值。
  11. @Size(min, max) : 指定字符串、数组、集合、Map 或其他可迭代类型的元素数量必须在指定范围内。
  12. @Digits(integer, fraction) : 指定数值的整数部分和小数部分的最大位数。
  13. @Past : 指定日期必须在过去。
  14. @Future : 指定日期必须在未来。
  15. @PastOrPresent : 指定日期必须在过去或现在。
  16. @FutureOrPresent : 指定日期必须在未来或现在。
  17. @Pattern(regexp) : 指定字符串必须匹配指定的正则表达式。
  18. @Positive : 指定数值必须大于 0。
  19. @PositiveOrZero : 指定数值必须大于等于 0。
  20. @Negative : 指定数值必须小于 0。
  21. @NegativeOrZero : 指定数值必须小于等于 0。
  22. @Email : 指定字符串必须是有效的电子邮件地址。
  23. @URL(protocol, host, port) : 指定字符串必须是有效的 URL。
  24. @CreditCardNumber : 指定字符串必须是有效的信用卡号码。
  25. @Length(min, max) : 指定字符串长度必须在指定范围内。
  26. @Range(min, max) : 指定数值必须在指定范围内。

2.2.使用案例

  1. 定义验证规则。

  2. 使用 @Valid 注解来验证控制器方法的参数。

  3. 处理验证错误。

  4. 实现额外的逻辑,如检查用户名是否唯一。

2.2.1.创建 User 类

定义一个 User 类,使用 Bean Validation 注解来定义验证规则:

java 复制代码
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public class User {

    @NotBlank(message = "用户名不能为空")
    @Size(min = 5, max = 20, message = "用户名长度应在5到20个字符之间")
    private String username;

    @NotBlank(message = "密码不能为空")
    @Size(min = 8, max = 32, message = "密码长度应在8到32个字符之间")
    private String password;

    @Email(message = "邮箱格式不正确")
    private String email;

    // 构造函数、getter 和 setter 省略
}
2.2.2.创建 UserRepository

创建一个简单的 UserServiceImpl ,用于模拟数据库操作:

java 复制代码
import com.yuan.springvalidationdemo.domain.User;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl  {

    public boolean existsByUsername(String username){
        // 模拟数据库查询, 验证用户名是否已存在
        return false;
    }

    public void save(User user) {
        // 模拟保存用户
    }
}
2.2.3.创建 UserController

创建一个 UserController 类,用于处理用户的注册请求,并使用 @Valid 注解来验证传入的用户对象:

java 复制代码
import com.yuan.springvalidationdemo.domain.User;
import com.yuan.springvalidationdemo.service.impl.UserServiceImpl;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserServiceImpl userService;

    @PostMapping("/register")
    public ResponseEntity<String> register(@Valid @RequestBody User user, BindingResult result) {
        if (result.hasErrors()) {
            // 如果有验证错误,则返回错误信息
            StringBuilder errorMessage = new StringBuilder();
            result.getFieldErrors().forEach(error -> {
                errorMessage.append(error.getDefaultMessage()).append("\n");
            });
            return ResponseEntity.badRequest().body(errorMessage.toString());
        }

        // 检查用户名是否唯一
        if (userService.existsByUsername(user.getUsername())) {
            return ResponseEntity.badRequest().body("用户名已存在");
        }

        // 保存用户
        userService.save(user);
        return ResponseEntity.ok("注册成功");
    }
}
2.2.4.测试

运行 Spring Boot 应用程序,并发送 POST 请求到 /register 端点,测试不同的输入情况:

  • 正确的输入:

    • 发送一个包含有效用户名、密码和电子邮件的 JSON 对象。
    • 应该收到响应 "注册成功"。
  • 错误的输入:

    • 发送一个包含无效用户名、密码或电子邮件的 JSON 对象。
    • 应该收到响应,显示验证错误信息。
2.2.5.BindingResult 的作用

BindingResult 是 Spring MVC 中的一个接口,它用于收集和处理模型对象的绑定结果,包括验证错误和其他绑定过程中产生的问题。当你在控制器方法中使用 @Valid@Validated 注解来验证一个对象时,通常会将 BindingResult 作为一个额外的参数传递给该方法。

  1. 收集验证错误 :
    • 当使用 @Valid@Validated 注解时,Spring 会自动调用验证器来验证对象。
    • 如果发现任何验证错误,这些错误会被收集到 BindingResult 对象中。
  2. 访问验证错误 :
    • 你可以通过 BindingResult 对象来获取验证错误的详细信息。
    • 例如,你可以使用 hasErrors(), getFieldErrors(), getGlobalErrors() 等方法来检查是否有验证错误,以及获取特定字段的错误信息。
  3. 处理验证错误 :
    • 一旦你获取到了验证错误,你可以根据需要处理这些错误。
    • 例如,你可以向客户端返回错误信息,或者在前端显示错误消息。

3.@Valid@Validated

@Valid@Validated 是 Spring Validation 中用于触发验证逻辑的注解。它们在不同的上下文中使用,并且有着细微的区别。

3.1.@Valid

  • 位置:

    • @Valid 注解可以放在控制器方法的参数上。
  • 作用:

    • 当一个对象被 @Valid 注解修饰时,Spring 会尝试对该对象进行验证。
    • 如果验证失败,即对象违反了定义的约束条件,那么 Spring 会将验证错误收集到 BindingResult 对象中。
    • 如果验证成功,方法将继续执行。
  • 使用场景:

    • 通常用于单个对象的验证。
    • 在控制器方法中,可以与 BindingResult 参数一起使用来处理验证错误。
java 复制代码
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;

@RestController
public class UserController {

    @PostMapping("/register")
    public String register(@Valid @RequestBody User user, BindingResult result) {
        if (result.hasErrors()) {
            return "注册异常";
        }
        // 用户注册逻辑
        return "注册成功";
    }
}

3.2.@Validated

  • 位置:

    • @Validated 注解可以放在类级别或方法级别。
    • 当放在类级别时,表示该类的所有方法都需要进行验证。
    • 当放在方法级别时,表示该方法需要进行验证。
  • 使用场景:

    • 用于验证控制器类中的方法参数。

    • 通常不需要与 BindingResult 一起使用,因为验证错误通常由控制器类处理。

java 复制代码
import com.yuan.springvalidationdemo.domain.User;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Validated
public class UserController2 {

    @PostMapping("/register2")
    public String register(@Valid @RequestBody User user) {
        // 用户注册逻辑
        return "注册成功";
    }
}

3.3.比较

  • @Valid:

    • 用于单个对象的验证。
    • 通常与 BindingResult 一起使用来处理验证错误。
  • @Validated:

    • 用于验证控制器类中的方法参数。
    • 可以放在类级别或方法级别。
    • 通常不需要与 BindingResult 一起使用,因为验证错误通常由控制器类处理。

注意

  • 如果您只需要验证一个对象,通常使用 @Valid 就足够了。
  • 如果您想要对整个控制器类中的所有方法进行验证,可以使用 @Validated
  • 在实际应用中,@Valid 更常用,因为它提供了更细粒度的控制,并且与 BindingResult 结合使用时可以方便地处理验证错误。
相关推荐
阿龟在奔跑1 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
飞滕人生TYF1 小时前
m个数 生成n个数的所有组合 详解
java·递归
代码小鑫1 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖1 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
激流丶1 小时前
【Kafka 实战】Kafka 如何保证消息的顺序性?
java·后端·kafka
周全全2 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
uzong2 小时前
一个 IDEA 老鸟的 DEBUG 私货之多线程调试
java·后端
AiFlutter2 小时前
Java实现简单的搜索引擎
java·搜索引擎·mybatis
飞升不如收破烂~3 小时前
Spring boot常用注解和作用
java·spring boot·后端
秦老师Q3 小时前
Java基础第九章-Java集合框架(超详细)!!!
java·开发语言