Hibernate validation 註解 springmvc 驗證 分組

 

SpringMVC驗證框架Validation特殊用法

 

1. 分組java

有的時候,咱們對一個實體類須要有多中驗證方式,在不一樣的狀況下使用不一樣驗證方式,好比說對於一個實體類來的id來講,保存的時候是不須要的,對於更新時是必須的,能夠以下配置:git

[java]  view plain  copy
 
  1. public class UserModel {  
  2.   
  3.     @NotNull(message = "{id.empty}", groups = { First.class })  
  4.     private int id;  
  5.   
  6.     @NotNull(message = "{username.empty}", groups = { First.class, Second.class })  
  7.     private String username;  
  8.   
  9.     @NotNull(message = "{content.empty}", groups = { First.class, Second.class })  
  10.     private String content;  
  11.   
  12.     public int getId() {  
  13.         return id;  
  14.     }  
  15.   
  16.     public void setId(int id) {  
  17.         this.id = id;  
  18.     }  
  19.   
  20.     public String getUsername() {  
  21.         return username;  
  22.     }  
  23.   
  24.     public void setUsername(String username) {  
  25.         this.username = username;  
  26.     }  
  27.   
  28.     public String getContent() {  
  29.         return content;  
  30.     }  
  31.   
  32.     public void setContent(String content) {  
  33.         this.content = content;  
  34.     }  
  35. }  
  36. public interface First {  
  37. }  
  38.   
  39. public interface Second {  
  40. }  

經過 groups 對驗證進行分組正則表達式

在controler中的代碼以下:數組

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. @RequestMapping(value = "/save.action", method = RequestMethod.POST)  
  2. public String save(@Validated( { Second.class }) UserModel userModel, BindingResult result) {  
  3.     if (result.hasErrors()) {  
  4.         return "validate/error";  
  5.     }  
  6.     return "redirect:/success";  
  7. }  
  8.   
  9. @RequestMapping(value = "/update.action", method = RequestMethod.POST)  
  10. public String update(@Validated( { First.class, Second.class }) UserModel user, BindingResult result) {  
  11.     if (result.hasErrors()) {  
  12.         return "validate/error";  
  13.     }  
  14.     return "redirect:/success";  
  15. }  

2. 組序列app

默認狀況下,不一樣組別的約束驗證是無序的,然而在某些狀況下,約束驗證的順序卻很重要,以下面兩個例子:(1)第二個組中的約束驗證依賴於一個穩定狀態來運行,而這個穩定狀態是由第一個組來進行驗證的。(2)某個組的驗證比較耗時,CPU 和內存的使用率相對比較大,最優的選擇是將其放在最後進行驗證。所以,在進行組驗證的時候尚需提供一種有序的驗證方式,這就提出了組序列的概念。框架

一個組能夠定義爲其餘組的序列,使用它進行驗證的時候必須符合該序列規定的順序。在使用組序列驗證的時候,若是序列前邊的組驗證失敗,則後面的組將再也不給予驗證。ide

下例中聲明瞭組 GroupA.class,GroupB.class 和 Group.class,其中 default,GroupA,GroupB 均爲 Group 的序列。性能

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. public interface GroupA {  
  2. }  
  3.   
  4. public interface GroupB {  
  5. }  
  6.   
  7. @GroupSequence( { Default.class, GroupA.class, GroupB.class })  
  8. public interface Group {  
  9. }  
  10.   
  11. public class User {  
  12.     @NotEmpty(message = "firstname may be empty")  
  13.     private String firstname;  
  14.   
  15.     @NotEmpty(message = "middlename may be empty", groups = Default.class)  
  16.     private String middlename;  
  17.   
  18.     @NotEmpty(message = "lastname may be empty", groups = GroupA.class)  
  19.     private String lastname;  
  20.   
  21.     @NotEmpty(message = "country may be empty", groups = GroupB.class)  
  22.     private String country;  
  23. }  
