一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Spring 驗(yàn)證(創(chuàng)建自定義JSR303的驗(yàn)證約束(Creating custom constraints) )

 windli筆記 2012-10-07

由于輸入驗(yàn)證在軟件開(kāi)發(fā)中是必須的一件事情,特別是與用戶交互的軟件產(chǎn)品,驗(yàn)證用戶的潛在輸入錯(cuò)誤是必不可少的一件事情,然而各種開(kāi)源的驗(yàn) 證框架也很多,為了一統(tǒng)標(biāo)準(zhǔn),jsr303規(guī)范橫空出世了,它定義了一些標(biāo)準(zhǔn)的驗(yàn)證約束,標(biāo)準(zhǔn)畢竟是標(biāo)準(zhǔn),它不可能定義到所有的驗(yàn)證約束,它只是提供了一 些基本的常用的約束,不過(guò)它提供了一個(gè)可拓展的自定義驗(yàn)證約束。下面就來(lái)說(shuō)說(shuō)怎么樣自定義一個(gè)約束.

      為了創(chuàng)建一個(gè)自定義約束,以下三個(gè)步驟是必須的。
Create a constraint annotation (首先定義一個(gè)約束注解)
Implement a validator(第二步是實(shí)現(xiàn)這個(gè)驗(yàn)證器)
Define a default error message(最后添加一條默認(rèn)的錯(cuò)誤消息即可)

    假定有這么一個(gè)要求,要驗(yàn)證用戶的兩次輸入密碼必須是相同的,非常常見(jiàn)的一個(gè)要求。下面就基于這個(gè)要求來(lái)自定義一個(gè)約束。

Java代碼  收藏代碼
  1. package org.leochen.samples;  
  2.   
  3. import javax.validation.Constraint;  
  4. import javax.validation.Payload;  
  5. import java.lang.annotation.*;  
  6.   
  7. /** 
  8.  * User: leochen 
  9.  * Date: 11-12-8 
  10.  * Time: 下午11:31 
  11.  */  
  12.   
  13. @Target({ElementType.TYPE,ElementType.ANNOTATION_TYPE})  
  14. @Retention(RetentionPolicy.RUNTIME)  
  15. @Constraint(validatedBy = MatchesValidator.class)  
  16. @Documented  
  17. public @interface Matches {  
  18.     String message() default "{constraint.not.matches}";  
  19.     Class<?>[] groups() default {};  
  20.     Class<? extends Payload>[] payload() default {};  
  21.   
  22.     String field();  
  23.     String verifyField();  
  24. }  

 從上到下來(lái)說(shuō)吧,@Target表示注解可出現(xiàn)在哪些地方,比如可以出現(xiàn)在class上,field,method,又或者是在另外一個(gè) annotation上,這里限制只能出現(xiàn)在類(lèi)和另外一個(gè)注解上,@Retention表示該注解的保存范圍是哪里,RUNTIME表示在源碼 (source)、編譯好的.class文件中保留信息,在執(zhí)行的時(shí)候會(huì)把這一些信息加載到JVM中去的.@Constraint比較重要,表示哪個(gè)驗(yàn)證 器提供驗(yàn)證。@interface表明這是一個(gè)注解,和class一樣都是關(guān)鍵字,message(),groups()和payload()這三個(gè)方法 是一個(gè)標(biāo)準(zhǔn)的約束所具備的,其中message()是必須的,{constraint.not.matches}表示該消息是要插值計(jì)算的,也就是說(shuō)是要 到資源文件中尋找這個(gè)key的,如果不加{}就表示是一個(gè)普通的消息,直接文本顯示,如果消息中有需要用到{或}符號(hào)的,需要進(jìn)行轉(zhuǎn)義,用\{和\}來(lái)表 示。groups()表示該約束屬于哪個(gè)驗(yàn)證組,在驗(yàn)證某個(gè)bean部分屬性是特別有用(也說(shuō)不清了,具體可以查看Hibernate Validator的文檔細(xì)看) default必須是一個(gè)類(lèi)型為Class<?>[]的空數(shù)組,attribute payload that can be used by clients of the Bean Validation API to assign custom payload objects to a constraint. This attribute is not used by the API itself.下面連個(gè)字段是我們添加進(jìn)去的,表示要驗(yàn)證字段的名稱,比如password和confirmPassword.

    下面就來(lái)實(shí)現(xiàn)這個(gè)約束。

