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判断,不过依然会爆出异常,想要处理的话需要使用自定义异常处理器,或者用下文的传参然后判断。
接口校验规则
验证注解 | 验证的数据类型 | 说明 |
---|---|---|
@AssertFalse | Boolean,boolean | 值必须是false |
@AssertTrue | Boolean,boolean | 值必须是true |
@NotNull | 任意类型 | 值不能是null |
@Null | 任意类型 | 值必须是null |
@Min | BigDecimal、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 | 同上 | 值必须比当前时间晚 |
@NotBlank | CharSequence及其子类 | 值不为空,在比较时会去除字符串的首位空格 |
@Length | CharSequence及其子类 | 字符串长度在指定区间内 |
@NotEmpty | CharSequence及其子类、Collection、Map、数组 | 值不为null且长度不为空(字符串长度不为0,集合大小不为0) |
@Range | BigDecimal、BigInteger、CharSequence、byte、short、int、long 以及原子类型和包装类型 | 值在指定区间内 |
CharSequence及其子类 | 值必须是邮件格式 | |
@Pattern | CharSequence及其子类 | 值需要与指定的正则表达式匹配 |
@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 {};
}