[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. @RequestMapping(value = "/update.action", method = RequestMethod.POST)  
  2. public String register(@Validated(Group.class) User user, BindingResult result) {  
  3.     if (result.hasErrors()) {  
  4.         return "validate/error";  
  5.     }  
  6.     return "redirect:/success";  
  7. }  

3. 驗證多個對象測試

當咱們在一個功能處理方法上須要驗證多個模型對象時,須要經過以下形式來獲取驗證結果:this

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. @RequestMapping("/validate/multi")  
  2. public String multi(@Valid @ModelAttribute("a") A a, BindingResult aErrors, @Valid @ModelAttribute("b") B b, BindingResult bErrors) {  
  3.   
  4.     if (aErrors.hasErrors()) { //若是a模型對象驗證失敗  
  5.         return "validate/error";  
  6.     }  
  7.     if (bErrors.hasErrors()) { //若是a模型對象驗證失敗  
  8.         return "validate/error";  
  9.     }  
  10.     return "redirect:/success";  
  11. }  

每個模型對象後邊都須要跟一個Errors或BindingResult對象來保存驗證結果,其方法體內部可使用這兩個驗證結果對象來選擇出錯時跳轉的頁面或處理的邏輯。

4. Junit測試

當自定義拓展Validation時,可使用以下方法進行測試:

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. @Test  
  2. public void testValidate() {  
  3.     AnnotationDescriptor<EqualsAny> descriptor = new AnnotationDescriptor<EqualsAny>(EqualsAny.class);  
  4.     EqualsAny equalsAny = AnnotationFactory.create(descriptor);  
  5.     EqualsAnyValidator equalsAnyValidator = new EqualsAnyValidator();  
  6.     equalsAnyValidator.initialize(equalsAny);  
  7.     Assert.assertTrue(equalsAnyValidator.isValid("123", null));  
  8. }  

另外再講一點Spring對自定義JSR-303限制類型支持的新特性,那就是Spring支持往ConstraintValidator裏面注入bean對象。例如在EqualsAnyValidator中利用@Resource註解注入其餘Bean對象。

 

在使用Validation時,傳遞參數到國際化資源文件properties

 

 在CODE上查看代碼片派生到個人代碼片
  1. @NotEmpty(message="{password.empty.error}")  
  2. private String password;  

資源文件validation_zh_CN.properties中爲

[plain]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. password.empty.error=password不能爲空  

實際開發中,不少參數都是要驗證非空的,若是每一個參數都單獨加個錯誤描述,是很麻煩的。properties雖支持「{}」的寫法傳遞參數,但使用JSR-303註解沒法實現傳遞參數。我想了個辦法可經過自定義註解方式實現。

 

首先,創建個自定義的@NotEmpty註解:

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. package com.itkt.payment.core.annotation;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Retention;  
  5. import java.lang.annotation.RetentionPolicy;  
  6. import java.lang.annotation.Target;  
  7.   
  8. import javax.validation.Constraint;  
  9. import javax.validation.Payload;  
  10.   
  11. import com.itkt.payment.core.handler.NotEmptyValidator;  
  12.   
  13. @Retention(RetentionPolicy.RUNTIME)  
  14. @Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER })  
  15. @Constraint(validatedBy = { NotEmptyValidator.class })  
  16. public @interface NotEmpty {  
  17.   
  18.     String field() default "";  
  19.   
  20.     String message() default "{com.itkt.payment.core.handler.NotEmpty.message}";  
  21.   
  22.     Class<?>[] groups() default {};  
  23.   
  24.     Class<? extends Payload>[] payload() default {};  
  25. }  

自定義的NotEmpty註解中,咱們新加了field字段,用於標識字段名稱。

