java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot Bean Validation参数校验

SpringBoot使用Bean Validation实现参数校验

作者:张老师技术栈

还在为接口参数校验头疼吗,本文带你快速掌握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参数校验的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文