Spring3.1 對Bean Validation規範的新支持(方法級別驗證)

上接Spring提供的BeanPostProcessor的擴展點-1繼續學習。

 

一、Bean Validation框架簡介

 寫道
Bean Validation standardizes constraint definition, declaration and validation for the Java platform.

大體意思是:Bean Validation 標準化了Java平臺的約束定義、描述、和驗證。

 

詳細瞭解請參考:http://beanvalidation.org/

 

Bean Validation現在一個有兩個規範:

 

1、Bean Validation 1.0(JSR-303)

 寫道
This JSR will define a meta-data model and API for JavaBeanTM validation based on annotations, with overrides and extended meta-data through the use of XML validation descriptors.

定義了基於註解方式的JavaBean驗證元數據模型和API,也可以通過XML進行元數據定義,但註解將覆蓋XML的元數據定義。

 

詳細瞭解請參考:http://jcp.org/en/jsr/detail?id=303

 

JSR-303主要是對JavaBean進行驗證,如方法級別(方法參數/返回值)、依賴注入等的驗證是沒有指定的。因此又有了JSR-349規範的產生。

 

2、Bean Validation 1.1(JSR-349)

 寫道
Bean Validation standardizes constraint definition, declaration and validation for the Java platform.

Bean Validation 標準化了Java平臺的約束定義、描述、和驗證。

 

此規範目前處於草案狀態,詳細瞭解請參考:http://jcp.org/en/jsr/detail?id=349.

 

該草案現在主要內容:

方法級別驗證支持(驗證方法參數和和返回值);

依賴注入驗證的支持。

  

對Bean Validation的詳細介紹可參考Bean Validation官網查看http://beanvalidation.org/


Spring3.1目前已經完全支持依賴注入驗證和方法級別驗證的支持,只是不是原生的(規範還是草案)。


