我创建了一个小示例项目,以显示我在Spring Boot验证配置及其与Hibernate集成时遇到的两个问题.
我已经尝试过我发现的有关该主题的其他回复,但遗憾的是它们对我不起作用或者要求禁用Hibernate验证.
我想使用实现ConstraintValidator的自定义Validator< ValidUser,User>并在其中注入我的UserRepository.
同时我想保持Hibernate的默认行为,在更新/持久化期间检查验证错误.
我在这里写的是应用程序的完整主要部分.
自定义配置
在这个类中,我使用自定义MessageSource设置自定义验证器,因此Spring将从文件resources / messages.properties中读取消息
@Configuration
public class CustomConfiguration {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:/messages");
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setCacheSeconds((int) TimeUnit.HOURS.toSeconds(1));
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
@Bean
public LocalValidatorfactorybean validator() {
LocalValidatorfactorybean factorybean = new LocalValidatorfactorybean();
factorybean.setValidationMessageSource(messageSource());
return factorybean;
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}
豆子
如果不是自定义验证器@ValidUser,这里没什么特别的
@ValidUser
@Entity
public class User extends AbstractPersistable
自定义验证器
这是我尝试注入存储库的地方.如果不禁用Hibernate验证,则存储库始终为null.
public class UserValidator implements ConstraintValidator
messages.properties
#CUSTOM VALIDATORS
ValidUser.message = I dati inseriti non sono validi. Verificare nuovamente e ripetere l'operazione.
ValidUser.unique.username = L'username [${validatedValue.getUsername()}] è già stato utilizzato. Sceglierne un altro e ripetere l'operazione.
#DEFAULT VALIDATORS
org.hibernate.validator.constraints.NotBlank.message = Il campo non può essere vuoto
# === USER ===
Pattern.user.landlinePhone = Il numero di telefono non è valido. Dovrebbe essere nel formato E.123 internazionale (https://en.wikipedia.org/wiki/E.123)
在我的测试中,您可以尝试使用源代码,我有两个问题:
>如果我不禁用Hibernate验证,则UserValidator中注入的存储库为null(spring.jpa.properties.javax.persistence.validation.mode = none)
>即使我禁用了Hibernate验证器,我的测试用例也会失败,因为有些东西会阻止Spring对验证消息使用默认字符串插值,这些消息应该类似于[Constraint].[class name lowercase].[propertyName].我不想使用像@NotBlank(message =“{mycustom.message}”这样的值元素的约束注释,因为我没有看到考虑到它有自己的插值对流的点,我可以利用那……这意味着更少编码.
I attach the code;您可以运行Junit测试并查看错误(启用Hibernate验证,检查application.properties).
我究竟做错了什么?我该怎么做才能解决这两个问题?
======更新======
为了澄清,阅读Spring验证文档https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation-beanvalidation-spring-constraints,他们说:
By default,the LocalValidatorfactorybean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances. This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.
As you can see,a ConstraintValidator implementation may have its dependencies @Autowired like any other Spring bean.
在我的配置类中,我在编写时创建了LocalValidatorfactorybean.
======更新2 ======
经过大量的研究,似乎用Hibernate验证器没有提供注入.
我找到了几种可以做到这一点的方法:
第一路
创建此配置类:
@Configuration
public class HibernateValidationConfiguration extends HibernateJpaAutoConfiguration {
public HibernateValidationConfiguration(DataSource dataSource,JpaProperties jpaProperties,ObjectProvider
第二种方式
创建一个实用程序bean
@Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static
然后在验证器初始化中:
@Override
public void initialize(ValidUser constraintAnnotation) {
userRepository = BeanUtil.getBean(UserRepository.class);
em = BeanUtil.getBean(EntityManager.class);
}
很重要
在这两种情况下,为了使其工作,您必须以这种方式“重置”实体管理器:
@Override
public boolean isValid(User value,ConstraintValidatorContext context) {
try {
em.setFlushMode(FlushModeType.COMMIT);
//your code
} finally {
em.setFlushMode(FlushModeType.AUTO);
}
}
无论如何,我不知道这是否真的是一种安全的方式. Probably it’s not a good practice access to the persistence layer at all.
@Configurable(autowire = Autowire.BY_TYPE,dependencyCheck = true)
public class UserValidator implements ConstraintValidator
从文档到该注释:
Marks a class as being eligible for Spring-driven configuration
所以这应该解决你的null问题.为了使它工作,你需要配置AspectJ …(检查如何在Spring中使用@Configurable)