Uli*_*ses 8 java spring spring-mvc
我正在使用用户注册表单处理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;
}
}
Run Code Online (Sandbox Code Playgroud)
这非常简单,验证在我的控制器上运行良好:
....
public String signup(@Valid @ModelAttribute("newUser") User user, BindingResult newUserBeanResult)
.....
Run Code Online (Sandbox Code Playgroud)
我面临的当前问题是,在我User验证对象后,我打电话:
userService.save(user);
Run Code Online (Sandbox Code Playgroud)
哪个实现CrudRepository,我得到了NullPointerException.出于某种原因,UserService验证过程中被注入的控制器上,但不是当我打电话CrudRepository.save().
我看到了类似的帖子: 当Sessionfactory.getCurrentSession.merge调用时,在ConstraintValidator中@Autowired bean null ,这个: hibernate验证器没有使用autowire, 但我想知道是否有人遇到过这个问题.我认为注入bean来访问验证器上的数据库是相当普遍的.
作为一种解决方法,我添加了一个null的检查,userService但感觉不对.
CrudRepository.save()?pre-insert我最终通过指示 SpringEntityManagerFactoryBean使用我的验证器 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>
Run Code Online (Sandbox Code Playgroud)
然而,这引发了 StackOverflow 错误:)
显然,这个问题的原因是我的验证器使用了 finder 方法 ( findByUsername),并且 finder 方法触发了休眠刷新,从而触发了验证。这个过程无限循环,直到你得到最著名的异常。
所以...我通过更改验证器直接使用 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这解决了验证器使用 finder 函数触发休眠刷新进而触发验证器导致 StackOverflowError 的问题。
| 归档时间: |
|
| 查看次数: |
2485 次 |
| 最近记录: |