1

我使用spring 3.1和hibernate validator 4.2。我观察到,休眠验证被调用两次: 一个在控制器级别当我使用类似的方法:Hibernate bean验证问题

@RequestMapping(method = RequestMethod.POST) 
    public String onSubmit(@Valid User user, BindingResult result) {....} 

而当实体持续为部分第2次:

org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(..) 
org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreUpdate(..) 
org.hibernate.action.EntityUpdateAction.preUpdate(..) 

我相信,这使更有意义在控制器级别有效并显示带错误消息的错误页面。无论如何,在流程中做两次相同的验证并不好。 我发现在休眠文档中可以通过在休眠配置中将hibernate.validator.autoregister_listeners设置为false来关闭它,但不建议这样做。

那么什么是验证的推荐方法?同样在我的特殊情况下,第二次验证会导致麻烦,因为我有一个字段'confirmPassword',这是用户提交表单时所需的验证字段,但在表格中并不需要,所以无论何时我必须保存,更新用户,我必须不必要地设置confirmPassword字段通过验证。

回答

1

验证不是一件容易的事情,尽管出现。

前端验证适用于填充表单的用户,并且可以从视图更改为另一个视图(例如不同的消息)。视图中必填字段的消息应该是“该字段是强制性的!”,在实体持久存储的后端中:“字段不能为空”。

后端验证应该总是当一个类被保存发生,考虑INFACT一个持久实体可以被保存在不脱离视图传递(例如从来自一个web服务或从队列ORA另一个源接收数据的批量..)。

如果您在实体级别添加了验证注释,那么您在该类上执行的合约独立于该类在视图中已使用或未使用的事实。

ConfirmPassword是一个视图字段,所以我认为不应该作为字段在实体中存在(例如,我用JSF开发了一个类似的案例,我把ConfirmPassword放在与该视图相关的ManagedBean中,而不是在实体中,该实体仅包含密码字段)。

因此总结我认为是正确的做两次'相同'的验证。

+0

因此,你建议我应该有两个pojo bean一个用户窗体进行视图验证和其他用户保存到数据库。而且我在两者上都有验证注释。其中很常见的例子是,一个单独的bean既用于jsp form也用于保存到数据库,从而节省了用于将字段从一个bean复制到另一个的代码。这是一种不好的做法吗? – user1694519

+0

..根据我的经验,并非(总是)有可能为视图和数据库创建一个类,考虑到在视图中并不罕见的是来自许多持久实体的当前字段(我称之为域视图上的'视图' ),而且(和你的情况一样,confirmPassword)有些字段没有持久性。在我的例子中,有一个bean(userForm)持有持久化类bean(有时候指的是更持久的bean):在我的例子中,confirmPassword/confirmEmail位于'表单bean'中,并且字段密码/电子邮件位于“实体”(永久性bean)中。 – obe6

+0

嗯,是的,你说的话对于使用两类物品VO和DTO来说是非常有意义的。我觉得代码中会有很多语句,如'user.setEmail(userForm.getEmail())',这看起来不太好。据我记得,即使春天roo生成代码使用相同的类视图和分贝。 – user1694519

0

一切都取决于用例,并在一定程度上对个人的品味。 @ obe6建议两个独立的bean,这在某些情况下可能有用,但在其他情况下不会。关于confirmPassword字段,您始终可以在实体中将其标记为@Transient,以便该值不会持续存在。

就我个人而言,我可能会通过@Valid禁用Spring验证,因为它不是标准的。另一方面JPA生命周期事件的Bean验证是。我想这是另一个味道的问题。虽然两者似乎都没有必要。

+0

它已经标记为瞬态,但验证器仍然会抛出违反约束的标记为NotEmpty。所以迄今为止最好的方法似乎有两个独立的bean(表单和实体),并为它们之间的覆盖编写代码,这不太好。尽管如此,仍然在等待更好的方法。 – user1694519

+0

在持续时(当事件触发时)应该设置和验证字段。我想你的问题发生在你加载实体时,然后改变并再次坚持它。一种解决方案是在实体加载时设置_confirmPassword_字段。例如,通过_ @ PostLoad_。 – Hardy

+0

是的,使用'@ PostLoad'来设置这种仅查看字段是很好的解决方法。 – user1694519