驗證邏輯(以及我的第一篇文章!)

工程 | Colin Yates | 2006年8月25日 | ...

大家好!

這是我上個月加入 Interface21 以來發布的第一篇文章。我之前的部落格現在已正式棄用,我將不再更新它。

那麼我第一篇文章的主題是什麼(除了自我介紹)?  驗證邏輯。  這不會是關於如何在 Spring 框架中執行驗證的演練,而是會討論我一個特別惱人的問題:)

我特別想討論的是,驗證邏輯中到底應該包含什麼。這似乎是一個顯而易見的答案;“用於驗證指定資料的邏輯”。好的,這確實是顯而易見的,但請繼續閱讀 :)。如您所知,Spring 框架透過 Errors Validator 介面為您提供了一個漂亮的驗證抽象層。特別是,Validator 是您將業務特定驗證規則應用於已填充的域物件的地方。Spring 卓越的繫結支援負責根據某些輸入更新您的域模型,而驗證器負責確保已填充的域模型在語義上是正確的。那麼我的困擾是什麼呢?我一次又一次地遇到一些應用程式,它們允許驗證邏輯從驗證器中流出,進入控制器(對於 Web 應用程式),甚至更糟的是進入中間層。在人們開始提出異議之前;我並不是說驗證不屬於中間層,我只是說 Validator 是放置驗證邏輯的地方!

最常見的例子是新增一個新實體,比如一個使用者。通常,驗證器會執行許多“簡單”檢查(欄位不能為空,文字欄位長度超過 25 個字元等)。控制器(例如)然後會呼叫中間層(userService.add(user))並捕獲 DuplicateKeyException(或強型別的 DuplicateUserException)異常。如果丟擲此異常,控制器將填充錯誤物件並重新顯示錶單。

那麼這張圖有什麼問題呢?很簡單,事實是某些驗證現在隱式地透過丟擲 DuplicateKeyException 來完成,表明驗證失敗了!。DB(在此示例中)在插入資料之前驗證資料以確保其唯一性,如果不唯一則丟擲異常。

我的觀點(我承認我說的很冗長 ;))是,這都是屬於 Validator 的驗證邏輯。將這種唯一性檢查移到驗證器中,它本就屬於那裡(!),可以帶來許多好處:

  • 這是一個更清晰、更直觀的實現;您會在哪裡尋找驗證邏輯?在驗證器中。
  • 驗證器實現現在是真正可重用的。以前,驗證器實際上只驗證了部分資料。
  • 對唯一使用者進行單元測試是在驗證單元測試中完成的。這比單元測試控制器容易得多,後者需要模擬 Errors、HttpServletRequest、HttpServletResponse(這實際上相當容易,但仍然……)等等。測試驗證器需要模擬的物件是 Errors 物件、DAO 和您的域模型。
  • 控制器中的 onSubmit 方法現在遵循 SimpleFormController 規定的契約(即它只在驗證成功時才被呼叫),因此程式碼更加清晰。
這不是什麼高深莫測的事情,但很多人就是不“明白”。我認為這可能是因為他們認為驗證器是驗證請求引數是否正確的地方。當然,您會在域模型本身上這樣做,但這仍然是他們的思維方式。事實並非如此。這完全是關於應用所有您的業務驗證規則。

注意:有一種觀點認為您正在重複驗證邏輯;資料庫知道什麼是唯一和不唯一的,那麼為什麼要將該邏輯複製到控制器中呢?好吧,關鍵是您確實在重複該邏輯,您正在使用丟擲 DuplicateXXXException 來指示驗證失敗,所以這並不是一個真正有效的論點。

還有另一種觀點認為,這不能 100% 保證捕獲所有(在這種情況下)重複鍵。這是事實。在呼叫驗證之後但在進行中間層呼叫之前,有一個很小的機會視窗,另一個程序可能會潛入並建立唯一行,但這是一個非常非常小的視窗(通常是毫秒),而且無論如何都可能會丟擲 OptimisticLockingException。還要考慮資料的性質。兩個不同的執行緒同時建立單個唯一實體的情況是極不可能的。如果確實發生了,沒關係。讓異常向上冒泡到容器,因為它現在確實是一個異常情況。

抱怨結束。

附註:我剩下的部落格文章可能也會同樣冗長 :)

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有