一、依赖配置
首先确保在 pom.xml
中添加了以下依赖:
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
这个依赖包含了 Hibernate Validator(JSR-380 规范的实现)和必要的 Spring 验证支持。
验证执行流程:
-
当请求到达Controller方法时,Spring会检查方法参数上的
@Valid
或@Validated
注解 -
触发
MethodValidationInterceptor
拦截器 -
创建
Validator
实例并执行验证 -
验证器会递归检查对象及其属性上的所有约束注解
-
如果验证失败,收集所有违反的约束
二、基本验证注解
以下是常用的验证注解:
-
@NotNull
- 值不能为 null -
@Null
- 值必须为 null -
@AssertTrue
- 值必须为 true -
@AssertFalse
- 值必须为 false -
@Min(value)
- 数字必须大于等于指定值 -
@Max(value)
- 数字必须小于等于指定值 -
@DecimalMin(value)
- 必须大于等于指定值(字符串形式表示) -
@DecimalMax(value)
- 必须小于等于指定值(字符串形式表示) -
@Size(min, max)
- 集合/字符串/数组大小必须在范围内 -
@Digits(integer, fraction)
- 数字格式检查 -
@Past
- 必须是过去的日期 -
@PastOrPresent
- 必须是过去或现在的日期 -
@Future
- 必须是将来的日期 -
@FutureOrPresent
- 必须是将来或现在的日期 -
@Pattern(regex)
- 必须匹配正则表达式 -
@Email
- 必须是有效的邮箱格式 -
@Valid
- 级联验证,用于验证对象中的嵌套对象
三、使用示例
1. 在实体类中使用验证注解
java
public class User {
@NotNull(message = "用户ID不能为空")
private Long id;
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度必须在2-20之间")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$",
message = "密码必须至少8个字符,包含大小写字母和数字")
private String password;
@Min(value = 18, message = "年龄必须大于等于18")
@Max(value = 100, message = "年龄必须小于等于100")
private Integer age;
@Past(message = "出生日期必须是过去的时间")
private LocalDate birthday;
// getters and setters
}
2. 在Controller中使用验证
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody User user) {
// 业务逻辑处理
return ResponseEntity.ok("用户创建成功");
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(
@PathVariable @Min(1) Long id,
@RequestParam(required = false) @Size(max = 100) String name) {
// 业务逻辑处理
return ResponseEntity.ok(new User());
}
}
3. 处理验证错误
当验证失败时,Spring 会抛出 MethodArgumentNotValidException
。可以全局处理这些异常:
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(
MethodArgumentNotValidException ex) {
List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
List<ErrorDetail> errorDetails = fieldErrors.stream()
.map(error -> new ErrorDetail(
error.getField(),
error.getRejectedValue(),
error.getDefaultMessage()))
.collect(Collectors.toList());
ErrorResponse response = new ErrorResponse(
"VALIDATION_FAILED",
"参数验证失败",
errorDetails);
return ResponseEntity.badRequest().body(response);
}
}
// 响应数据结构
public class ErrorResponse {
private String code;
private String message;
private List<ErrorDetail> details;
// 构造方法/getters/setters
}
public class ErrorDetail {
private String field;
private Object rejectedValue;
private String message;
// 构造方法/getters/setters
}
响应示例
当验证失败时,返回的JSON结构如下:
java
{
"code": "VALIDATION_FAILED",
"message": "参数验证失败",
"details": [
{
"field": "age",
"rejectedValue": 15,
"message": "年龄必须大于等于18"
},
{
"field": "email",
"rejectedValue": "invalid-email",
"message": "必须是有效的邮箱格式"
}
]
}