1. 程式人生 > >自定義註解驗證引數

自定義註解驗證引數

使用註解去驗證某個物件屬性是否按照我們的註解來賦值的。

例子:我們需要定義一個MyLimit的註解,這個註解裡面規定了類屬性的限制;編寫註解解析;在類中屬性使用註解;最後測試是否是我們需要的效果。

定義MyLimit註解:

[java] view plain copy print?
  1. @Target({ ElementType.FIELD })  
  2. // 標註只能放在類或介面的註解
  3. @Retention(RetentionPolicy.RUNTIME)  
  4. // 在執行時有效
  5. public@interface MyLimit {  
  6.     //這個欄位是否為必填
  7.     boolean isNotNull() default
    false;  
  8.     // 欄位描述
  9.     String description() default“”;  
  10.     int MaxLength() default0;  
  11.     int MinLength() default0;  
  12.     //表示這個欄位是否為int型別
  13.     boolean isInt() defaultfalse;  
  14.     int MaxNum() default30;  
  15.     int MinNum() default18;  
  16. }  
@Target({ ElementType.FIELD })
// 標註只能放在類或介面的註解
@Retention(RetentionPolicy.RUNTIME)
// 在執行時有效
public @interface MyLimit {
    //這個欄位是否為必填
    boolean isNotNull() default false;
    // 欄位描述
    String description() default "";
    int MaxLength() default 0;
    int MinLength() default 0;
    //表示這個欄位是否為int型別
    boolean isInt() default false;
    int MaxNum() default 30;
    int MinNum() default 18;
}
編寫註解的解析:VerifyAnnotationMyLimit類,這個裡面使用一個List來存放驗證的錯誤資訊,getListExceptions()方法返回這個List,可以通過annotationMyLimit.getListExceptions().size()!=0來判斷驗證是否成功,不成功可以取得錯誤資訊:

VerifyAnnotationMyLimit:

[java] view plain copy print?
  1. import java.lang.reflect.Field;  
  2. import java.util.ArrayList;  
  3. publicclass VerifyAnnotationMyLimit {  
  4.     private MyLimit limit;  
  5.     private Class obj;  
  6.     private ArrayList<Exception> ListExceptions;  
  7.     public VerifyAnnotationMyLimit(Object object) throws Exception {  
  8.         obj = object.getClass();  
  9.         ListExceptions = new ArrayList<Exception>();  
  10.         Field[] fields = obj.getDeclaredFields();  
  11.         for (Field field : fields) {  
  12.             // 設定field為private時設定可以訪問許可權,
  13.             field.setAccessible(true);  
  14.             // 開始驗證
  15.             verify(field, object);  
  16.             // 重新對field設定許可權
  17.             field.setAccessible(false);  
  18.         }  
  19.     }  
  20.     public ArrayList<Exception> getListExceptions() {  
  21.         return ListExceptions;  
  22.     }  
  23.     privatevoid verify(Field field, Object object) throws Exception {  
  24.         limit = field.getAnnotation(MyLimit.class);  
  25.         // 檢查這個field是否被MyLimit註釋
  26.         if (!field.isAnnotationPresent(MyLimit.class)) {  
  27.             return;  
  28.         }  
  29.         // 取出object物件中的field值
  30.         Object objectvalue = field.get(object);  
  31.         String description = ”“.equals(limit.description()) ? field.getName()  
  32.                 : limit.description();  
  33.         // 先驗證是否為必填,如果必填且value為空,則丟擲異常,如果不是必填,那我們
  34.         if (limit.isNotNull()) {  
  35.             if (“”.equals(objectvalue) || objectvalue == null) {  
  36.                 ListExceptions.add(new Exception(description + “不能為空”));  
  37.             }  
  38.         } else {  
  39.             // 不是必填項先檢查是否有值,沒有就直接返回,有就繼續向下驗證
  40.             if (objectvalue == null) {  
  41.                 return;  
  42.             }  
  43.         }  
  44.         if (limit.isInt()) {  
  45.             int value = Integer.valueOf(objectvalue.toString());  
  46.             if (value < limit.MinNum() || value > limit.MaxNum()) {  
  47.                 ListExceptions.add(new Exception(description + “必須在”
  48.                         + limit.MinNum() + ”到” + limit.MaxNum() + “之間”));  
  49.             }  
  50.             return;  
  51.         }  
  52.         if (objectvalue.toString().length() < limit.MinLength()  
  53.                 || objectvalue.toString().length() > limit.MaxLength()) {  
  54.             ListExceptions.add(new Exception(description + “長度必須在”
  55.                     + limit.MinLength() + ”到” + limit.MaxLength() + “之間”));  
  56.         }  
  57.     }  
  58. }  
import java.lang.reflect.Field;
import java.util.ArrayList;

public class VerifyAnnotationMyLimit {
    private MyLimit limit;
    private Class obj;
    private ArrayList<Exception> ListExceptions;

    public VerifyAnnotationMyLimit(Object object) throws Exception {
        obj = object.getClass();
        ListExceptions = new ArrayList<Exception>();
        Field[] fields = obj.getDeclaredFields();
        for (Field field : fields) {
            // 設定field為private時設定可以訪問許可權,
            field.setAccessible(true);
            // 開始驗證
            verify(field, object);
            // 重新對field設定許可權
            field.setAccessible(false);

        }
    }

    public ArrayList<Exception> getListExceptions() {
        return ListExceptions;
    }

