1. 程式人生 > >Java自定義註解反射校驗數據

Java自定義註解反射校驗數據

sda new out 格式 是否 本地 imp 使用範圍 數據類型

package com.annotations.ecargo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateRules {
    ValidateRule[] value();
}

package com.annotations.ecargo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateRule {
    String ruleName();

    String params() 
default ""; String errorMsg(); }

package com.annotations.ecargo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate { public enum ValidateType { OBJECT, LIST } // 默認是Object ValidateType value() default ValidateType.OBJECT; // 默認非空 boolean notBlank() default true; // 默認參數0 int params() default 0; // 默認錯誤信息空 String errorMsg() default ""; }

package com.annotations.ecargo;

public class SeeBillAbandoRequset {
    
    @Validate(errorMsg = "報文頭不能為空")
    private SeeBillHead head;
    
    @Validate(errorMsg = "主節點不能為空")
    private SeeBillMain main;
    
    @Validate(errorMsg = "基本信息不能為空")
    private SeeBillAbandonBase base;

    public SeeBillHead getHead() {
        return head;
    }

    public void setHead(SeeBillHead head) {
        this.head = head;
    }

    public SeeBillMain getMain() {
        return main;
    }

    public void setMain(SeeBillMain main) {
        this.main = main;
    }

    public SeeBillAbandonBase getBase() {
        return base;
    }

    public void setBase(SeeBillAbandonBase base) {
        this.base = base;
    }

}

package com.annotations.ecargo;

public class SeeBillHead {
    @ValidateRules(value = { @ValidateRule(ruleName = "notBlank", params = "", errorMsg = "用戶名為空!") })
    private String userCode;// 用戶名

    @ValidateRules(value = { @ValidateRule(ruleName = "notBlank", params = "", errorMsg = "密碼為空!") })
    private String passWord;// 密碼

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public String getUserCode() {
        return userCode;
    }

    public void setUserCode(String userCode) {
        this.userCode = userCode;
    }
}

package com.annotations.ecargo;

public class SeeBillMain {
    @ValidateRules(value = { @ValidateRule(ruleName = "notBlank", params = "", errorMsg = "交易碼為空!") })
    private String transNo;// 交易碼

    @ValidateRules(value = { @ValidateRule(ruleName = "notBlank", params = "", errorMsg = "交易流水號為空!") })
    private String serialNumber;// 交易流水號

    @ValidateRules(value = { @ValidateRule(ruleName = "notBlank", params = "", errorMsg = "交易時間為空!"),
            @ValidateRule(ruleName = "date_v", params = "yyyy-MM-dd HH:mm:ss", errorMsg = "交易時間格式錯誤") })
    private String transDate;// 交易時間

    private String transPortNum;

    private String resultCode;// 返回接口

    private String errorInfo;// 返回信息

    public String getTransNo() {
        return transNo;
    }

    public void setTransNo(String transNo) {
        this.transNo = transNo;
    }

    public String getSerialNumber() {
        return serialNumber;
    }

    public void setSerialNumber(String serialNumber) {
        this.serialNumber = serialNumber;
    }

    public String getTransDate() {
        return transDate;
    }

    public void setTransDate(String transDate) {
        this.transDate = transDate;
    }

    public String getTransPortNum() {
        return transPortNum;
    }

    public void setTransPortNum(String transPortNum) {
        this.transPortNum = transPortNum;
    }

    public String getResultCode() {
        return resultCode;
    }

    public void setResultCode(String resultCode) {
        this.resultCode = resultCode;
    }

    public String getErrorInfo() {
        return errorInfo;
    }

    public void setErrorInfo(String errorInfo) {
        this.errorInfo = errorInfo;
    }

}

package com.annotations.ecargo;

public class SeeBillAbandonBase {
    @ValidateRules(value = { @ValidateRule(ruleName = "notBlank", params = "", errorMsg = "保單號不能為空!") })
    private String policyNo;

    @ValidateRules(value = { @ValidateRule(ruleName = "notBlank", params = "", errorMsg = "退保原因不能為空!") })
    private String reason;

    public String getPolicyNo() {
        return policyNo;
    }

    public void setPolicyNo(String policyNo) {
        this.policyNo = policyNo;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

}

package com.annotations.ecargo;

public class RuleReturn {
    public final static RuleReturn SUCCESS;
    public final static RuleReturn SUCCESS_BREAK;

    public final static String BREAK = "break";
    public final static String CONTINUE = "continue";

    private boolean flag;

    private String type = "";

    private String errorMsg;

    static {
        SUCCESS = new RuleReturn();
        SUCCESS.setFlag(true);
        SUCCESS.setType(CONTINUE);

        SUCCESS_BREAK = new RuleReturn();
        SUCCESS_BREAK.setFlag(true);
        SUCCESS_BREAK.setType(BREAK);
    }

    public RuleReturn() {
        super();
    }

    public RuleReturn(String type, String errorMsg) {
        this.flag = false;
        this.type = type;
        this.errorMsg = errorMsg;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}
package com.annotations.ecargo;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;

public class StringUtils {

    /**
     * 將字符串有某種編碼轉變成另一種編碼
     * 
     * @param string 編碼的字符串
     *            
     * @param originCharset  原始編碼格式
     *           
     * @param targetCharset  目標編碼格式
     *           
     * @return String 編碼後的字符串
     */
    public static String encodeString(String string, Charset originCharset, Charset targetCharset) {
        return string = new String(string.getBytes(originCharset), targetCharset);
    }

    /**
     * URL編碼
     * 
     * @param string 編碼字符串
     *            
     * @param charset  編碼格式
     *           
     * @return String
     */
    @SuppressWarnings("deprecation")
    public static String encodeUrl(String string, String charset) {
        if (null != charset && !charset.isEmpty()) {
            try {
                return URLEncoder.encode(string, charset);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return URLEncoder.encode(string);
    }

    /**
     * URL編碼
     * 
     * @param string 解碼字符串
     *            
     * @param charset  解碼格式
     *           
     * @return String
     */
    @SuppressWarnings("deprecation")
    public static String decodeUrl(String string, String charset) {
        if (null != charset && !charset.isEmpty()) {
            try {
                return URLDecoder.decode(string, charset);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return null;
            }
        }
        return URLDecoder.decode(string);
    }

    /**
     * 判斷字符串是否是空的 方法摘自commons.lang
     * 
     * <pre>
     * StringUtils.isEmpty(null)      = true
     * StringUtils.isEmpty("")        = true
     * StringUtils.isEmpty(" ")       = false
     * StringUtils.isEmpty("bob")     = false
     * StringUtils.isEmpty("  bob  ") = false
     * </pre>
     * 
     * @param str
     * @return boolean
     */
    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

    /**
     * <p>
     * 判斷字符串是否是""," ",null,註意和isEmpty的區別
     * </p>
     * 方法摘自commons.lang
     * 
     * <pre>
     * StringUtils.isBlank(null)      = true
     * StringUtils.isBlank("")        = true
     * StringUtils.isBlank(" ")       = true
     * StringUtils.isBlank("bob")     = false
     * StringUtils.isBlank("  bob  ") = false
     * </pre>
     */
    public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }
}

package com.annotations.ecargo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.annotations.ecargo.Validate.ValidateType;

public class ValidateService {

    public void validateSeeRequest(Object requset, StringBuffer stringBuffer) throws Exception, Exception {
        List<Field> fieldList = new ArrayList<Field>();
        fieldList.addAll(Arrays.asList(requset.getClass().getDeclaredFields()));
        for (Field field : fieldList) {
            field.setAccessible(true);
            Validate validate = field.getAnnotation(Validate.class);
            if (validate != null) {
                if (validate.value() == ValidateType.OBJECT) {
                    Object object = field.get(requset);
                    if (object != null) {
                        validateSeeRequest(object, stringBuffer);
                    } else {
                        RuleReturn ruleReturn = notBlank_OBJ(field, validate, stringBuffer);
                        if (!ruleReturn.isFlag()) {
                            stringBuffer.append("Q:").append(ruleReturn.getErrorMsg()).append(";");
                            if ("break".equals(ruleReturn.getType())) {
                                return;
                            }
                        }
                    }

                } else if (validate.value() == ValidateType.LIST) {
                    Object subList = field.get(requset); // 屬性
                    if (subList != null) {
                        List<?> list = (List<?>) subList;
                        for (int i = 0; i < list.size(); i++) {
                            Object subObj = list.get(i);
                            validateSeeRequest(subObj, stringBuffer);
                        }
                    }
                }
            }
            ValidateRules validateRules = field.getAnnotation(ValidateRules.class);
            if (validateRules == null) {
                continue;
            }
            ValidateRule[] rules = validateRules.value();
            for (ValidateRule validateRule : rules) {
                String methodName = validateRule.ruleName();
                Class<?>[] clazzs = { Field.class, Object.class, ValidateRule.class};
                Method method = this.getClass().getMethod(methodName, clazzs);
                Object[] params = { field, requset, validateRule };
                RuleReturn ruleReturn = (RuleReturn) method.invoke(this, params);
                if (!ruleReturn.isFlag()) { // 校驗未通過
                    stringBuffer.append("Q:").append(ruleReturn.getErrorMsg()).append(";");
                    if ("break".equals(ruleReturn.getType())) {
                        break;
                    }
                }
                if (ruleReturn.getType().equals(RuleReturn.BREAK)) {
                    break;
                }
            }

        }
    }

    private RuleReturn notBlank_OBJ(Field field, Validate validate, StringBuffer stringBuffer) {
        RuleReturn ruleReturn = RuleReturn.SUCCESS;

        if (validate.notBlank()) {
            field.setAccessible(true);
            ruleReturn = new RuleReturn(RuleReturn.BREAK, validate.errorMsg());
        }

        return ruleReturn;
    }

    public RuleReturn notBlank(Field field, Object obj, ValidateRule validateRule) throws Exception {
        String value = field.get(obj) != null ? (String) field.get(obj) : "";

        if (StringUtils.isBlank(value)) {
            return new RuleReturn(RuleReturn.BREAK, validateRule.errorMsg());
        }
        return RuleReturn.SUCCESS;
    }
    public RuleReturn date_v(Field field, Object obj, ValidateRule validateRule) throws Exception {
        String value = field.get(obj) != null ? (String) field.get(obj) : "";
        String date = validateRule.params();
        if (!StringUtils.isBlank(value)) {
            try {
                new SimpleDateFormat(date).parse(value);
            } catch (Exception e) {
                return new RuleReturn(RuleReturn.BREAK, validateRule.errorMsg());
            }
        }
        return RuleReturn.SUCCESS;
    }
}

package com.annotations.ecargo;

import org.junit.Test;

public class TestMain {

    @Test
    public void test() throws Exception {
        ValidateService validateService = new ValidateService();
        StringBuffer stringBuffer = new StringBuffer();

        SeeBillAbandoRequset requset = new SeeBillAbandoRequset();
        SeeBillHead head = new SeeBillHead();
        head.setUserCode("zhouxaigoe");
        head.setPassWord("123123123");
        
        SeeBillMain main = new SeeBillMain();
        main.setErrorInfo("errorInfo");
        main.setResultCode("resultCode");
        main.setSerialNumber("serialNumber");
        main.setTransDate("2017-05-12 16:38:54");
        main.setTransNo("transNo");
        main.setTransPortNum("transPortNum");
        
        SeeBillAbandonBase base = new SeeBillAbandonBase();
        base.setPolicyNo("policyNo");
        base.setReason("reason");
        
        requset.setHead(head);
        requset.setMain(main);
        requset.setBase(base);
        
        validateService.validateSeeRequest(requset,stringBuffer);
        System.out.println(stringBuffer);
    }
}

Java:自定義註解
元註解:
元註解的作用就是負責註解其他註解。
Java定義了4個標準的meta-annotation類型,它們被用來提供對其他的annotation類型做說明。
@Target:
@Target說明了Annatation所修飾的對象範圍:Annotation可以被用於packages、types(類、接口、枚舉、Annation類型)、
類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
作用: 用於描述註解的使用範圍(即:被描述的註解可以用在什麽地方)。
取值(ElementType.):
1、CONSTRUCTOR 用於描述構造器
2、FIELD 用於描述域
3、LOCAL_VARIABLE 用於描述局部變量
4、METHOD 用於描述方法
5、PACKAGE 用於描述包
6、PARMETER 用於描述參數
7、TYPE 用於描述類、接口(包括註解類型)或enum聲明
@Retention
@Retention定義了該Annotation被保留的時間長短: 某些Annotation僅出現在源代碼中,而被編譯器丟棄;
而另一些被卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另外一些class被裝載是將被讀取。
使用這個meta-Annotation可以對Annotation的生命周期限制。

作用:表示需要什麽級別保存該註釋信息,用於描述註解的生命周期(即: 被描述的註解在什麽範圍內有效)
取值(RetentionPoicy):
1、SOURCE: 編譯器要丟棄的註釋,在源文件中有效(即源文件保留)。
2、CLASS: 編譯器將把註釋記錄在類文件中,但在運行時 VM 不需要保留註釋。
3、RUNTIME: 編譯器將把註釋記錄在類文件中,在運行時 VM 將保留註釋,因此可以反射性地讀取。
Retention meta-annotation類型有唯一的value作為成員,它的取值來自java.lang.annotation.RetentionPolicy的枚舉類型值。
RetentionPolicy的屬性值是RUTIME,這樣註解處理器可以通過反射,獲取到該註解的屬性值,從而去做一些運行時的邏輯處理
@Documented
@Documented 如果類型聲明是用 Documented 來註釋的,則其註釋將成為註釋元素的公共 API 的一部分。 Documented是一個標記註解,沒有成員。

@Inherited
@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承的。如果[email protected]class,則這個annotation將被用於該class的子類。
自定義註解
[email protected],自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節。在定義註解時,不能繼承其他的註解或接口。
@interface用來聲明一個註解,其中的每一個方法實際上是聲明了一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)。可以通過default來聲明參數的默認值。
定義註解格式:
   public @interface 註解名 {定義體}
註解參數的可支持數據類型:
1.所有基本數據類型(int,float,boolean,byte,double,char,long,short)
2.String類型
3.Class類型
4.enum類型
5.Annotation類型
6.以上所有類型的數組
Annotation類型裏面的參數該怎麽設定:
第一,只能用public或默認(default)這兩個訪問權修飾.例如,String value();這裏把方法設為defaul默認類型;   
第二,參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和 String,Enum,Class,annotations等數據類型,以及這一些類型的數組.例如,String value();這裏的參數成員就為String;  
第三,如果只有一個參數成員,最好把參數名稱設為"value",後加小括號。

註解元素的默認值:
   註解元素必須有確定的值,要麽在定義註解的默認值中指定,要麽在使用註解時指定,非基本類型的註解元素的值不可為null。
因此, 使用空字符串或0作為默認值是一種常用的做法。這個約束使得處理器很難表現一個元素的存在或缺失的狀態,因為每個註解的聲明中,
所有元素都存在,並且都具有相應的值,為了繞開這個約束,我們只能定義一些特殊的值,
例如空字符串或者負數,一次表示某個元素不存在,在定義註解時,這已經成為一個習慣用法
註解處理器





Java自定義註解反射校驗數據