✍️ 【Spring的@Validated:程序员的自我修养之数据安检指南】 ✍️
一、开篇:当代码遇到杠精——数据校验的哲学思考
想象你开发的API是个夜店入口,各种请求参数是形形色色的客人。
@Validated 就是那个拿着金属探测器的保安,专治各种"带刀带枪"的非法分子(无效参数)。
但这位保安不仅会检查身份证(数据类型),还能揪出伪造的VIP卡(业务规则校验)!
二、@Validated角色卡
身份:Spring框架校验MVP
必杀技:
- 支持JSR-303/JSR-380规范(Hibernate Validator的幕后金主)
- 方法级别校验(能怼Service层的方法参数)
- 分组校验(不同场景用不同安检规则)
- 自定义校验扩展(保安还能学会擒拿术)
宿敌:非法参数、越界数据、格式错误
三、使用姿势大全
1. 基础版:Controller层防暴模式
@PostMapping("/users")
public String createUser(@RequestBody @Validated UserDTO user) {
// 当user的@NotBlank字段为空时,这里根本执行不到!
}
2. 进阶版:Service层无差别攻击
@Service
@Validated // 类级别开启轰炸模式
public class UserService {
public void updateUser(@Valid @Min(18) Integer age) {
// 年龄不足18?门都没有!
}
}
3. 黑科技:分组校验(场景化安检)
public interface AdultGroup {} // 成人验证组
public interface ChildGroup {} // 儿童验证组
public class UserDTO {
@NotBlank(groups = {AdultGroup.class, ChildGroup.class})
private String name;
@Min(value = 18, groups = AdultGroup.class)
private Integer age;
}
@PostMapping("/buy-alcohol")
public String buyAlcohol(@Validated(AdultGroup.class) UserDTO user) {
// 买酒必须通过成人验证!
}
4. 自定义必杀技:打造专属安检规则
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = EmojiValidator.class)
public @interface NoEmoji {
String message() default "禁止使用颜文字!(╯‵□′)╯︵┻━┻";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class EmojiValidator implements ConstraintValidator<NoEmoji, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return !value.matches(".*[\\uD83C-\\uDBFF\\uDC00-\\uDFFF]+.*");
}
}
四、原理揭秘:Spring的AOP魔法
- MethodValidationPostProcessor 悄悄给Bean套上校验马甲
- 通过AOP代理拦截带有@Validated注解的方法
- 在方法执行前用Validator进行参数突击检查
- 发现可疑分子立即抛出MethodArgumentNotValidException
就像给每个方法门口装了智能安检门,参数想溜进去?先过X光机!
五、@Validated vs @Valid:塑料姐妹花の爱恨情仇
| 特性 | @Validated | @Valid |
|---|---|---|
| 出身 | Spring亲闺女 | JSR标准大家闺秀 |
| 作用范围 | 类/方法 | 方法参数/字段 |
| 分组校验 | ✅ 支持 | ❌ 不支持 |
| 嵌套校验 | 需要@Valid助攻 | 自带嵌套技能 |
| 使用场景 | 更Spring风格的场景 | 通用JSR场景 |
CP使用指南:在Controller层用@Valid触发校验,在需要分组校验或方法级校验时召唤@Validated
六、避坑宝典:那些年我们踩过的雷
1. 嵌套校验失踪案
public class OrderDTO {
@Valid // 必须加这个!否则嵌套对象里的校验不生效
private UserDTO user;
}
就像行李箱过安检必须打开,嵌套对象需要@Valid配合使用
2. 分组使用翻车现场
// 错误示范:忘记指定分组
@Validated // 漏掉分组就像让保安瞎检查
public void updateUser(@Valid UserDTO user) {...}
// 正确姿势
@Validated(AdultGroup.class)
3. 异常捕获大作战
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<?> handleValidationException(ConstraintViolationException ex) {
// 处理校验失败的异常,组装友好错误信息
}
}
不处理异常的话,API消费者会收到500错误大礼包
七、最佳实践:老司机的安全驾驶指南
-
分层校验策略
- Controller层:基础格式校验
- Service层:核心业务规则校验
- 数据库层:最终防线(unique约束等)
-
分组使用技巧
按业务场景划分:CreateGroup/UpdateGroup/QueryGroup -
自定义注解工厂
封装常用校验:@PhoneNumber @ChineseIDCard @SafePassword -
性能优化
对高频接口使用快速失败模式:@Bean public Validator validator() { return Validation.byProvider(HibernateValidator.class) .configure() .failFast(true) // 发现第一个错误立即返回 .buildValidatorFactory() .getValidator(); }
八、面试考点突击班
Q1: @Validated和@Valid有什么区别?
参考答案:
- @Valid是JSR标准注解,主要用于字段和方法参数的校验,支持嵌套校验
- @Validated是Spring的增强版,支持分组校验和方法级别校验,通常需要配合@Valid使用嵌套校验
Q2: 如何实现自定义校验逻辑?
参考答案:
- 创建自定义注解(如@NoEmoji)
- 实现ConstraintValidator接口
- 在需要校验的字段上使用自定义注解
Q3: 为什么Service层的方法校验需要@Validated?
参考答案:
因为Spring默认只在Controller层处理@Valid注解,在Service层需要通过@Validated注解开启AOP代理,结合方法参数上的校验注解实现校验
九、总结:校验的艺术
数据校验就像代码世界的防疫措施:
- 外层校验是机场海关(格式检查)
- 业务校验是医院核酸检测(业务规则)
- 数据库约束是最后的ICU(兜底防护)
@Validated就是我们手中的智能测温枪,用好这个神器,让你的系统百毒不侵!最后送各位一句编程箴言:
"早校验,早隔离,你的程序更健康!"
💡 互动环节:你在使用@Validated时踩过哪些有趣的坑?欢迎在评论区分享你的"血泪史"!