【问题标题】:HV000028: Unexpected exception during isValid callHV000028:isValid 调用期间出现意外异常
【发布时间】:2021-11-03 10:01:18
【问题描述】:

我创建了一个自定义验证规则来检查数据库中是否存在用户名。

我的 User 类有一个用户名,该用户名有一个自定义验证规则,当创建一个对象时,它会检查数据库中是否存在相同的用户名。

我使用interface UserRepository extends JpaRepository<User, Integer> 将用户保存到数据库并在自定义验证规则中检查用户名是否已存在。我利用

@Autowired
UserRepository userRepository;

我可以单独验证用户并将它们保存到数据库中,但是当将它们一起使用时,例如调用 userRepository.save(user);,自定义验证规则中的 @Autowired UserRepository userRepository; 不会启动,因此它仍然为空。

javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.

自定义验证规则

public class UsernameConstraintValidator implements ConstraintValidator<Username, String> {
    
    @Autowired
    UserRepository userRepository;

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        return !userRepository.existsUserByUsername(s);
    }
}

试图在控制器中保存用户

  @PostMapping("/save")
    public String save(@Valid @ModelAttribute("user") User user,BindingResult result, @RequestParam String password2){

        if(result.hasErrors()) return "register";

       userRepository.save(user);
               
        return "login";
    }

【问题讨论】:

    标签: spring dependency-injection spring-data-jpa


    【解决方案1】:

    您的自定义验证类似乎不是 Spring 托管 bean。尝试如下添加@Component注解:

    @Component
    public class UsernameConstraintValidator implements ConstraintValidator<Username, String> {
        
        @Autowired
        UserRepository userRepository;
    
        @Override
        public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
            return !userRepository.existsUserByUsername(s);
        }
    }
    

    2021 年 6 月 9 日更新 看起来(根据https://stackoverflow.com/a/13361762/16572295),您还需要设置LocalValidatorFactoryBean 才能使其正常工作:

    @Bean
    public Validator validatorFactory() {
        return new LocalValidatorFactoryBean();
    }
    

    【讨论】:

    • 我已经尝试过了,但没有成功。我还尝试将 UserRepository 的范围更改为原型,也没有成功。
    • 看来你需要别的东西才能让它工作 --> stackoverflow.com/a/13361762/16572295。我会将其添加到我的答案中。
    • 我认为它与 LocalValidatorFactoryBean() 没有任何关系,因为验证工作完美。我认为问题可能出在该存储库中,因为它正在尝试启动另一个进程,而另一个进程已经在运行,因此 userRepo.save(user) 正在调用 userRepo.existsUserByUsername("username")
    • 老实说,我也不太确定LocalValidatorFactoryBean。但我不相信它与userRepo.save(user) 有任何关系。验证在代码到达该点之前完成。而且当您在问题中指出“在自定义验证规则中没有启动因此它保持为空”时,我也没有得到“验证工作完美”。
    • 尽管如此,无论我在哪里,我都会发现类似这样的东西:“在春天,如果我们注册 LocalValidatorFactoryBean 以引导 javax.validation.ValidatorFactory 然后自定义 ConstraintValidator 类被加载为 Spring Bean。这意味着我们可以Spring 在验证器类中的依赖注入的好处。”这基本上就是您要寻找的。​​span>
    【解决方案2】:

    application.propperties中添加spring.jpa.properties.javax.persistence.validation.mode=none

    我在这个帖子中找到了答案:Spring-Boot How to properly inject javax.validation.Validator

    This 答案包括解决我在 bean 验证和休眠时遇到的问题。

    "...因为 Hibernate 不知道 Spring Context 并且据我所知没有办法告诉它,即使使用 LocalValidatorFactoryBean 也是如此。这会导致 Validator 运行两次。一个正确,一旦失败。”

    简而言之,解决方案是通过在 application.propperties

    中添加以下行来告诉 hibernate 不运行验证
    spring.jpa.properties.javax.persistence.validation.mode=none
    

    我建议您阅读此问题的完整答案,以更好地了解它对 LocalValidatorFactoryBean 的影响。

    感谢 João Dias 帮助我找到这个答案。

    【讨论】:

      猜你喜欢
      • 2020-05-30
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 2017-07-17
      • 2019-03-19
      • 2018-12-06
      • 1970-01-01
      • 2017-08-06
      相关资源
      最近更新 更多