我会试着忽略其他细节并简短说明:
@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 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
将自动装配构建到验证器工厂中。
要将春豆注入你的ConstraintValidator
,你需要一个特定的ConstraintValidatorFactory
,它应该在ValidatorFactory
的初始化时通过。
有点像:
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.constraintValidatorFactory( new MySpringAwareConstraintValidatorFactory( mySpringContext ) )
.build();
与MySpringAwareConstraintValidatorFactory
是一个ConstraintValidatorFactory
,注入你的ConstraintValidator
豆。
我怀疑Spring Data使用的ValidatorFactory
在创建它时没有注入验证器,这是不幸的。
我想你应该能够覆盖它。或者更好的是,你应该针对Spring Boot / Spring Data打开一个问题,以便他们正确地注入ConstraintValidator
s,因为它是第二次我们在SO上有这个问题。
在这里发布的答案非常大。请检查S.O中的这篇文章以帮助您。这应该可以帮助您入门。
Test Custom Validator with Autowired spring Service
问题是hibernate将无法知道spring定义。但是,您可以让实体了解任何类型的javax.validation
类型。希望这可以帮助。