Java代碼  收藏代碼
  1. package org.leochen.samples;  
  2.   
  3. import org.apache.commons.beanutils.BeanUtils;  
  4.   
  5. import javax.validation.ConstraintValidator;  
  6. import javax.validation.ConstraintValidatorContext;  
  7. import java.lang.reflect.InvocationTargetException;  
  8.   
  9. /** 
  10.  * User: leochen 
  11.  * Date: 11-12-8 
  12.  * Time: 下午11:39 
  13.  */  
  14. public class MatchesValidator implements ConstraintValidator<Matches,Object>{  
  15.     private String field;  
  16.     private String verifyField;  
  17.   
  18.     public void initialize(Matches matches) {  
  19.         this.field = matches.field();  
  20.         this.verifyField = matches.verifyField();  
  21.     }  
  22.   
  23.     public boolean isValid(Object value, ConstraintValidatorContext context) {  
  24.         try {  
  25.             String fieldValue= BeanUtils.getProperty(value,field);  
  26.             String verifyFieldValue = BeanUtils.getProperty(value,verifyField);  
  27.             boolean valid = (fieldValue == null) && (verifyFieldValue == null);  
  28.             if(valid){  
  29.                 return true;  
  30.             }  
  31.   
  32.             boolean match = (fieldValue!=null) && fieldValue.equals(verifyFieldValue);  
  33.             if(!match){  
  34.                 String messageTemplate = context.getDefaultConstraintMessageTemplate();  
  35.                 context.disableDefaultConstraintViolation();  
  36.                 context.buildConstraintViolationWithTemplate(messageTemplate)  
  37.                         .addNode(verifyField)  
  38.                         .addConstraintViolation();  
  39.             }  
  40.             return match;  
  41.         } catch (IllegalAccessException e) {  
  42.             e.printStackTrace();  
  43.         } catch (InvocationTargetException e) {  
  44.             e.printStackTrace();  
  45.         } catch (NoSuchMethodException e) {  
  46.             e.printStackTrace();  
  47.         }  
  48.         return true;  
  49.     }  
  50. }  

 

我們必須要實(shí)現(xiàn)ConstraintValidator這個(gè)接口,下面就來(lái)具體看看這個(gè)接口是怎么定義的吧:

Java代碼  收藏代碼
  1. package javax.validation;  
  2.   
  3. import java.lang.annotation.Annotation;  
  4.   
  5. public interface ConstraintValidator<A extends Annotation, T> {  
  6.     /** 
  7.      * Initialize the validator in preparation for isValid calls. 
  8.      * The constraint annotation for a given constraint declaration 
  9.      * is passed. 
  10.      * <p/> 
  11.      * This method is guaranteed to be called before any use of this instance for 
  12.      * validation. 
  13.      * 
  14.      * @param constraintAnnotation annotation instance for a given constraint declaration 
  15.      */  
  16.     void initialize(A constraintAnnotation);  
  17.   
  18.     /** 
  19.      * Implement the validation logic. 
  20.      * The state of <code>value</code> must not be altered. 
  21.      * 
  22.      * This method can be accessed concurrently, thread-safety must be ensured 
  23.      * by the implementation. 
  24.      * 
  25.      * @param value object to validate 
  26.      * @param context context in which the constraint is evaluated 
  27.      * 
  28.      * @return false if <code>value</code> does not pass the constraint 
  29.      */  
  30.     boolean isValid(T value, ConstraintValidatorContext context);  
  31. }  

 

 A 表示邊界范圍為java.lang.annotation.Annotation即可,這個(gè)T參數(shù)必須滿足下面兩個(gè)限制條件:

  • T must resolve to a non parameterized type (T 必須能被解析為非參數(shù)化的類(lèi)型,通俗講就是要能解析成具體類(lèi)型,比如Object,Dog,Cat之類(lèi)的,不能是一個(gè)占位符)
  • or generic parameters of T must be unbounded wildcard types(或者也可以是一個(gè)無(wú)邊界范圍含有通配符的泛型類(lèi)型)

我們?cè)?code>initialize (A  constraintAnnotation) 方法中獲取到要驗(yàn)證的兩個(gè)字段的名稱,在isValid方法中編寫(xiě)驗(yàn)證規(guī)則。

Java代碼  收藏代碼
  1. String fieldValue= BeanUtils.getProperty(value,field);  
  2. String verifyFieldValue = BeanUtils.getProperty(value,verifyField);  

 

