一、为什么需要参数校验?
在开发 Web 应用时,用户输入的合法性校验是保障系统稳定性的基础。传统做法是通过 if-else 语句逐个判断参数,但代码臃肿、可读性差且容易遗漏校验逻辑。Spring Boot 的 @Validated 注解 提供了一种更优雅的解决方案,结合 JSR-303/380 规范,只需简单注解即可实现复杂校验。
二、Validated 的核心用法
1. 基础校验
在实体类字段上添加校验注解(如 @NotBlank、@Email),并在控制器方法参数前添加 @Validated,即可自动触发校验。
示例代码:
// 实体类
public class UserDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "长度需 3-20 位")
private String username;
@Email(message = "邮箱格式错误")
private String email;
}
// 控制器
@RestController
public class UserController {
@PostMapping("/register")
public String register(@Validated @RequestBody UserDTO user) {
return "注册成功!"; // 校验通过后执行
}
}
效果: 若参数不合法,直接返回错误信息,不会进入方法体。
2. 分组校验
针对不同场景(如新增、更新)设置不同校验规则,通过 groups 参数实现精细化控制。
示例代码:
public interface ValidationGroups {
interface Insert extends Default {} // 新增分组
interface Update extends Default {} // 更新分组
}
public class Project {
@NotBlank(groups = Update.class, message = "ID 不能为空")
private String id;
@Min(value = 1000, groups = Insert.class, message = "预算不能低于 1000")
private int budget;
}
// 控制器
@RestController
public class ProjectController {
@PostMapping("/add")
public String addProject(
@Validated(Insert.class) @RequestBody Project project) {
return "新增成功!";
}
@PostMapping("/modify")
public String modifyProject(
@Validated(Update.class) @RequestBody Project project) {
return "修改成功!";
}
}
效果: 新增时校验预算,更新时校验 ID。
3. 嵌套校验
对嵌套对象进行级联校验,只需在父对象字段添加 @Valid(注意:@Validated 无法直接用于嵌套对象)。
示例代码:
public class User {
@NotBlank
private String name;
@Valid
private Address address; // 嵌套对象需加 @Valid
}
public class Address {
@NotBlank
private String city;
}
// 控制器
@PostMapping("/user")
public String user(@Validated @RequestBody User user) {
return "校验通过!";
}
效果: 若 address.city 为空,直接返回错误。
三、进阶技巧
1. 自定义校验注解
当内置注解无法满足需求时,可创建自定义注解。例如校验用户名唯一性:
步骤:
定义注解 @UniqueUsername
实现校验器 UniqueUsernameValidator
代码片段:
// 自定义注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueUsernameValidator.class)
public @interface UniqueUsername {
String message() default "用户名已存在";
}
// 校验器
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {
@Override
public boolean isValid(String username, ConstraintValidatorContext context) {
// 调用数据库或缓存验证唯一性
return !"admin".equals(username); // 示例逻辑
}
}
使用:
public class UserDTO {
@UniqueUsername
private String username;
}
效果: 校验用户名是否重复。
2. 全局异常处理
通过 @RestControllerAdvice 统一处理校验异常,返回结构化错误信息:
代码示例:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return errors;
}
}
效果: 返回 JSON 格式错误信息,如 {“username”:“用户名不能为空”}。
四、总结
@Validated 不仅简化了参数校验逻辑,还通过分组、嵌套校验和自定义注解提供了强大的扩展性。结合全局异常处理,开发者可以专注于业务逻辑,而非重复的校验代码。
实践建议:
在 pom.xml 中添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
优先使用 @Validated(Spring 特有),复杂场景结合 @Valid(Java 标准)。
公众号:【码农小站】