    private void verify(Field field, Object object) throws Exception {
        limit = field.getAnnotation(MyLimit.class);
        // 檢查這個field是否被MyLimit註釋
        if (!field.isAnnotationPresent(MyLimit.class)) {
            return;
        }
        // 取出object物件中的field值
        Object objectvalue = field.get(object);
        String description = "".equals(limit.description()) ? field.getName()
                : limit.description();

        // 先驗證是否為必填,如果必填且value為空,則丟擲異常,如果不是必填,那我們
        if (limit.isNotNull()) {
            if ("".equals(objectvalue) || objectvalue == null) {
                ListExceptions.add(new Exception(description + "不能為空"));
            }
        } else {
            // 不是必填項先檢查是否有值,沒有就直接返回,有就繼續向下驗證
            if (objectvalue == null) {
                return;
            }
        }

        if (limit.isInt()) {
            int value = Integer.valueOf(objectvalue.toString());
            if (value < limit.MinNum() || value > limit.MaxNum()) {
                ListExceptions.add(new Exception(description + "必須在"
                        + limit.MinNum() + "到" + limit.MaxNum() + "之間"));
            }
            return;
        }

        if (objectvalue.toString().length() < limit.MinLength()
                || objectvalue.toString().length() > limit.MaxLength()) {
            ListExceptions.add(new Exception(description + "長度必須在"
                    + limit.MinLength() + "到" + limit.MaxLength() + "之間"));
        }
    }
}
Students類時註解的使用者: [java] view plain copy print?
  1. publicclass Students {  
  2.     privateint id;  
  3.     @MyLimit(description=“學生的姓名”,MaxLength=5,MinLength=2,isNotNull=true)  
  4.     private String name;  
  5.     @MyLimit(description=“學生的年齡”,isNotNull=true,isInt=true)  
  6.     privateint age;  
  7.     @MyLimit(MaxLength=200,isNotNull=true)  
  8.     private String addr;  
  9.     @MyLimit(description=“學生所在城市”,MaxLength=20)  
  10.     private String city;  
  11.     set…get…  
  12.     @Override
  13.     public String toString() {  
  14.         return“Students [id=” + id + “, name=” + name + “, age=” + age  
  15.                 + ”, addr=” + addr + “, city=” + city + “]”;  
  16.     }     
  17. }  
public class Students {
    private int id;
    @MyLimit(description="學生的姓名",MaxLength=5,MinLength=2,isNotNull=true)
    private String name;
    @MyLimit(description="學生的年齡",isNotNull=true,isInt=true)
    private int age;
    @MyLimit(MaxLength=200,isNotNull=true)
    private String addr;
    @MyLimit(description="學生所在城市",MaxLength=20)
    private String city;
    set...get...
    @Override
    public String toString() {
        return "Students [id=" + id + ", name=" + name + ", age=" + age
                + ", addr=" + addr + ", city=" + city + "]";
    }   
}
在Students類中我們沒有在id的屬性上設定註解,所以不會對id進行驗證;對name屬性設定規定了長度在2到5之間,而且是必填項;在age上規定了這個是必填項,是一個int型別的,所以會使用註解對int型別預設的範圍18到哦30之間;而對於addr屬性只是規定了200長度,但是必填。

最後到了測試部分:

[java] view plain copy print?
  1. publicstaticvoid main(String[] args) {  
  2.         // TODO Auto-generated method stub
  3.         Students students = new Students();  
  4.         students.setName(”abcdefghijklmn”);  
  5.         students.setAddr(”“);  
  6.         students.setAge(230);  
  7.         try {//傳人Students物件進行驗證
  8.             VerifyAnnotationMyLimit annotationMyLimit = new VerifyAnnotationMyLimit(students);  
  9.             if(annotationMyLimit.getListExceptions().size()!=0){  
  10.                 for (Exception exception : annotationMyLimit.getListExceptions()) {  
  11.                     System.out.println(”錯誤:”+exception.getMessage());  
  12.                 }  
  13.             }  
  14.         } catch (Exception e) {  
  15.             // TODO Auto-generated catch block
  16.             System.out.println(e.getMessage());  
  17.             e.printStackTrace();  
  18.         }  
  19.         System.out.println(students.toString());  
  20.     }  
public static void main(String[] args) {
        // TODO Auto-generated method stub
        Students students = new Students();
        students.setName("abcdefghijklmn");
        students.setAddr("");
        students.setAge(230);
        try {//傳人Students物件進行驗證
            VerifyAnnotationMyLimit annotationMyLimit = new VerifyAnnotationMyLimit(students);
            if(annotationMyLimit.getListExceptions().size()!=0){
                for (Exception exception : annotationMyLimit.getListExceptions()) {
                    System.out.println("錯誤:"+exception.getMessage());
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        System.out.println(students.toString());
    }

if(annotationMyLimit.getListExceptions().size()!=0)判斷是驗證有錯誤;

for (Exception exception : annotationMyLimit.getListExceptions()) {
System.out.println(“錯誤:”+exception.getMessage());//輸出錯誤資訊。
}
結果:


當我們改動一些值時:

[java] view plain copy print?
  1. students.setName(“張三”);  
  2. students.setAddr(”xxx省xxx市xxx縣”);  
  3. students.setAge(23);  
       students.setName("張三");
        students.setAddr("xxx省xxx市xxx縣");
        students.setAge(23);

我們按照規定填寫時就沒有錯誤了,

但是這樣還是有弊端的,因為我們是使用已經設定好屬性的物件去驗證了,等於是先給Students賦值,再去驗證我們賦值是否正確,有了一些中間操作。