2016-11-01 50 views
3

有點貪心的問題在這裏,希望這一次也能幫助其他的誰想要知道更多關於註釋驗證春自定義註解驗證多個領域

我目前就讀的春天,現在來看,我打算嘗試自定義註釋驗證。

我尋覓了很多,現在我知道有主要有兩種驗證,一個用於控制,另一個是使用@Valid

的標註方法

因此,這裏是我的情況: 想我兩個或更多的字段,當它們是ALL NULL時可以爲空。 但是隻有當其中一個字段包含除空字符串以外的任何值時,這些字段才需要輸入。我有兩個想法,但沒有如何正確實施。

這裏的類示例:

public class Subscriber { 
    private String name; 
    private String email; 
    private Integer age; 
    private String phone; 
    private Gender gender; 
    private Date birthday; 
    private Date confirmBirthday; 
    private String birthdayMessage; 
    private Boolean receiveNewsletter; 

    //Getter and Setter 
} 

假設我想要的生日和confirmBirthday領域需要在兩個空或反對,我可能希望他們使用一個進行註解爲他們每個人看起來像這樣的:

public class Subscriber { 
    private String name; 
    private String email; 
    private Integer age; 
    private String phone; 
    private Gender gender; 

    @NotNullIf(fieldName="confirmBirthday") 
    private Date birthday; 

    @NotNullIf(fieldName="birthday") 
    private Date confirmBirthday; 

    private String birthdayMessage; 
    private Boolean receiveNewsletter; 

    //Getter and Setter 
} 

,所以我需要創建的驗證註解如下:

@Documented 
@Constraint(validatedBy = NotNullIfConstraintValidator.class) 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.METHOD, ElementType.FIELD }) 
public @interface NotNullIf { 

    String fieldName(); 

    String message() default "{NotNullIf.message}"; 
    Class<?>[] group() default {}; 
    Class<? extends Payload>[] payload() default {}; 
} 

之後,我將需要創建驗證本身:

public class NotNullIfConstraintValidator implements ConstraintValidator<NotNullIf, String>{ 

    private String fieldName; 

    public void initialize(NotNullIf constraintAnnotation) { 
     fieldName = constraintAnnotation.fieldName(); 
    } 

    public boolean isValid(String value, ConstraintValidatorContext context) { 
     if(value == null) { 
      return true; 
     }; 
     //TODO Validation 
     return false; 
    } 

} 

所以怎麼能說是可以實現的?

對於另一種使用相同Class的例子來說,我希望生日,confirmBirthday和birthdayMessdage只能同時爲null或反對。 我可能需要使用此類註釋驗證進行交叉字段驗證。

下面是如何假設其註釋類: @NotNullIf(fieldName的= { 「生日」, 「confirmBirthday」, 「birthdayMessage」}) 公共類訂戶{ //這些字段與上述相同一個 }

所以當其中一個字段不爲空時,其餘部分也需要在客戶端大小上輸入。 可能嗎?

我讀這篇文章:How to access a field which is described in annotation property

但我仍然在註釋驗證從我上面列出的那些元素是如何工作的混亂。 也許我需要一些關於該代碼的詳細解釋,或者更糟的是我可能需要一些基本的概念檢查。

請幫忙!

回答

2

爲此,您只能使用type level annotation,因爲字段級註釋無法訪問其他字段!

我做了類似的允許選擇驗證(正好有一個屬性必須不爲空)。在你的情況@AllOrNone註釋(或任何你喜歡的名字)將需要的字段名稱的數組,你會得到的註釋類型的整個對象的驗證:

@Target(ElementType.TYPE) 
@Retention(RUNTIME) 
@Documented 
@Constraint(validatedBy = AllOrNoneValidator.class) 
public @interface AllOrNone { 
    String[] value(); 

    String message() default "{AllOrNone.message}"; 
    Class<?>[] groups() default {}; 
    Class<? extends Payload>[] payload() default {}; 
} 

public class AllOrNoneValidator implements ConstraintValidator<AllOrNone, Object> { 
    private static final SpelExpressionParser PARSER = new SpelExpressionParser(); 
    private String[] fields; 

    @Override 
    public void initialize(AllOrNone constraintAnnotation) { 
     fields = constraintAnnotation.value(); 
    } 

    @Override 
    public boolean isValid(Object value, ConstraintValidatorContext context) { 
     long notNull = Stream.of(fields) 
       .map(field -> PARSER.parseExpression(field).getValue(value)) 
       .filter(Objects::nonNull) 
       .count(); 
     return notNull == 0 || notNull == fields.length; 
    } 
} 

(正如你說你使用Spring我二手規劃環境地政司,以允許甚至嵌套字段訪問)

現在你可以註解你Subscriber類型:

@AllOrNone({"birthday", "confirmBirthday"}) 
public class Subscriber { 
    private String name; 
    private String email; 
    private Integer age; 
    private String phone; 
    private Gender gender; 
    private Date birthday; 
    private Date confirmBirthday; 
    private String birthdayMessage; 
    private Boolean receiveNewsletter; 
} 
+0

還有什麼除了這個,我們需要以開始使用自定義註解呢? –

+0

@TusharBanne如果你有一個像hibernate validator這樣的正在運行的驗證框架,沒有 –

+0

嗨,我沒有使用任何驗證框架。 –