SpringBoot使用Bean Validation实现参数校验

 更新时间:2026年07月15日 09:30:58   作者:张老师技术栈  
还在为接口参数校验头疼吗,本文带你快速掌握Bean Validation(JSR303)的常用校验注解,比如@NotNull、@NotBlank、@Email等,还教你如何实现分组校验和自定义校验注解,让校验逻辑和业务代码彻底分离,轻松处理校验异常,需要的朋友可以参考下

参数校验是后端接口的第一道防线。如果让前端传过来的脏数据直接进入业务逻辑,后面排查起来非常麻烦。Bean Validation(JSR 303)提供了一套声明式校验注解,让校验逻辑和业务逻辑分离。

一、为什么需要参数校验

// ❌ 不校验参数,直接用
@PostMapping("/user")
public ResultVO<User> createUser(@RequestBody User user) {
    // 如果 user.name 为空,保存到数据库后会报错
    // 如果 user.age = -1,业务逻辑会出问题
    // 如果 user.email 格式不对,其他地方会解析失败
    return ResultVO.success(userService.save(user));
}
// ✅ 使用注解校验
@PostMapping("/user")
public ResultVO<User> createUser(@RequestBody @Valid User user) {
    return ResultVO.success(userService.save(user));
}

二、常用校验注解

@Data
public class UserCreateDTO {

    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20, message = "用户名长度必须在{min}-{max}之间")
    private String username;

    @NotBlank(message = "密码不能为空")
    @Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*\\d).{6,20}$",
             message = "密码必须包含字母和数字,长度6-20")
    private String password;

    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;

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

    @NotNull(message = "年龄不能为空")
    @Min(value = 0, message = "年龄不能小于0")
    @Max(value = 150, message = "年龄不能大于150")
    private Integer age;

    @NotNull(message = "性别不能为空")
    @Range(min = 0, max = 2, message = "性别值不正确")
    private Integer gender;

    @DecimalMin(value = "0.01", message = "金额不能小于0.01")
    @DecimalMax(value = "999999.99", message = "金额超限")
    private BigDecimal amount;

    @Future(message = "过期时间必须是将来的时间")
    private LocalDateTime expireTime;

    @Size(min = 1, max = 10, message = "角色数量1-10个")
    private List<@NotBlank String> roles;
}

三、分组校验

// 定义分组接口
public interface CreateGroup {}
public interface UpdateGroup {}
@Data
public class UserDTO {

    @Null(groups = CreateGroup.class, message = "新增时ID必须为空")
    @NotNull(groups = UpdateGroup.class, message = "修改时ID不能为空")
    private Long id;

    @NotBlank(groups = CreateGroup.class, message = "用户名不能为空")
    private String username;

    @NotBlank(groups = CreateGroup.class, message = "密码不能为空")
    private String password;

    private String email;
}
@PostMapping
public ResultVO<?> create(@RequestBody @Validated(CreateGroup.class) UserDTO dto) {
    return ResultVO.success(userService.create(dto));
}

@PutMapping("/{id}")
public ResultVO<?> update(@PathVariable Long id,
                           @RequestBody @Validated(UpdateGroup.class) UserDTO dto) {
    dto.setId(id);
    return ResultVO.success(userService.update(dto));
}

四、自定义校验注解

1. 创建注解

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {

    String message() default "手机号格式不正确";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

2. 实现校验器

public class PhoneValidator implements ConstraintValidator<Phone, String> {

    private static final Pattern PHONE_PATTERN =
        Pattern.compile("^1[3-9]\\d{9}$");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null || value.isEmpty()) {
            return true;  // 空值由 @NotBlank 处理
        }
        return PHONE_PATTERN.matcher(value).matches();
    }
}

3. 使用

@Data
public class UserDTO {
    @Phone(message = "手机号格式错误")
    private String phone;
}

五、校验异常处理

@RestControllerAdvice
public class ValidationExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO<?> handleValidation(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldErrors().stream()
            .map(err -> err.getField() + ": " + err.getDefaultMessage())
            .collect(Collectors.joining("; "));
        return ResultVO.error(400, msg);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ResultVO<?> handleConstraint(ConstraintViolationException e) {
        String msg = e.getConstraintViolations().stream()
            .map(v -> v.getPropertyPath() + ": " + v.getMessage())
            .collect(Collectors.joining("; "));
        return ResultVO.error(400, msg);
    }
}