以上是我們把驗(yàn)證出錯(cuò)的消息放在哪個(gè)字段上顯示,一般我們是在確認(rèn)密碼上顯示密碼不一致的消息。

好了這樣我們的自定義約束就完成了,下面來(lái)使用并測(cè)試吧。

假如我們要驗(yàn)證這么一個(gè)formbean

Java代碼  收藏代碼
  1. package org.leochen.samples;  
  2.   
  3. /** 
  4.  * User: leochen 
  5.  * Date: 11-12-20 
  6.  * Time: 下午4:04 
  7.  */  
  8. @Matches(field = "password", verifyField = "confirmPassword",  
  9.                  message = "{constraint.confirmNewPassword.not.match.newPassword}")  
  10. public class TwoPasswords {  
  11.     private String password;  
  12.     private String confirmPassword;  
  13.   
  14.     public String getPassword() {  
  15.         return password;  
  16.     }  
  17.   
  18.     public void setPassword(String password) {  
  19.         this.password = password;  
  20.     }  
  21.   
  22.     public String getConfirmPassword() {  
  23.         return confirmPassword;  
  24.     }  
  25.   
  26.     public void setConfirmPassword(String confirmPassword) {  
  27.         this.confirmPassword = confirmPassword;  
  28.     }  
  29. }    

 

在路徑下放入我們的資源文件:ValidationMessages.properties(名字必須叫這個(gè),不然你就費(fèi)好大一番勁,何苦呢是不是,基于約定來(lái))

Java代碼  收藏代碼
  1. javax.validation.constraints.AssertFalse.message = must be false  
  2. javax.validation.constraints.AssertTrue.message  = must be true  
  3. javax.validation.constraints.DecimalMax.message  = must be less than or equal to {value}  
  4. javax.validation.constraints.DecimalMin.message  = must be greater than or equal to {value}  
  5. javax.validation.constraints.Digits.message      = numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)  
  6. javax.validation.constraints.Future.message      = must be in the future  
  7. javax.validation.constraints.Max.message         = must be less than or equal to {value}  
  8. javax.validation.constraints.Min.message         = must be greater than or equal to {value}  
  9. javax.validation.constraints.NotNull.message     = may not be null  
  10. javax.validation.constraints.Null.message        = must be null  
  11. javax.validation.constraints.Past.message        = must be in the past  
  12. javax.validation.constraints.Pattern.message     = must match "{regexp}"  
  13. javax.validation.constraints.Size.message        = size must be between {min} and {max}  
  14.   
  15. org.hibernate.validator.constraints.CreditCardNumber.message = invalid credit card number  
  16. org.hibernate.validator.constraints.Email.message            = not a well-formed email address  
  17. org.hibernate.validator.constraints.Length.message           = length must be between {min} and {max}  
  18. org.hibernate.validator.constraints.NotBlank.message         = may not be empty  
  19. org.hibernate.validator.constraints.NotEmpty.message         = may not be empty  
  20. org.hibernate.validator.constraints.Range.message            = must be between {min} and {max}  
  21. org.hibernate.validator.constraints.SafeHtml.message         = may have unsafe html content  
  22. org.hibernate.validator.constraints.ScriptAssert.message     = script expression "{script}" didn't evaluate to true  
  23. org.hibernate.validator.constraints.URL.message              = must be a valid URL  
  24.   
  25.   
  26.   
  27. ## custom constraints  
  28.   
  29. constraint.not.matches=two fields not matches  
  30. constraint.confirmNewPassword.not.match.newPassword=two password not the same  

 

 單元測(cè)試如下:

