SpringBoot 为我们提供了很方便的接口校验框架:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

使用前先在 Controller 类上配置 @Validated:

@Slf4j
@Validated   //首先在Controller上开启接口校验
@Controller
public class TestController {
 
    ...
 
    @ResponseBody
    @PostMapping("/submit")
    public String submit(@Length(min = 3) String username,  //使用@Length注解一步到位
                         @Length(min = 10) String password){
        System.out.println(username.substring(3));
        System.out.println(password.substring(2, 10));
        return "请求成功!";
    }
}

这样就可以方便的替代手动if判断,不过依然会爆出异常,想要处理的话需要使用自定义异常处理器,或者用下文的传参然后判断。

接口校验规则

验证注解验证的数据类型说明
@AssertFalseBoolean,boolean值必须是false
@AssertTrueBoolean,boolean值必须是true
@NotNull任意类型值不能是null
@Null任意类型值必须是null
@MinBigDecimal、BigInteger、byte、short、int、long、double 以及任何Number或CharSequence子类型大于等于@Min指定的值
@Max同上小于等于@Max指定的值
@DecimalMin同上大于等于@DecimalMin指定的值(超高精度)
@DecimalMax同上小于等于@DecimalMax指定的值(超高精度)
@Digits同上限制整数位数和小数位数上限
@Size字符串、Collection、Map、数组等长度在指定区间之内,如字符串长度、集合大小等
@Past如 java.util.Date, java.util.Calendar 等日期类型值必须比当前时间早
@Future同上值必须比当前时间晚
@NotBlankCharSequence及其子类值不为空,在比较时会去除字符串的首位空格
@LengthCharSequence及其子类字符串长度在指定区间内
@NotEmptyCharSequence及其子类、Collection、Map、数组值不为null且长度不为空(字符串长度不为0,集合大小不为0)
@RangeBigDecimal、BigInteger、CharSequence、byte、short、int、long 以及原子类型和包装类型值在指定区间内
@EmailCharSequence及其子类值必须是邮件格式
@PatternCharSequence及其子类值需要与指定的正则表达式匹配
@Valid任何非原子类型用于验证对象属性

对象校验

@Data
public class Account {
    String username;
    String password;
}
@ResponseBody
@PostMapping("/submit")
public String submit(Account account){   //直接使用对象接收
    System.out.println(account.getUsername().substring(3));
    System.out.println(account.getPassword().substring(2, 10));
    return "请求成功!";
}

此时接口是以对象形式接收前端发送的表单数据的,这个时候就没办法向上面一样编写对应的校验规则了,那么现在又该怎么做呢?

对应对象类型,我们也可以进行验证,方法如下:

@ResponseBody
@PostMapping("/submit")  //在参数上添加@Valid注解表示需要验证
public String submit(@Valid Account account){
    System.out.println(account.getUsername().substring(3));
    System.out.println(account.getPassword().substring(2, 10));
    return "请求成功!";
}
@Data
public class Account {
    @Length(min = 3)   //只需要在对应的字段上添加校验的注解即可
    String username;
    @Length(min = 10)
    String password;
}

校验错误获取

针对每个字段的校验注解添加完成后,还需要在 controller 层进行捕获,并将错误信息返回。编辑 TestController 类,代码如下:

@RestController
@Slf4j
public class TestController {
 
    @PostMapping("/test")
    @ApiOperationLog(description = "测试接口")
        public ResponseEntity<String> test(@RequestBody @Validated User user, BindingResult bindingResult) {
        // 是否存在校验错误
        if (bindingResult.hasErrors()) {
            // 获取校验不通过字段的提示信息
            String errorMsg = bindingResult.getFieldErrors()
                    .stream()
                    .map(FieldError::getDefaultMessage)
                    .collect(Collectors.joining(", "));
 
            return ResponseEntity.badRequest().body(errorMsg);
        }
 
        // 返参
        return ResponseEntity.ok("参数没有任何问题");
    }
 
}

也可以使用接口返参工具类响应参数工具类

自定义校验规则

例如校验手机号是否提交了非数字、或者数字不满 11 位。

SpringValidation 自定义需要创建一个 Validator 设计校验逻辑,再创建一个注解用于指定报错提示并指定应用位置:

  • PhoneNumberValidator
/**  
 * @author Edwin  
 * @date 2/23/2025 10:39 AM  
 * @description: 手机号校验规则  
 */  
  
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {  
    @Override  
    public void initialize(PhoneNumber constraintAnnotation) {  
  
    }  
  
    @Override  
    public boolean isValid(String phoneNumber, ConstraintValidatorContext constraintValidatorContext) {  
        // 校验逻辑  
        // 是否未满11位  
        return phoneNumber != null && phoneNumber.matches("\\d{11}");  
    }  
}
  • PhoneNumber 注解:
/**  
 * @author Edwin  
 * @date 2/23/2025 10:38 AM  
 * @description: 自定义手机号校验注解  
 */  
  
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Constraint(validatedBy = PhoneNumberValidator.class)  
public @interface PhoneNumber {  
    String message() default "手机号格式不正确,需为 11 位数字";  
    Class<?>[] groups() default {};  
    Class<? extends Payload>[] payload() default {};  
}