Java自定义注解反射校验数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java自定义注解反射校验数据相关的知识,希望对你有一定的参考价值。

 

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阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
    自定义注解
        使用@interface自定义注解时,自动继承了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自定义注解反射校验数据的主要内容,如果未能解决你的问题,请参考以下文章

java注解与自定义注解

java注解与自定义注解

java 自定义的注解有啥作用

自定义注解结合SpringAop实现权限,参数校验,日志等等功能

SpringBoot自定义校验注解

关于反射与自定义注解的一些使用