Spring Boot条件依赖校验核心是校验分组+@Validated分组指定,通过RegisterStep1/2等接口分组、@ConstraintComposition字段级条件注解、@ScriptAssert跨字段校验及@ConvertGroup嵌套动态桥接实现。

Spring Boot 中实现条件依赖的参数校验,核心是使用 校验分组(Validation Groups) + @Validated 的分组指定,配合业务逻辑动态触发不同规则,而不是让所有字段无差别校验。
什么是条件依赖校验
指某些字段是否需要校验,取决于其他字段的值或当前操作场景。例如:
- 用户注册时,
inviteCode为非空才要求referralId必填且格式合法; - 订单提交时,支付方式为
"alipay"才校验alipayAccount; - 更新用户资料时,仅当修改了邮箱字段,才触发邮箱格式校验和唯一性检查。
用校验分组实现条件触发
不靠 if 判断,而是将不同校验逻辑拆到不同接口分组中,再由 Controller 按需启用:
- 定义两个分组标记接口:
public interface RegisterStep1 {}
public interface RegisterStep2 {} - 在 DTO 中按需绑定注解:
@NotBlank(groups = RegisterStep1.class)
private String username;
@NotBlank(groups = RegisterStep2.class)
@Email(groups = RegisterStep2.class)
private String email; - Controller 中指定分组:
@PostMapping("/register/step2")
public Result step2(@Validated(RegisterStep2.class) @RequestBody UserDTO dto) { ... }
用 @ConstraintComposition 实现字段级条件逻辑
当“是否校验某字段”完全取决于另一个字段值(如 type == "wechat" 时才校验 wechatId),可自定义组合注解:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- 创建注解
@WechatIdIfTypeWechat,标注在目标字段上; - 实现
ConstraintValidator,在isValid()中先获取当前对象的type字段值; - 若
type不为"wechat",直接返回true(跳过校验);否则执行@NotBlank或正则校验逻辑。
用 @ScriptAssert 做跨字段联动校验
适合简单逻辑,比如“密码和确认密码必须一致”“开始时间不能晚于结束时间”:
- 在 DTO 类上加注解:
@ScriptAssert(lang = "javascript", script = "_this.password == _this.confirmPassword", message = "两次输入的密码不一致") - 注意:需引入
javax.script:javax.script-api,且默认只支持 GraalVM 或 JDK 自带 Nashorn(JDK 15+ 已移除),生产环境建议改用自定义 ConstraintValidator 更稳妥。
结合 @ConvertGroup 动态桥接分组
当嵌套对象也需要条件校验时(如主对象启用 GroupA,其内部 address 对象才启用 AddressGroupA),可在属性上使用:
@Valid @ConvertGroup(from = RegisterStep1.class, to = AddressGroup1.class)
private Address address;










