現在讓我們更深入地研究Spring。 在本文中,我們將學習驗證從表單中獲取的數據。 讓我們更仔細地看一下驗證任務。
場景1 :我們可能需要驗證,例如,所提供的電子郵件確實確實看起來像一封電子郵件(以簡化的x @ xx格式顯示)。 這可以通過僅在電子郵件字段本身上運行一些腳本來完成。 那應該很簡單。 我們可以編寫一些可在瀏覽器本身上運行JavaScript。 并且還要在服務器端寫相同的驗證[為什么? 在這里閱讀 ]。 對于所有隔離的驗證都是如此,例如,檢查數據是否不為空,檢查數據是否為一定長度等。
場景2 :希望生活如此簡單。 由于我們正在討論電子郵件驗證,因此可以說其中一項驗證要求我們檢查電子郵件是否屬于某些域(例如合作伙伴組織),以便系統也可以通過電子郵件發送某些特權信息。 假設我們需要檢查電子郵件的格式為x @ partner1.com,x @ partner2.com或x@partner3.com。 可能很瑣碎,這是無法僅對表單本身的數據進行驗證的類型的示例。 無論驗證代碼是什么,它都需要知道哪些域有效。 并且此數據不存在于最終用戶以表格形式提供的數據中。 如果您稍微發揮想象力,則可以輕松地創建用例,其中可能需要業務規則引擎(例如,規則過于靈活)和/或可以引入國際化元素(例如,所有國家/地區的成年人年齡都未滿18歲) )或其他復雜性。 這些是非隔離的驗證,需要訪問同步可用的其他信息。 這些驗證可以在服務器端和客戶端都進行編碼,盡管可以說它將更多地依賴于服務器端。
場景3 :同樣,希望生活如此簡單。 如果我們處于驗證電子郵件的主題上,我們可能還需要檢查電子郵件是否有效,即它不是thisemail@doesnot.exist(我不確定該電子郵件是否存在-或在其中不存在未來-但您希望我能想到)。 我們將需要向該電子郵件ID發送一封電子郵件,并可能要求用戶單擊并確認。 我們需要通過SMTP與其他系統進行異步交互。 同樣,稍微依靠您的想象力,整個潘多拉盒子就會破裂。 很快,您將通過REST,SOAP,JMS,文件服務器進行集成,并通過分布式系統處理安全性和身份驗證問題。 我敢打賭,大多數系統都將在該領域中進行服務器端驗證,并且客戶端驗證(盡管在技術上是可行的)不會經常使用。
方案4 :而且我們還沒有違反相同的領域對象的問題,這些領域對象不僅從基于Web的表單填充,而且還從Feed文件,JMS消息等填充,因此需要將相同的驗證邏輯應用于多個渠道。 在本討論開始時,它最初是一個微不足道的小形式,帶有少量無辜的文本框,如今已演變為一個怪物。
幸運的是,JSR 303或Bean驗證[ 此處 ]可以拯救。 它立即解決了上述情況1和4。 它支持您解決方案2和3。我建議您閱讀標有“此標準對用戶有何好處?”的部分。 它會解決什么問題?” 在此鏈接 。
該Java規范于2006年提出要求,并于2009年底發布。 換句話說,可用的實現已經有機會在一年中成熟。 作為一流的開源公民,Spring 3使您可以使用此標準解決方案,而不必重新發明輪子。 而且,如果您絕對需要重新發明輪子(所有專業應用程序都需要編寫myAppSpecificKickAssValidator()),Spring也會允許這樣做。 讓我們一一看看這兩種情況。
將JSR 303支持添加到任何基于Maven的項目
JSR 303是一個開放的api。 您可以在此鏈接中找到它。 任何人都可以實現。 有hibernate和apache bval的實現。 讓我們一起進行Hibernate實現。 在此鏈接中,您可以在Maven Central看到他們的罐子。 在撰寫本文時,最新的穩定版本是4.3.0.Final。 您只需要在pom中添加此依賴項即可。 該實現也捆綁了api,因此您無需添加任何一個。
檔案:pom.xml
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> [...]
<hibernate.validation.version>4.3.0.Final</hibernate.validation.version> [...]
</properties> <!-- Hibernate validations -->
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate.validation.version}</version>
</dependency>
只需添加此依賴項,您就可以進入實體/表單類并聲明約束。 JSR 303有一些標準約束( 在此處列出 ),涵蓋了NotNull之類的標準檢查。 Hibernate添加了一些非標準的自定義約束[ 此處列出 ]。 它們不是標準的,但是非常方便,例如檢查有效的電子郵件。 讓我們在ContactFrm.java中介紹這兩項檢查。 如果您不知道那是從哪里來的,那么您很可能沒有閱讀本系列的上一篇文章,即使用Spring 3 MVC處理表單 。
文件:/org/academy/ui/spring3/forms/ContactFrm.java
package org.academy.ui.spring3.forms; import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.Email; public class ContactFrm { @NotNull private String firstname; private String lastname; @Email private String email; private String telephone; // Getter and setters omitted for brevity. [...]
}
單元測試
到目前為止,我們的ContactFrm bean沒有任何功能,因此我不費心進行單元測試(盡管TDD愛好者會對此表示懷疑)。 但是,現在僅通過添加幾個注釋,我們就為Bean添加了功能,并且可以進行單元測試(TDD愛好者可以從現在開始感到高興)。 讓我們添加一個單元測試。
文件:/src/test/java/org/academy/ui/spring3/forms/ContactFrmTest.java
package org.academy.ui.spring3.forms; import static org.junit.Assert.*; import java.util.Set; import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator; import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class ContactFrmTest { private final static Logger logger = LoggerFactory .getLogger(ContactFrmTest.class); private static Validator validator; @BeforeClass public static void init() { validator = Validation.buildDefaultValidatorFactory().getValidator(); } @Test public void test() { Set<ConstraintViolation<ContactFrm>> errors; ContactFrm contactFrm = new ContactFrm(); errors = validator.validate(contactFrm); printErrors(errors); // We are expecting 1 error here. // Just the NotNull. assertEquals(1, errors.size()); errors.clear(); contactFrm.setFirstname("partha"); errors = validator.validate(contactFrm); printErrors(errors); // We are not expecting any errors here. assertEquals(0, errors.size()); errors.clear(); contactFrm.setEmail("this can not be a valid email"); errors = validator.validate(contactFrm); printErrors(errors); // We are expecting 1 errors here. assertEquals(1, errors.size()); errors.clear(); contactFrm.setEmail("this@mightbevalid.email"); errors = validator.validate(contactFrm); printErrors(errors); // We are not expecting any errors here. assertEquals(0, errors.size()); errors.clear(); } // Utility function to print out errors from validation. private void printErrors(Set<ConstraintViolation<ContactFrm>> errors) { if (errors.size() > 0) { for (ConstraintViolation<ContactFrm> error : errors) { logger.debug(error.getMessage()); } } else { logger.debug("There were no errors to print."); } } }
您會發現我不需要使用任何Hibernate,Spring或JSR特定代碼進行單元測試。 它只是一個簡單的JUnit。 在我看來,只需添加幾個批注就可以在POJO上添加驗證,然后我可以使用標準的單元測試框架進行單元測試,而無需進行任何調整,這一事實是一個巨大的進步。 我們才剛剛開始。
單元測試–使用Spring功能。
當然,可以放心的是,我們可以在不依賴Spring的情況下完成完整的驗證和單元測試。 但是,如果我們不探索在網站上使用Spring將這些功能整合在一起有多么容易,我們將完全錯過本練習的重點。
首先,將所有必需的Spring依賴項添加到我們的項目中,并按照上一篇文章中的說明從公共記錄中刪除它們。
文件:/pom.xml
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions>
</dependency> [...] <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework.version}</version> <scope>test</scope> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions>
</dependency>
現在, 如上一篇文章中所述,在單元測試中添加@RunWith和@ContextConfiguration魔術。
文件:/src/test/java/org/academy/ui/spring3/forms/ContactFrmTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ContactFrmTest { private final static Logger logger = LoggerFactory .getLogger(ContactFrmTest.class); @Autowired private Validator validator; // This is no more required as Spring does it for us. // @BeforeClass // public static void init() { // validator = Validation.buildDefaultValidatorFactory().getValidator(); // }
[省略了其余代碼,因為它仍然相同。] 現在,剩下的就是讓我們告訴Spring應該在驗證器中自動裝配什么。 我們使用配置而不是代碼來做到這一點。
文件:/src/test/resources/org/academy/ui/spring3/forms/ContactFrmTest-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
</beans>
你們都準備好了。 您現在可以使用“ mvn -e clean install”來運行整個代碼并對其進行單元測試。 如果您覺得要求太高,可以使用“ mvn -e網站”創建一個不錯HTML網站,該網站將報告代碼覆蓋率。
:
- JSR 303的主頁
- Hibernate Validator主頁
- Hibernate Validation首席開發人員訪談– Emmanuel Bernard
- Spring關于驗證的官方文檔
參考:我們的JCG合作伙伴 Partho在Tech for Enterprise博客上使用Spring 3 MVC處理表單驗證
翻譯自: https://www.javacodegeeks.com/2012/08/handling-forms-with-spring-3-mvc.html