Spring Boot - Hibernate 自定义约束不注入服务

cdx*_*dxf 2 spring hibernate-validator spring-boot

我将尝试忽略其他细节并使其简短:

@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);
    }

}
Run Code Online (Sandbox Code Playgroud)

这将在 Spring 中进行验证(Spring MVC@Valid或注入Validatorusing @Autowire)时起作用,一切都会好起来的。但是一旦我使用 Spring Data JPA 保存实体:

User save = userRepository.save(newUser);
Run Code Online (Sandbox Code Playgroud)

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

更新:这是我的用户服务:

   @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 ....
    }
Run Code Online (Sandbox Code Playgroud)

M. *_*num 7

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

您可以使用 aHibernatePropertiesCustomizer并将属性添加到现有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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样的东西应该用休眠连接现有的验证器,并且它将使用自动连接。

注意:您不需要@Component在验证器上使用自动装配在返回Validator.