前言
在 Java Web 开发中,输入校验是一项至关重要的任务。为了保证接口的健壮性与数据安全性,Spring 提供了两类常用注解:@Validated
(Spring 提供)与 @Valid
(Java Bean Validation 规范提供),帮助我们在方法参数级别实现优雅、自动化的校验机制。
一、什么是 @Valid
与 @Validated
注解 | 提供者 | 作用范围 | 特点 |
---|---|---|---|
@Valid | Javax(JSR-303) | Bean、方法参数等 | 不支持分组校验 |
@Validated | Spring Framework | 类、方法参数 | 支持分组校验(Group Validation) |
两者可以搭配使用,但在分组校验场景中需使用 @Validated
才能生效。
二、常见校验注解(基于 javax.validation.constraints
)
注解 | 说明 |
---|---|
@NotNull | 值不能为 null |
@NotBlank | 字符串不能为空(去空格) |
@NotEmpty | 集合/数组/字符串非空 |
@Size | 长度范围限制 |
@Min / @Max | 数值最小/最大值限制 |
@Pattern | 正则表达式匹配 |
@Email | 校验邮箱格式 |
@Future / @Past | 时间必须在未来或过去 |
三、结合 Spring 使用:方法参数校验
示例 1:简单参数对象校验
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping("/create")
public String createUser(@Valid @RequestBody UserDTO userDTO) {
return "创建成功";
}
}
@Data
public class UserDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 18, message = "年龄不能小于18岁")
private int age;
}
⚠️ 如果不加
@Valid
或@Validated
,这些注解将不会生效。
示例 2:集合对象校验
@PostMapping("/batch")
public String createUsers(@Valid @RequestBody List<@Valid UserDTO> users) {
return "批量创建成功";
}
四、分组校验(必须使用 @Validated
)
Step 1:定义校验分组接口
public interface CreateGroup {}
public interface UpdateGroup {}
Step 2:在字段上指定分组
@Data
public class ProductDTO {
@NotNull(message = "ID不能为空", groups = UpdateGroup.class)
private Long id;
@NotBlank(message = "产品名不能为空", groups = {CreateGroup.class, UpdateGroup.class})
private String name;
}
Step 3:使用 @Validated
指定分组
@PostMapping("/create")
public String create(@RequestBody @Validated(CreateGroup.class) ProductDTO dto) {
return "创建成功";
}
@PostMapping("/update")
public String update(@RequestBody @Validated(UpdateGroup.class) ProductDTO dto) {
return "更新成功";
}
五、嵌套对象校验
@Data
public class OrderDTO {
@NotNull
private String orderId;
@Valid
private UserDTO user;
}
嵌套类字段必须加上
@Valid
,否则不会校验子对象。
六、自定义校验注解(扩展能力)
如果内置注解无法满足需求,可以自定义注解:
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
String message() default "手机号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
配套实现类:
public class PhoneValidator implements ConstraintValidator<Phone, String> {
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && value.matches("1[3-9]\\d{9}");
}
}
七、异常处理建议
建议统一处理校验异常,避免前端收到堆栈信息:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidException(MethodArgumentNotValidException ex) {
String msg = ex.getBindingResult().getFieldErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", "));
return ResponseEntity.badRequest().body(msg);
}
}
八、总结
@Valid
和 @Validated
是 Spring Bean 校验机制的核心注解。前者适用于大部分简单校验,后者支持更复杂的分组校验需求。在结合 @RequestBody
、嵌套对象以及统一异常处理机制后,可以构建一套健壮且优雅的参数校验体系。
掌握它们的用法,能显著提升项目的可靠性与开发效率,是每一位 Java Web 开发者必须掌握的核心技能之一。