我们一般都需要对接口参数进行校验,但一般都会觉得 if-else 的方式不够优雅,不妨试试 Spring Validation。
本文将介绍 Spring Validation 的使用方法、常用注解、自定义校验规则,以及在实际项目中的最佳实践。
一、什么是 Spring Validation?
Spring Validation 是 Spring 框架对 JSR-303/JSR-380(Bean Validation)规范 的实现,用于对 Java Bean 的属性进行声明式校验。它通过注解的方式,将校验逻辑与业务代码解耦,让代码更清晰、更易维护。
✅ JSR-303:Bean Validation 1.0
✅ JSR-380:Bean Validation 2.0(支持 Java 8+,如 Optional、LocalDateTime 等)
Spring Boot 默认集成了 Hibernate Validator(Bean Validation 的参考实现),一般只需引入 spring-boot-starter-web,它已经默认包含了 hibernate-validator:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如果你使用的是非 Spring Boot 项目,需要手动添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
二、快速上手:一个简单例子
1. 定义请求对象
public class UserRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 18, message = "年龄不能小于18岁")
@Max(value = 100, message = "年龄不能超过100岁")
private Integer age;
// getter / setter 省略
}
2. 在 Controller 中启用校验
@RestController
public class UserController {
@PostMapping("/user")
public ResponseEntity<String> createUser(
@Valid @RequestBody UserRequest request) {
// 如果校验失败,会自动抛出 MethodArgumentNotValidException
return ResponseEntity.ok("用户创建成功");
}
}
⚠️ 注意:必须加上 @Valid 或 @Validated 注解,才能触发校验!
3. 全局异常处理(推荐)
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return ResponseEntity.badRequest().body(errors);
}
}
这样,当参数校验失败时,前端会收到清晰的错误信息,例如:
{
"username": "用户名不能为空",
"email": "邮箱格式不正确"
}
三、常用校验注解一览
|
注解 |
说明 |
|
@NotNull |
不能为 null(但可以是空字符串) |
|
@NotEmpty |
不能为 null 且长度 > 0(适用于 String、Collection 等) |
|
@NotBlank |
不能为 null 且去除空格后长度 > 0(仅用于 String) |
|
|
邮箱格式校验 |
|
@Pattern(regexp = “…”) |
正则表达式校验 |
|
@Min / @Max |
数值范围校验 |
|
@Size(min=, max=) |
字符串/集合长度校验 |
|
@Past / @Future |
时间必须在过去/未来 |
|
@AssertTrue |
布尔值必须为 true(常用于同意协议等) |
四、分组校验:不同场景不同规则
有时同一个对象在不同接口中校验规则不同。列如注册时需要邮箱,修改资料时可选。
1. 定义分组接口
public interface CreateGroup {}
public interface UpdateGroup {}
2. 在字段上指定分组
public class UserRequest {
@NotBlank(groups = CreateGroup.class)
private String username;
@Email(groups = {CreateGroup.class, UpdateGroup.class})
private String email;
}
3. Controller 中指定使用哪个分组
@PostMapping("/user")
public String createUser(@Validated(CreateGroup.class) @RequestBody UserRequest req) {
// 只校验 CreateGroup 相关的字段
}
五、自定义校验:灵活应对业务需求
当内置注解无法满足需求时,我们可以自定义校验逻辑。
示例:校验手机号格式
1. 定义注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface ValidPhone {
String message() default "手机号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2. 实现校验逻辑
public class PhoneValidator implements ConstraintValidator<ValidPhone, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) return true; // null 由 @NotNull 处理
return value.matches("^1[3-9]d{9}$");
}
}
3. 使用
public class UserRequest {
@ValidPhone
private String phone;
}
六、最佳实践提议
- 不要在 Controller 层写 if-else 校验,统一使用 Validation。
- 结合全局异常处理,返回结构化错误信息。
- 合理使用分组校验,避免重复定义 DTO。
- 自定义校验器要轻量,避免复杂业务逻辑。
- 前端也应做基础校验,但后端校验不可省略(安全兜底)。
七、结语
Spring Validation 让参数校验变得简单、统一、可维护。掌握它,不仅能提升开发效率,还能让你的 API 更健壮、更专业。
小贴士:如果你的项目还在用大量 if 判断做参数校验,是时候重构了!







![[C++探索之旅] 第一部分第十一课:小练习,猜单词 - 鹿快](https://img.lukuai.com/blogimg/20251015/da217e2245754101b3d2ef80869e9de2.jpg)










- 最新
- 最热
只看作者