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