为何运行自定义Spring Validator需依赖Hibernate Validator?
自定义Spring Validator不生效,必须添加Hibernate Validator才正常
我写了一个自定义Spring Validator用来校验UserRegistrationDTO类,但不管用@Valid注解、数据绑定器校验还是直接调用validate方法,都触发不了校验逻辑。我已经引入了spring-boot-starter-validation依赖,但只有添加Hibernate Validator依赖后校验才正常工作,想知道为什么spring-boot-starter-validation满足不了需求。
依赖配置
初始引入的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
额外添加的Hibernate Validator依赖
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.0.Final</version> </dependency>
DTO类
@Getter @Setter public class UserRegistrationDTO { private String username; private String password; private String confirmPassword; private String email; }
自定义Validator类
@Component(value = "userRegistrationValidator") public class UserRegistrationValidator implements Validator { @Override public boolean supports(Class<?> clazz) { return UserRegistrationDTO.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { UserRegistrationDTO userRegistrationDTO = (UserRegistrationDTO) target; ValidationUtils.rejectIfEmptyOrWhitespace(errors,"password", "password.empty", "The password must not be empty"); ValidationUtils.rejectIfEmptyOrWhitespace(errors,"confirmPassword", "cpassword.empty", "You have to confirm you password"); if (userRegistrationDTO.getPassword() != null) { if (userRegistrationDTO.getPassword().length() < 5 || userRegistrationDTO.getPassword().length() > 25) errors.rejectValue("password", "password.size", "The password size must be between 5 to 25"); if (userRegistrationDTO.getConfirmPassword() != null && !userRegistrationDTO.getPassword().equals(userRegistrationDTO.getConfirmPassword())) errors.rejectValue("confirmPassword", "password.not_equals", "The password is not equals"); } } }
Controller类(最终手动调用版本)
@Controller @RequestMapping("/register") @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class RegisterController { @Qualifier("userRegistrationValidator") private final Validator validator; @PostMapping public String registerProcessing(@ModelAttribute("userRegistration") @RequestBody UserRegistrationDTO userRegistrationDTO, BindingResult bindingResult) { ValidationUtils.invokeValidator(validator, userRegistrationDTO, bindingResult); if (bindingResult.hasErrors()) { return "login/signup"; } // ... 业务逻辑 return "redirect:/login"; } }
之前尝试的无效方案
方案一:通过数据绑定器添加校验器
@Qualifier("userRegistrationValidator") private final Validator validator; @InitBinder public void initBinder(WebDataBinder webDataBinder) { webDataBinder.addValidators(validator); }配合
@Valid注解使用,但校验未触发。方案二:直接调用validate方法
@PostMapping public String registerProcessing(@ModelAttribute("userRegistration") @RequestBody UserRegistrationDTO userRegistrationDTO, BindingResult bindingResult) { validator.validate(userRegistrationDTO, bindingResult); if (bindingResult.hasErrors()) { return "login/signup"; } // ... 业务逻辑 }校验逻辑依然未生效。
问题原因
- API与实现的分离:
spring-boot-starter-validation在Spring Boot 3.x及以上版本中,默认只引入Jakarta Validation API(规范定义),不包含具体实现。Hibernate Validator是Jakarta Validation的官方实现,没有它的话,Spring的校验体系缺少核心执行引擎,连自定义Validator的调用流程都无法正常初始化。 - 自动配置的隐性条件:Spring Boot的
ValidationAutoConfiguration自动配置类,会在检测到存在校验实现(比如Hibernate Validator)时才会完全初始化校验上下文。如果缺少实现类,自动配置逻辑会部分失效,导致自定义Validator无法被纳入执行链。 - 依赖冲突或排除:如果项目中其他依赖间接排除了Hibernate Validator,也会导致starter无法自动引入它。
解决办法
- 优先用starter管理版本:不需要手动指定Hibernate Validator的版本,
spring-boot-starter-validation会根据Spring Boot版本自动匹配兼容的Hibernate Validator版本,避免版本冲突。如果starter没自动引入,检查是否有依赖排除了Hibernate Validator。 - 验证自动配置状态:启动项目时添加
--debug参数,查看自动配置报告,确认ValidationAutoConfiguration是否生效。如果失效,排查是否有自定义配置覆盖了自动配置逻辑。 - 确认Validator注入正确性:确保
UserRegistrationValidator被Spring正确扫描(所在包被@ComponentScan覆盖),Controller中@Qualifier指定的名称和@Component的value完全匹配。
内容的提问来源于stack exchange,提问作者Victor Hugo Pongolino
相关产品推荐
相关产品推荐