而後,創建NotNullValidator實現類:

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. package com.itkt.payment.core.handler;  
  2.   
  3. import javax.validation.ConstraintValidator;  
  4. import javax.validation.ConstraintValidatorContext;  
  5.   
  6. import com.itkt.payment.core.annotation.NotNull;  
  7.   
  8. public class NotNullValidator implements ConstraintValidator<NotNull, Object> {  
  9.   
  10.     @Override  
  11.     public void initialize(NotNull annotation) {  
  12.     }  
  13.   
  14.     @Override  
  15.     public boolean isValid(Object str, ConstraintValidatorContext constraintValidatorContext) {  
  16.         return str != null;  
  17.     }  
  18.   
  19. }  

以後,在資源文件validation_zh_CN.properties中,改變寫法:

[plain]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. password.empty.error={field}不能爲空  

最後,咱們就能夠在User類中使用自定義的NotEmpty註解:

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. @NotEmpty(field = "password", message = "{password.empty.error}")  
  2. private String password;  

 

實際上,國際化資源文件自己支持從JSR-303註解中獲取屬性的參數值的,例如從@Length註解中,獲取min和max屬性的值:

[plain]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. username.length.error=用戶名長度必須在{min}-{max}之間  

之因此自帶的@NotEmpty註解沒法實現,是由於沒有一個屬性能傳遞字段名,因此經過自定義@NotEmpty註解來拓展個field字段。

 
 
@AssertTrue   //用於boolean字段,該字段只能爲true   
@AssertFalse //該字段的值只能爲false   
@CreditCardNumber //對信用卡號進行一個大體的驗證   
@DecimalMax //只能小於或等於該值   
@DecimalMin //只能大於或等於該值   
@Digits (integer= 2 ,fraction= 20 ) //檢查是不是一種數字的整數、分數,小數位數的數字。   
@Email //檢查是不是一個有效的email地址   
@Future //檢查該字段的日期是不是屬於未來的日期   
@Length (min=,max=) //檢查所屬的字段的長度是否在min和max之間,只能用於字符串   
@Max //該字段的值只能小於或等於該值   
@Min //該字段的值只能大於或等於該值   
@NotNull //不能爲null   
@NotBlank //不能爲空,檢查時會將空格忽略   
@NotEmpty //不能爲空,這裏的空是指空字符串   
@Null //檢查該字段爲空   
@Past //檢查該字段的日期是在過去   
@Size (min=, max=) //檢查該字段的size是否在min和max之間,能夠是字符串、數組、集合、Map等   
@URL (protocol=,host,port) //檢查是不是一個有效的URL,若是提供了protocol,host等,則該URL還需知足提供的條件   
@Valid //該註解只要用於字段爲一個包含其餘對象的集合或map或數組的字段,或該字段直接爲一個其餘對象的引用,   
       //這樣在檢查當前對象的同時也會檢查該字段所引用的對象   如下是分類 Bean Validation 中內置的 constraint   @Null     被註釋的元素必須爲 null @NotNull     被註釋的元素必須不爲 null @AssertTrue     被註釋的元素必須爲 true @AssertFalse     被註釋的元素必須爲 false @Min(value)     被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 @Max(value)     被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 @DecimalMin(value)     被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 @DecimalMax(value)     被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 @Size(max=, min=)     被註釋的元素的大小必須在指定的範圍內 @Digits (integer, fraction)     被註釋的元素必須是一個數字,其值必須在可接受的範圍內 @Past     被註釋的元素必須是一個過去的日期 @Future     被註釋的元素必須是一個未來的日期 @Pattern(regex=,flag=)     被註釋的元素必須符合指定的正則表達式 Hibernate Validator 附加的 constraint @NotBlank(message =)   驗證字符串非null,且長度必須大於0 @Email     被註釋的元素必須是電子郵箱地址 @Length(min=,max=)     被註釋的字符串的大小必須在指定的範圍內 @NotEmpty     被註釋的字符串的必須非空 @Range(min=,max=,message=)     被註釋的元素必須在合適的範圍內
相關文章
相關標籤/搜索