You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring自定义Validator未自动执行?排查错误原因及解决方法

问题:Spring Boot自定义Validator未自动执行,条件验证失效

我需要验证POST请求的JSON内容,实现当属性type为A且name为空时输入无效的条件验证。使用自定义Validator实现,但该Validator未被执行,只有在控制器中通过@InitBinder手动注册才能生效,希望找到更优雅的解决方式。

现有代码

控制器代码

@RestController
@RequestMapping("/orders")
@Validated
public class OrderController {
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void createOrder(@Valid @RequestBody OrderDto order) {
      // 业务逻辑
    }
}

自定义Validator代码

@Component
public class OrderValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return OrderDto.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        final var order = (OrderDto) target;

        if (order.getType() == Type.A && Strings.isEmpty(order.getName())) {
            errors.rejectValue("name", "name.required", "Name required for type A");
        }
    }
}

OrderDto实体类

@Getter
@Setter
public class OrderDto {
    private String name;
    @NotNull
    private Type type;
}

问题现象

  • 当type为null时,@NotNull注解正常触发,返回HTTP 400错误;
  • 当type为A且name为null时,自定义的OrderValidator未执行(断点未进入supports和validate方法),请求返回HTTP 201成功;
  • Validator已被Spring Boot识别为Bean,可以正常注入。

原因分析

Spring Boot默认不会自动将实现Validator接口的Bean关联到对应的实体类上,@Valid注解只会触发JSR-380标准的Bean Validation注解(如@NotNull),不会自动调用自定义的Validator实现,必须通过显式注册才能生效。

解决方案

方案一:全局注册自定义Validator

通过实现WebMvcConfigurer全局配置,将自定义Validator注册到Spring的验证体系中,无需在每个控制器中添加@InitBinder:

@Configuration
public class WebValidationConfig implements WebMvcConfigurer {
    private final OrderValidator orderValidator;

    // 构造方法注入Validator
    public WebValidationConfig(OrderValidator orderValidator) {
        this.orderValidator = orderValidator;
    }

    @Override
    public void addValidators(ValidatorRegistry registry) {
        registry.addValidator(orderValidator);
    }
}

方案二:改用JSR-380自定义注解(推荐)

遵循Bean Validation标准,通过自定义注解+ConstraintValidator实现条件验证,这种方式更符合Spring Boot的验证体系,无需额外注册:

  1. 定义自定义约束注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = OrderTypeConstraintValidator.class)
public @interface ValidOrder {
    String message() default "Name is required when type is A";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  1. 实现约束验证器
public class OrderTypeConstraintValidator implements ConstraintValidator<ValidOrder, OrderDto> {
    @Override
    public boolean isValid(OrderDto order, ConstraintValidatorContext context) {
        // 当type为A时,name不能为空
        if (Type.A.equals(order.getType())) {
            return !Strings.isEmpty(order.getName());
        }
        // 其他类型无需验证name
        return true;
    }
}
  1. 在实体类上添加注解
@Getter
@Setter
@ValidOrder // 添加自定义验证注解
public class OrderDto {
    private String name;
    @NotNull
    private Type type;
}

完成以上配置后,原控制器代码无需修改,@Valid注解会自动触发@ValidOrder对应的验证逻辑,当type为A且name为空时,会返回HTTP 400错误。

内容的提问来源于stack exchange,提问作者Datz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:17:04