java – @Autowired bean在控制器上与@Valid一起使用但在CRUD存储库中失败

前端之家收集整理的这篇文章主要介绍了java – @Autowired bean在控制器上与@Valid一起使用但在CRUD存储库中失败前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用用户注册表单处理 Spring MVC Hibernate JPA应用程序,我决定使用JSR-303验证程序检查用户名是否已存在于DB中:
  1. public class UniqueUsernameValidator implements ConstraintValidator<VerifyUniqueUsername,String> {
  2.  
  3. @Autowired
  4. UserService userService;
  5.  
  6. @Override
  7. public void initialize(VerifyUniqueUsername constraintAnnotation) {
  8. }
  9.  
  10. @Override
  11. public boolean isValid(String username,ConstraintValidatorContext context) {
  12.  
  13. return username!=null && userService.findByUsername(username) == null;
  14. }
  15. }

它非常简单,验证在我的控制器上运行良好:

  1. ....
  2. public String signup(@Valid @modelattribute("newUser") User user,BindingResult newUserBeanResult)
  3. .....

我面临的当前问题是,在我验证了User对象之后,我调用了:

  1. userService.save(user);

哪个实现了CrudRepository,我得到一个NullPointerException.出于某种原因,UserService在控制器上的验证期间注入,但在调用CrudRepository.save()时则不会.

我看到类似的帖子如下:
@Autowired bean null in ConstraintValidator when invoked by Sessionfactory.getCurrentSession.merge
还有这个:
hibernate validator without using autowire
但我想知道是否有人之前遇到过此事.我认为注入bean来访问验证器上的数据库是相当普遍的.

作为一种解决方法,我在userService上添加了一个null检查,但感觉不对.

>这是预期的行为吗?在调用CrudRepository.save()之前,这些验证是否会被激活?
>我是否愿意处理“手动”休眠事件?在这种情况下预插入

解决方法

我最终通过指示Spring的EntityManagerfactorybean使用我的验证器bean来解决这个问题(更准确地说,hibernate现在将使用Spring的验证器):
  1. <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerfactorybean">
  2. <property name="dataSource" ref="dataSource" />
  3. <property name="jpaVendorAdapter">
  4. <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
  5. </property>
  6. <property name="packagesToScan" value="some.packages"/>
  7. <property name="jpaPropertyMap">
  8. <map>
  9. <entry key="javax.persistence.validation.factory" value-ref="validator" />
  10. </map>
  11. </property>
  12. <property name="jpaProperties">
  13. <props>
  14. <prop key="hibernate.dialect">org.hibernate.dialect.MysqLDialect</prop>
  15. <prop key="hibernate.max_fetch_depth">3</prop>
  16. <prop key="hibernate.jdbc.fetch_size">50</prop>
  17. <prop key="hibernate.jdbc.batch_size">10</prop>
  18. <prop key="hibernate.show_sql">true</prop>
  19. </props>
  20. </property>
  21. </bean>

但是,这引发了StackOverflow错误:)

显然,这个问题的原因是我的验证器使用了finder方法(findByUsername),finder方法触发了hibernate flush,后者又触发了验证.这无限循环,直到你得到最着名的例外.

所以…我通过更改验证器直接使用EntityManager(而不是CRUD存储库)并暂时将FlushModeType更改为COMMIT来解决此问题.这是一个例子:

  1. public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername,String> {
  2.  
  3. @PersistenceContext
  4. private EntityManager em;
  5.  
  6. @Autowired
  7. UserService userService;
  8.  
  9. @Override
  10. public void initialize(UniqueUsername constraintAnnotation) {
  11. }
  12.  
  13. @Override
  14. public boolean isValid(String username,ConstraintValidatorContext context) {
  15. try {
  16. em.setFlushMode(FlushModeType.COMMIT);
  17. return userService.findByUsername(username) == null;
  18.  
  19. } finally {
  20. em.setFlushMode(FlushModeType.AUTO);
  21. }
  22. }
  23. }

解决了验证器使用finder函数触发hibernate flush的问题,而hibernate flush又触发了验证器导致StackOverflowError.

猜你在找的Java相关文章