六、常用注解速查

注解作用支持类型
@NotNull值不能为 null所有类型
@NotBlank字符串不能为 null 且不能全空格String
@NotEmpty集合/字符串不能为空String/Collection/Map/数组
@Size长度/大小在指定范围内String/Collection/Map/数组
@Min/@Max数值最小值/最大值数值类型
@Range数值在指定范围内数值类型
@Email邮箱格式String
@Pattern正则表达式匹配String
@Past/@Future过去/将来的时间Date/LocalDate
@DecimalMin/@DecimalMax精确数值范围BigDecimal

以上就是SpringBoot使用Bean Validation实现参数校验的详细内容,更多关于SpringBoot Bean Validation参数校验的资料请关注脚本之家其它相关文章!

相关文章

  • Java中的隐式参数和显示参数实例详解

    Java中的隐式参数和显示参数实例详解

    这篇文章主要介绍了Java中的隐式参数和显示参数是什么,另外还有两个小例子帮助大家理解,需要的朋友可以参考下。
    2017-08-08
  • 关于线程池创建、执行、销毁的原理及分析

    关于线程池创建、执行、销毁的原理及分析

    这篇文章主要介绍了关于线程池创建、执行、销毁的原理及分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • Java中的值传递以及引用传递和数组传递详解

    Java中的值传递以及引用传递和数组传递详解

    这篇文章主要介绍了Java中的值传递以及引用传递和数组传递详解,Java不允许程序员选择按值传递还是按引用传递各个参数,就对象而言,不是将对象本身传递给方法,而是将对象的的引用或者说对象的首地址传递给方法,引用本身是按值传递的,需要的朋友可以参考下
    2023-07-07
  • java多线程Synchronized实现可见性原理解析

    java多线程Synchronized实现可见性原理解析

    这篇文章主要介绍了java多线程Synchronized实现可见性原理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • 通过JDK源码角度分析Long类详解

    通过JDK源码角度分析Long类详解

    这篇文章主要给大家介绍了关于通过JDK源码角度分析Long类的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用long类具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-11-11
  • cookie+mybatis+servlet实现免登录时长两天半的整体流程

    cookie+mybatis+servlet实现免登录时长两天半的整体流程

    这篇文章主要介绍了cookie+mybatis+servlet实现免登录时长两天半,主要用到的技术有session、cookie、转发、重定向、filter、和servlet,最重要的还是具体的来运用它们在前端页面真正的搭建出一个应用,通过这个练习,对我们所学的web知识做一个整合,需要的朋友可以参考下
    2022-10-10
  • SpringBoot定时任务不执行的几个可能原因及解决方法

    SpringBoot定时任务不执行的几个可能原因及解决方法

    这篇文章主要介绍了SpringBoot定时任务不执行的几个可能原因及解决方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-12-12
  • Java线程之间通信的几种方式详解

    Java线程之间通信的几种方式详解

    在 Java 中,线程之间的通信是通过共享内存模型来实现的,线程通过共享的对象和变量来交换数据,为了确保线程间通信的正确性,Java 提供了一系列机制来实现线程安全、同步和通信,以下是常用的几种线程间通信的方式,以及它们的使用方法和场景,需要的朋友可以参考下
    2025-03-03
  • Java实现自动把报表插入到word文档中

    Java实现自动把报表插入到word文档中

    在很多业务场景中需要在 word 文档中嵌入报表,这篇文章主要为大家介绍了如何使用Java实现自动把报表插入到word文档中,需要的可以参考下
    2024-12-12
  • idea在用Mybatis时xml文件sql不提示解决办法(提示后背景颜色去除)

    idea在用Mybatis时xml文件sql不提示解决办法(提示后背景颜色去除)

    mybatis的xml文件配置的时候,有时候会没有提示,这让我们很头疼,下面这篇文章主要给大家介绍了关于idea在用Mybatis时xml文件sql不提示的解决办法,提示后背景颜色去除的相关资料,需要的朋友可以参考下
    2023-03-03

最新评论