SpringMVC 参数校验实现方案¶
一、JSR-303 / JSR-380¶
Java 官方校验规范:
- JSR-303(Bean Validation 1.0):
@NotNull、@Size、@Min、@Max。 - JSR-380(Bean Validation 2.0):加
@Email、@NotBlank、@Positive、@NegativeOrZero。
Hibernate Validator 是参考实现,Spring Boot 自带 starter。
二、常用注解¶
| 注解 | 作用 |
|---|---|
@NotNull |
不能为 null("" 可以) |
@NotBlank |
字符串不能为 null 且 trim 后非空 |
@NotEmpty |
不能为 null 且 size > 0(字符串、集合) |
@Size(min, max) |
长度范围 |
@Min / @Max |
数值范围 |
@Email |
邮箱格式 |
@Pattern(regexp) |
正则 |
@Positive / @PositiveOrZero |
正数 |
@Past / @Future |
过去 / 未来日期 |
三、Controller 用法¶
1. 表单 / Query 参数¶
@PostMapping("/user")
public String create(@Validated @RequestBody UserDTO dto,
BindingResult result) {
if (result.hasErrors()) {
return result.getFieldError().getDefaultMessage();
}
userService.create(dto);
return "ok";
}
DTO:
public class UserDTO {
@NotBlank(message = "姓名不能为空")
@Size(max = 20, message = "姓名最长 20")
private String name;
@NotNull(message = "年龄不能为空")
@Min(value = 0, message = "年龄不能为负")
private Integer age;
@Email(message = "邮箱格式不正确")
private String email;
}
BindingResult 必须紧跟在 @Valid 对象后面
否则 Spring 直接抛 MethodArgumentNotValidException,不会进入你的方法。
2. 路径参数 / Query 参数¶
类上要加 @Validated。
四、全局异常处理¶
不手动写 if (result.hasErrors()),统一由 @RestControllerAdvice 处理:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleValid(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(400, msg);
}
@ExceptionHandler(BindException.class)
public Result handleBind(BindException e) { ... }
@ExceptionHandler(ConstraintViolationException.class)
public Result handleConstraint(ConstraintViolationException e) { ... }
}
五、分组校验¶
不同场景校验规则不同:
public interface Create {}
public interface Update {}
public class UserDTO {
@NotNull(groups = Update.class)
private Long id;
@NotBlank(groups = {Create.class, Update.class})
private String name;
}
@PostMapping("/user")
public String create(@Validated(Create.class) @RequestBody UserDTO dto) { ... }
六、自定义校验注解¶
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
String message() default "身份证号格式错误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class IdCardValidator
implements ConstraintValidator<IdCard, String> {
public boolean isValid(String value, ConstraintValidatorContext ctx) {
return value != null && value.matches("^\\d{17}[\\dXx]$");
}
}
高频追问
@Validated和@Valid:前者是 Spring 提供,支持分组;后者是 JSR 标准,不支持分组。@RequestBody校验失败抛MethodArgumentNotValidException;表单对象校验失败抛BindException;方法参数级校验失败抛ConstraintViolationException。