Java代碼  收藏代碼
  1. package org.leochen.samples;  
  2.   
  3. import org.junit.BeforeClass;  
  4. import org.junit.Test;  
  5.   
  6. import javax.validation.ConstraintViolation;  
  7. import javax.validation.Validation;  
  8. import javax.validation.Validator;  
  9. import javax.validation.ValidatorFactory;  
  10.   
  11. import java.util.Set;  
  12.   
  13. import static junit.framework.Assert.assertEquals;  
  14. import static junit.framework.Assert.assertNotNull;  
  15.   
  16. /** 
  17.  * User: leochen 
  18.  * Date: 11-12-20 
  19.  * Time: 下午4:06 
  20.  */  
  21. public class TwoPasswordsTest {  
  22.     private static Validator validator;  
  23.   
  24.     @BeforeClass  
  25.     public static void setUp() {  
  26.         ValidatorFactory factory = Validation.buildDefaultValidatorFactory();  
  27.         validator = factory.getValidator();  
  28.     }  
  29.   
  30.   
  31.     @Test  
  32.     public void testBuildDefaultValidatorFactory() {  
  33.         ValidatorFactory factory = Validation.buildDefaultValidatorFactory();  
  34.         Validator validator = factory.getValidator();  
  35.   
  36.         assertNotNull(validator);  
  37.     }  
  38.   
  39.     @Test  
  40.     public void testPasswordEqualsConfirmPassword() {  
  41.         TwoPasswords bean = new TwoPasswords();  
  42.         bean.setPassword("110");  
  43.         bean.setConfirmPassword("110");  
  44.   
  45.         Set<ConstraintViolation<TwoPasswords>> constraintViolations = validator.validate(bean);  
  46.         for (ConstraintViolation<TwoPasswords> constraintViolation : constraintViolations) {  
  47.             System.out.println(constraintViolation.getMessage());  
  48.         }  
  49.   
  50.         assertEquals("newPassword and confirmNewPassword should be the same."0, constraintViolations.size());  
  51.     }  
  52.   
  53.     @Test  
  54.     public void testPasswordNotEqualsConfirmPassword() {  
  55.         TwoPasswords bean = new TwoPasswords();  
  56.         bean.setPassword("110");  
  57.         bean.setConfirmPassword("111");  
  58.   
  59.         Set<ConstraintViolation<TwoPasswords>> constraintViolations = validator.validate(bean);  
  60.   
  61.         assertEquals(1, constraintViolations.size());  
  62.         assertEquals("two password not the same", constraintViolations.iterator().next().getMessage());  
  63.     }  
  64.   
  65.     @Test  
  66.     public void testIfTwoPasswordWereNullShouldPast() {  
  67.         TwoPasswords bean = new TwoPasswords();  
  68.         bean.setPassword(null);  
  69.         bean.setConfirmPassword(null);  
  70.   
  71.         Set<ConstraintViolation<TwoPasswords>> constraintViolations = validator.validate(bean);  
  72.   
  73.         assertEquals(0, constraintViolations.size());  
  74.     }  
  75.   
  76.     @Test  
  77.     public void testIfOneIsNullAndOtherIsNotShouldNotPast() {  
  78.         TwoPasswords bean = new TwoPasswords();  
  79.         bean.setPassword(null);  
  80.         bean.setConfirmPassword("110");  
  81.   
  82.         Set<ConstraintViolation<TwoPasswords>> constraintViolations = validator.validate(bean);  
  83.   
  84.         assertEquals(1, constraintViolations.size());  
  85.         assertEquals("two password not the same", constraintViolations.iterator().next().getMessage());  
  86.     }  
  87. }  

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多

    日本妇女高清一区二区三区| 午夜福利视频日本一区| 2019年国产最新视频| 免费观看在线午夜视频| 欧美三级不卡在线观线看| 扒开腿狂躁女人爽出白浆av| 免费在线播放不卡视频| 欧美午夜一级艳片免费看| 亚洲精品国产第一区二区多人| 国产亚洲二区精品美女久久 | 91天堂素人精品系列全集| 大香蕉精品视频一区二区| 风韵人妻丰满熟妇老熟女av| 欧美日韩综合在线精品| 国产欧美精品对白性色| 日韩美女偷拍视频久久| 久久亚洲精品成人国产| 国产欧美另类激情久久久| 国产av大片一区二区三区| 夫妻激情视频一区二区三区| 国产又粗又猛又爽又黄| 亚洲av首页免费在线观看| 久热这里只有精品九九| 国产精品一区日韩欧美| 国产午夜福利片在线观看| 国产情侣激情在线对白| 亚洲欧洲一区二区中文字幕| 午夜精品国产一区在线观看| 99视频精品免费视频| 超碰在线播放国产精品| 日韩一区二区三区高清在| 一区二区三区免费公开| 午夜国产成人福利视频| 日韩精品一区二区三区含羞含羞草| 日本深夜福利视频在线| 国产精品福利一二三区| 在线观看欧美视频一区| 久久福利视频在线观看| 国产精品欧美一区两区| 国产又色又爽又黄的精品视频| 国产亚洲精品俞拍视频福利区|