java – @Autowired bean在控制器上与@Valid一起使用但在CRUD存
我正在使用用户注册表单处理
Spring MVC Hibernate JPA应用程序,我决定使用JSR-303验证程序检查用户名是否已存在于DB中:
public class UniqueUsernameValidator implements ConstraintValidator<VerifyUniqueUsername,String> { @Autowired UserService userService; @Override public void initialize(VerifyUniqueUsername constraintAnnotation) { } @Override public boolean isValid(String username,ConstraintValidatorContext context) { return username!=null && userService.findByUsername(username) == null; } } 它非常简单,验证在我的控制器上运行良好: .... public String signup(@Valid @ModelAttribute("newUser") User user,BindingResult newUserBeanResult) ..... 我面临的当前问题是,在我验证了User对象之后,我调用了: userService.save(user); 哪个实现了CrudRepository,我得到一个NullPointerException.出于某种原因,UserService在控制器上的验证期间注入,但在调用CrudRepository.save()时则不会. 我看到类似的帖子如下: 作为一种解决方法,我在userService上添加了一个null检查,但感觉不对. >这是预期的行为吗?在调用CrudRepository.save()之前,这些验证是否会被激活? 解决方法
我最终通过指示Spring的EntityManagerFactoryBean使用我的验证器bean来解决这个问题(更准确地说,hibernate现在将使用Spring的验证器):
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> </property> <property name="packagesToScan" value="some.packages"/> <property name="jpaPropertyMap"> <map> <entry key="javax.persistence.validation.factory" value-ref="validator" /> </map> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.max_fetch_depth">3</prop> <prop key="hibernate.jdbc.fetch_size">50</prop> <prop key="hibernate.jdbc.batch_size">10</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> 但是,这引发了StackOverflow错误:) 显然,这个问题的原因是我的验证器使用了finder方法(findByUsername),finder方法触发了hibernate flush,后者又触发了验证.这无限循环,直到你得到最着名的例外. 所以…我通过更改验证器直接使用EntityManager(而不是CRUD存储库)并暂时将FlushModeType更改为COMMIT来解决此问题.这是一个例子: public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername,String> { @PersistenceContext private EntityManager em; @Autowired UserService userService; @Override public void initialize(UniqueUsername constraintAnnotation) { } @Override public boolean isValid(String username,ConstraintValidatorContext context) { try { em.setFlushMode(FlushModeType.COMMIT); return userService.findByUsername(username) == null; } finally { em.setFlushMode(FlushModeType.AUTO); } } } 这解决了验证器使用finder函数触发hibernate flush的问题,而hibernate flush又触发了验证器导致StackOverflowError. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |