Spring Boot - Hibernate自定义约束不会注入Service

问题描述 投票:2回答:3

我会试着忽略其他细节并简短说明:

@Entity
public class User
    @UniqueEmail
    @Column(unique = true)
    private String email;
}

@Component
public class UniqueEmailValidatior implements ConstraintValidator<UniqueEmail,String>, InitializingBean {

    @Autowired private UserService userService;

    @Override
    public void initialize(UniqueEmail constraintAnnotation) {

    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(userService == null) throw new IllegalStateException();
        if(value == null) return false;
        return !userService.isEmailExisted(value);
    }

}

这将在Spring(Spring MVC @Valid或使用Validator注入@Autowire)进行验证时有效,一切都会好的。但是只要我使用Spring Data JPA保存实体:

User save = userRepository.save(newUser);

Hibernate将尝试在不注入UniqueEmailValidatior bean的情况下实例化新的UserService。那么我怎么能让Hibernate使用我的UniqueEmailValidatior组件而不用实例化一个新的组件。我可以使用spring.jpa.properties.javax.persistence.validation.mode=none禁用hibernate验证,但我希望还有另一种方法

更新:这是我的UserService:

   @Autowired private Validator validator;
   @Transactional
    public SimpleUserDTO newUser(UserRegisterDTO user) {
        validator.validate(user);
        System.out.println("This passes");
        User newUser = new User(user.getUsername(),
                passwordEncoder.encode(user.getPassword()),user.getEmail(),
                "USER",
                user.getAvatar());
        User save = userRepository.save(newUser);
        System.out.println("This won't pass");
        return ....
    }
spring spring-boot hibernate-validator
3个回答
4
投票

我希望Spring Boot会将现有的验证器连接到EntityManager,显然它没有。

你可以使用HibernatePropertiesCustomizer并在现有的EntityManagerFactoryBuilder中添加属性并注册Validator

注意:我假设您使用的是Spring Boot 2.0

@Component
public class ValidatorAddingCustomizer implements HibernatePropertiesCustomizer {

    private final ObjectProvider<javax.validation.Validator> provider;

    public ValidatorAddingCustomizer(ObjectProvider<javax.validation.Validator> provider) {
        this.provider=provider;
    }

    public void customize(Map<String, Object> hibernateProperties) {
        Validator validator = provider.getIfUnique();
        if (validator != null) {
            hibernateProperties.put("javax.persistence.validation.factory", validator);
        }
    }
}

像这样的东西应该用hibernate连接现有的验证器,并且它将利用自动布线。

注意:在返回@Component实例之前,您不需要在验证器上使用Validator将自动装配构建到验证器工厂中。


1
投票

要将春豆注入你的ConstraintValidator,你需要一个特定的ConstraintValidatorFactory,它应该在ValidatorFactory的初始化时通过。

有点像:

ValidatorFactory validatorFactory = Validation.byDefaultProvider()
    .configure()
    .constraintValidatorFactory( new MySpringAwareConstraintValidatorFactory( mySpringContext ) )
    .build();

MySpringAwareConstraintValidatorFactory是一个ConstraintValidatorFactory,注入你的ConstraintValidator豆。

我怀疑Spring Data使用的ValidatorFactory在创建它时没有注入验证器,这是不幸的。

我想你应该能够覆盖它。或者更好的是,你应该针对Spring Boot / Spring Data打开一个问题,以便他们正确地注入ConstraintValidators,因为它是第二次我们在SO上有这个问题。


0
投票

在这里发布的答案非常大。请检查S.O中的这篇文章以帮助您。这应该可以帮助您入门。

Test Custom Validator with Autowired spring Service

问题是hibernate将无法知道spring定义。但是,您可以让实体了解任何类型的javax.validation类型。希望这可以帮助。

© www.soinside.com 2019 - 2024. All rights reserved.