核心是将字段校验逻辑从硬编码迁移至注解,通过反射在运行时自动触发校验;定义@target(field)、@retention(runtime)的业务字段注解,提供required/min/max/pattern/message等属性;用泛型validate(t)方法遍历字段、提取注解、匹配预置校验器并统一抛出validationexception;嵌入spring mvc或mybatis拦截点自动执行;新增校验规则只需添加注解及对应validator,无需修改原有代码。

核心是把字段校验逻辑从硬编码搬进注解里,再靠反射在运行时自动触发——产品改字段名、加新字段、调校验规则,开发只需改注解,不用碰校验代码。
一、定义面向业务字段的校验注解
注解要贴在 DTO 或 VO 的字段上,而不是方法或类上。关键点有三个:
- @Target(ElementType.FIELD):确保只能标在字段上,和业务字段一一对应
- @Retention(RetentionPolicy.RUNTIME):必须保留到运行时,反射才能读到
- 提供可配置属性,比如 required()、min()、max()、pattern()、message(),让产品提需求时直接写注解参数,不写 Java 逻辑
二、用反射构建通用校验执行链
不为每个 DTO 写单独的校验方法,而是写一个泛型入口:public static <t> void validate(T object)</t>。它内部做四件事:
- 遍历
object.getClass().getDeclaredFields(),跳过 static 和 final 字段 - 对每个字段调用
field.getAnnotation(NotBlank.class)等,批量提取所有校验注解 - 按注解类型匹配预置的校验器(如 NotBlankValidator、RangeValidator),每个校验器只关心自己那条规则
- 任一校验失败就收集错误信息,统一抛出
ValidationException,带字段名 + 自定义 message
三、嵌入到请求生命周期的关键位置
让校验自动发生,而不是等业务代码手动调用:
- Spring MVC 场景:用 @Valid 配合 MethodValidationPostProcessor,或自定义 HandlerMethodArgumentResolver,在 Controller 入参绑定后立即触发
validate() - MyBatis 场景:在 ResultSetHandler 拦截器中,对查询返回的每条记录执行
validate(),确保前端拿到的数据已过基础校验 - 避免放在 Service 层手动调用——那又回到了“改字段就得改代码”的老路
四、支持产品侧灵活扩展校验能力
新校验规则来了怎么办?不改框架、不改已有 DTO,只做两步:
- 新增一个注解,比如
@ChineseMobile,标注手机号是否需符合国内格式 - 写一个对应的
ChineseMobileValidator,注册进校验器工厂(可用 Spring 的@Component自动发现) - 产品在字段上加上
@ChineseMobile(message = "请填11位大陆手机号")即可生效
这样,前台字段增删改、校验规则调整,都收敛在注解声明和少量校验器实现里,彻底切断对业务方法体的侵入。










