通过 @Validated
和 @Valid可以对请求的进行参数校验。
1.核心对比:
特性 | @Valid (JSR-303) | @Validated (Spring) |
---|---|---|
来源 | Java标准规范 | Spring框架扩展 |
分组校验 | 不支持 | 支持(通过groups 属性) |
嵌套路径 | 自动处理级联校验 | 需配合@Valid 生效 |
应用范围 | 方法参数、属性、返回值 | 类、方法、参数 |
List校验 | 需放在集合声明处 | 需配合@Valid 生效 |
2.基础使用示例
2.1 单对象校验
public class UserDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式错误")
private String email;
}
// 使用@Valid
@PostMapping("/users")
public Result createUser(@RequestBody @Valid UserDTO user) {
// ...
}
// 使用@Validated
@RestController
@Validated // 类级别启用校验
public class UserController {
@PostMapping("/users")
public Result createUser(@RequestBody @Validated UserDTO user) {
// ...
}
}
3. 级联属性校验
3.1 嵌套对象校验
public class OrderDTO {
@NotNull
private Long orderId;
@Valid // 关键注解,启用嵌套校验
private UserDTO user;
}
// 测试
@PostMapping("/orders")
public Result createOrder(@RequestBody @Valid OrderDTO order) {
// 会自动校验order.user里的约束
}
3.2 集合元素校验
public class BatchRequest {
@Size(min = 1, max = 10)
private List<@Valid UserDTO> users; // 校验每个元素
}
@PostMapping("/batch")
public Result batchCreate(@RequestBody @Valid BatchRequest request) {
// 会校验list内每个UserDTO
}
4. 分组校验(仅@Validated支持)
4.1 定义校验分组
public interface CreateCheck {}
public interface UpdateCheck {}
public class ProductDTO {
@Null(groups = CreateCheck.class) // 创建时ID必须为空
@NotNull(groups = UpdateCheck.class) // 更新时ID不能为空
private Long id;
@NotBlank(groups = {CreateCheck.class, UpdateCheck.class})
private String name;
}
4.2 使用分组
@PostMapping("/products")
public Result create(@RequestBody @Validated(CreateCheck.class) ProductDTO product) {
// 仅触发CreateCheck组的校验
}
@PutMapping("/products/{id}")
public Result update(@PathVariable Long id,
@RequestBody @Validated(UpdateCheck.class) ProductDTO product) {
// 仅触发UpdateCheck组的校验
}
5.统一异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理@Validated和@Valid抛出的异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleValidException(MethodArgumentNotValidException e) {
List<String> errors = e.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.toList());
return Result.fail(400, "参数错误", errors);
}
}
6.最佳实现
6.1 混合使用
类/方法级用 @Validated
参数/属性级用 @Valid
6.2 性能优化
// 避免在循环中校验
@Validated
@Service
public class UserService {
public void batchProcess(@Valid List<UserDTO> users) {
// 批量处理
}
}
6.3 自定义校验
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
String message() default "手机号格式错误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
6.4 复杂场景
// 级联校验+集合校验
public class DepartmentDTO {
@Valid
private List<@Valid EmployeeDTO> employees;
@Valid
private AddressDTO location;
}