我会尽量忽略其他细节并简短说明:
@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 ....
}
答案 0 :(得分: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 :(得分:1)
要将Spring bean注入ConstraintValidator
,您需要一个特定的ConstraintValidatorFactory
,应该在ValidatorFactory
的初始化时传递。
有些事情:
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.constraintValidatorFactory( new MySpringAwareConstraintValidatorFactory( mySpringContext ) )
.build();
MySpringAwareConstraintValidatorFactory
为ConstraintValidatorFactory
,会将{bean}注入ConstraintValidator
。
我怀疑Spring Data使用的ValidatorFactory
在创建时没有注入验证器,这是不幸的。
我想你应该能够覆盖它。或者更好的是,您应该针对Spring Boot / Spring Data打开一个问题,以便他们能够正确地注入ConstraintValidator
,因为我们连续第二次在SO上提出这个问题。
答案 2 :(得分:0)
这里的答案非常大。请检查S.O中的这篇文章以帮助您。这应该可以帮助您入门。
Test Custom Validator with Autowired spring Service
问题是hibernate无法知道spring定义。但是,您可以让实体了解任何类型的javax.validation
类型。希望这会有所帮助。