Spring的@Validated:程序员的自我修养之数据安检指南

98 阅读4分钟

✍️ 【Spring的@Validated:程序员的自我修养之数据安检指南】 ✍️


一、开篇:当代码遇到杠精——数据校验的哲学思考

想象你开发的API是个夜店入口,各种请求参数是形形色色的客人。
@Validated 就是那个拿着金属探测器的保安,专治各种"带刀带枪"的非法分子(无效参数)。
但这位保安不仅会检查身份证(数据类型),还能揪出伪造的VIP卡(业务规则校验)!


二、@Validated角色卡

身份:Spring框架校验MVP
必杀技

  1. 支持JSR-303/JSR-380规范(Hibernate Validator的幕后金主)
  2. 方法级别校验(能怼Service层的方法参数)
  3. 分组校验(不同场景用不同安检规则)
  4. 自定义校验扩展(保安还能学会擒拿术)

宿敌:非法参数、越界数据、格式错误


三、使用姿势大全

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魔法

  1. MethodValidationPostProcessor 悄悄给Bean套上校验马甲
  2. 通过AOP代理拦截带有@Validated注解的方法
  3. 在方法执行前用Validator进行参数突击检查
  4. 发现可疑分子立即抛出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错误大礼包


七、最佳实践:老司机的安全驾驶指南

  1. 分层校验策略

    • Controller层:基础格式校验
    • Service层:核心业务规则校验
    • 数据库层:最终防线(unique约束等)
  2. 分组使用技巧
    按业务场景划分:CreateGroup/UpdateGroup/QueryGroup

  3. 自定义注解工厂
    封装常用校验:@PhoneNumber @ChineseIDCard @SafePassword

  4. 性能优化
    对高频接口使用快速失败模式:

    @Bean
    public Validator validator() {
        return Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(true) // 发现第一个错误立即返回
                .buildValidatorFactory()
                .getValidator();
    }
    

八、面试考点突击班

Q1: @Validated和@Valid有什么区别?

参考答案

  • @Valid是JSR标准注解,主要用于字段和方法参数的校验,支持嵌套校验
  • @Validated是Spring的增强版,支持分组校验和方法级别校验,通常需要配合@Valid使用嵌套校验

Q2: 如何实现自定义校验逻辑?

参考答案

  1. 创建自定义注解(如@NoEmoji)
  2. 实现ConstraintValidator接口
  3. 在需要校验的字段上使用自定义注解

Q3: 为什么Service层的方法校验需要@Validated?

参考答案
因为Spring默认只在Controller层处理@Valid注解,在Service层需要通过@Validated注解开启AOP代理,结合方法参数上的校验注解实现校验


九、总结:校验的艺术

数据校验就像代码世界的防疫措施:

  • 外层校验是机场海关(格式检查)
  • 业务校验是医院核酸检测(业务规则)
  • 数据库约束是最后的ICU(兜底防护)

@Validated就是我们手中的智能测温枪,用好这个神器,让你的系统百毒不侵!最后送各位一句编程箴言:

"早校验,早隔离,你的程序更健康!"


💡 互动环节:你在使用@Validated时踩过哪些有趣的坑?欢迎在评论区分享你的"血泪史"!