Bean Validation 1.0的參考實現有Hibernate Validator(下載地址:http://www.hibernate.org/subprojects/validator.html);1.1還處於草案狀態。

 

二、Bean Validation在開發中的位置


 


 

 

上圖摘自hibernate validator 參考文檔,從圖中可以看出,我們可以在任何位置實施驗證。

 

1、表現層驗證:SpringMVC提供對JSR-303的表現層驗證;

2、業務邏輯層驗證:Spring3.1提供對業務邏輯層的方法驗證(當然方法驗證可以出現在其他層,但筆者覺得方法驗證應該驗證業務邏輯);

3、DAO層驗證:Hibernate提供DAO層的模型數據的驗證(可參考hibernate validator參考文檔的7.3. ORM集成)。

4、數據庫端的驗證:通過數據庫約束來進行;

5、客戶端驗證支持:JSR-303也提供編程式驗證支持。

 

對於DAO層和客戶端驗證支持不在我們示例範圍,忽略,感興趣的同學可以參考《hibernate validator reference》(有中文)。

  

在測試支持大家需要準備好如下jar包:

validation-api-1.0.0.GA.jar

hibernate-validator-4.2.0.Final.jar

 

四、Spring3.0支持表現層驗證

可以參考我的《最新SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結》或《SpringMVC 使用JSR-303進行校驗 @Valid》。

 

此處不再闡述。

 

五、Spring3.0支持依賴注入驗證(Bean Validation 1.1草案)

Spring3.0開始支持對依賴注入的依賴進行驗證。Spring對依賴注入驗證支持請參考《Spring開閉原則的表現-BeanPostProcessor擴展點-2》中的BeanValidationPostProcessor。

 

示例:

1、Bean組件類定義

Java代碼  收藏代碼
  1. public class UserModel {  
  2.     @NotNull(message = "user.username.null")  
  3.     @Pattern(regexp = "[a-zA-Z0-9_]{5,10}", message = "user.username.illegal")  
  4.     private String username;  
  5.     @Size(min = 5, max=10, message = "password.length.illegal")  
  6.     private String password;  
  7.     //省略setter/getter  
  8. }  

 2、開啓依賴注入驗證支持(spring-config-bean-validator.xml)

Java代碼  收藏代碼
  1. <!--註冊Bean驗證後處理器-->  
  2. <bean class="org.springframework.validation.beanvalidation.BeanValidationPostProcessor"/>  

 3、Bean的XML配置定義(spring-config-bean-validator.xml)

Java代碼  收藏代碼
  1. <bean id="user" class="com.sishuok.validator.UserModel">  
  2.     <property name="username" value="@"/>  
  3.     <property name="password" value="#"/>  
  4. </bean>  

 4、測試用例

Java代碼  收藏代碼
  1. @RunWith(value = SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(value = {"classpath:spring-config-bean-validator.xml"})  
  3. public class BeanValidatorTest {  
  4.     @Autowired  
  5.     UserModel user;  
  6.     @Test  
  7.     public void test() {  
  8.     }  
  9. }  

 5、運行測試後,容器啓動失敗並將看到如下異常:

Java代碼  收藏代碼
  1. java.lang.IllegalStateException: Failed to load ApplicationContext  
  2. ……  
  3. Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'user' defined in class path resource [spring-config-bean-validator.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanInitializationException: Bean state is invalid: password - password.length.illegal; username - user.username.illegal  
  4. ……  
  5. Caused by: org.springframework.beans.factory.BeanInitializationException: Bean state is invalid: password - password.length.illegal; username - user.username.illegal  

 我們可以看出 用戶名驗證失敗。

 

六、Spring3.1支持方法級別驗證(Bean Validation 1.1草案)

Spring3.1開始支持方法級別的驗證。Spring對方法級別的驗證支持請參考《Spring開閉原則的表現-BeanPostProcessor擴展點-2》中的MethodValidationPostProcessor。

 

有了方法級別驗證,我們就能夠更加簡單的在Java世界進行契約式設計了,關於契約式設計請參考《建造無錯軟件:契約式設計引論》。

 

沒有MethodValidationPostProcessor之前我們可能這樣驗證:

Java代碼  收藏代碼
  1. public UserModel get(Integer uuid) {  
  2.     //前置條件  
  3.     Assert.notNull(uuid);  
  4.     Assert.isTrue(uuid > 0"uuid must lt 0");  
  5.   
  6.     //獲取 User Model  
  7.     UserModel user = new UserModel(); //此處應該從數據庫獲取  
  8.   
  9.     //後置條件  
  10.     Assert.notNull(user);  
  11.     return user;  
  12. }  

前置條件和後置條件的書寫是很煩人的工作。

 

有了MethodValidationPostProcessor之後我們可以這樣驗證:

Java代碼  收藏代碼
  1. public @NotNull UserModel get2(@NotNull @Size(min = 1) Integer uuid) {  
  2.     //獲取 User Model  
  3.     UserModel user = new UserModel(); //此處應該從數據庫獲取  
  4.     return user;  
  5. }  

 

前置條件的驗證:在方法的參數上通過Bean Validation註解進行實施;

後置條件的驗證:直接在返回值上通過Bean Validation註解進行實施。 

非常好,非常好,自此我們可以在Java世界進行更完美的契約式編程了。

 

示例:

1、Service類定義

Java代碼  收藏代碼
  1. @Validated      //① 告訴MethodValidationPostProcessor此Bean需要開啓方法級別驗證支持  
  2. public class UserService {  
  3.     public @NotNull UserModel get2(@NotNull @Min(value = 1) Integer uuid) { //②聲明前置條件/後置條件  
  4.         //獲取 User Model  
  5.         UserModel user = new UserModel(); //此處應該從數據庫獲取  
  6.         if(uuid > 100) {//方便後置添加的判斷(此處假設傳入的uuid>100 則返回null)  
  7.             return null;  
  8.         }  
  9.         return user;  
  10.     }  
  11. }  

 2、開啓Spring3.1對方法級別驗證支持(spring-config-method-validator.xml)

Java代碼  收藏代碼
  1. <!--註冊方法驗證的後處理器-->  
  2. <bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>  

 3、Bean的XML配置定義(spring-config-method-validator.xml)

Java代碼  收藏代碼
  1. <bean id="userService" class="com.sishuok.validator.UserService"/>  

 4、測試用例

Java代碼  收藏代碼
  1. @RunWith(value = SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(value = {"classpath:spring-config-method-validator.xml"})  
  3. public class MethodValidatorTest {  
  4.     @Autowired  
  5.     UserService userService;  
  6.     @Test  
  7.     public void testConditionSuccess() {//① 正常流程   
  8.         userService.get2(1);  
  9.     }  
  10.     @Test(expected = org.hibernate.validator.method.MethodConstraintViolationException.class)  
  11.     public void testPreCondtionFail() { //②錯誤的uuid(即前置條件不滿足)  
  12.         userService.get2(0);  
  13.     }  
  14.   
  15.     @Test(expected = org.hibernate.validator.method.MethodConstraintViolationException.class)  
  16.     public void testPostCondtionFail() { //③不滿足後置條件的返回值  
  17.         userService.get2(10000);  
  18.     }  
  19. }  

通過如上測試,我們可以看出Spring3.1已經非常好的支持契約式編程了。

 

注意,在使用方法級別驗證時:

1、由於Bean Validation1.1正處於草案狀態,Spring3.1無法支持原生的Bean Validation1.1,在未來的Bean Validation1.1發佈時會直接使用原生的。

2、Spring3.1需要使用Hibernate Validator 4.2及更高版本。

發佈了8 篇原創文章 · 獲贊 13 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章