美文网首页程序员
使用JAVA注解(Annotation)、反射手动实现友好的、可

使用JAVA注解(Annotation)、反射手动实现友好的、可

作者: 平行线 | 来源:发表于2017-11-07 12:40 被阅读148次

    1:需求背景

    当你的系统是一个纯后台服务且各个接口没有前台约束(手机号码合法性校验,字段长度等等)的情况下,各个接口简单的必填、长度、合法性等简单校验也是要具备的。当然也要给调用方很好的体验,总不能手机号码没传的时候你给别人抛个“NullPointerException”、“NumberFormatException”什么鬼……估计对接开发心里千万只草泥马在奔腾了~~ 开始做的时候脑子一闪而过的想法就是在业务开始前加一堆if ~else 判断不就行了,都是当你的代码中全是这样的判断条件你自己看了估计都会吐,那还有什么其他优雅的实现方式呢?Java注解(Annotation)!!

    2:使用注解(Annotation)实现符合自己系统需求的、可复用的、可拓展的校验规则

    1:Annotation的基本语法就不累述了,网上的资料太多了。
    2:通过在Bean中的添加自定义注解如PxxFixLengthRule、PxxMustNumber、PxxRequiredRule和判断规则实现友好的校验规则
    如下图所示。这样的代码是不是清爽很多
    !


    校验效果图

    3:示例PxxFixLengthRule、PxxMustNumber、PxxRequiredRule自定义注解实现

    3.1:PxxFixLengthRule

    package com.kpdpxx.accumulate.testAnnotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PxxFixLengthRule {
        /**
         * 固定长度
         * @return
         */
        public int fixLength();
        /**
         * 异常信息描述
         * @return
         */
        public String exceptionMsg() default "";
        
    }
    
    

    3.2 PxxMustNumber

    package com.kpdpxx.accumulate.testAnnotation;
    
    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 PxxMustNumber {
        /**
         * 必须为数字
         * @return
         */
        public boolean isNum() default false;
        public String exceptionMsg () default "必须为数字";
    }
    
    

    3.3 PxxRequiredRule

    package com.kpdpxx.accumulate.testAnnotation;
    
    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 PxxRequiredRule {
        /**
         * 必填项
         * true 为必填项
         * @return
         */
        public boolean required() default false;
        /**
         * 具体异常信息
         * @return
         */
        public String exceptionMsg() default "异常信息";
        
        
    }
    
    

    4:自定义注解标签在订单(Order)bean中的使用例子,直接上代码了

    package com.kpdpxx.accumulate.testAnnotation;
    
    public class Order {
    
        @PxxRequiredRule(required=true,exceptionMsg="手机号码不能为空")
        @PxxFixLengthRule(fixLength=11,exceptionMsg="手机号码必须为11位")
        private String phoneNum;//手机号码
        @PxxMustNumber(isNum=true,exceptionMsg="充值金额必须为数字")
        private String payMent;//支付金额
        private String create_time;//创建时间
        public String getPhoneNum() {
            return phoneNum;
        }
        public void setPhoneNum(String phoneNum) {
            this.phoneNum = phoneNum;
        }
        public String getCreate_time() {
            return create_time;
        }
        public void setCreate_time(String create_time) {
            this.create_time = create_time;
        }
        public String getPayMent() {
            return payMent;
        }
        public void setPayMent(String payMent) {
            this.payMent = payMent;
        }
        @Override
        public String toString() {
            return "phoneNum="+getPhoneNum()+",Create_time="+getCreate_time()+",PayMent="+getPayMent();
        }
        
    }
    
    

    5:通过反射和注解实现友好的校验规则,也直接上代码了哈

    重点关注checkMyRule和getFieldVaule方法如下图所示


    checkMyRule和getFieldVaule方法

    代码如下:

    package com.kpdpxx.accumulate.testAnnotation;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class TestCheckOrder {
    
        public static void main(String[] args) {
            try{
                Order o_110=new Order();
                o_110.setPhoneNum("");
                o_110.setPayMent("12312");
                checkMyRule(o_110);
                //通过校验后开始业务逻辑
            }catch(Exception e){
                e.printStackTrace();
            }   
            try{
                Order o_1=new Order();
                o_1.setPayMent("1亿");
                o_1.setPhoneNum("15088888888");
                checkMyRule(o_1);
            }catch(Exception e){
                e.printStackTrace();
            }
            try{
                Order o_1=new Order();
                o_1.setPhoneNum("15088888888");
                o_1.setPayMent("12312");
                o_1.setCreate_time("2017/11/7 10:41:44");
                checkMyRule(o_1);
                
                System.out.println(o_1.toString()+" 【校验通过】");
            }catch(Exception e){
                e.printStackTrace();
            }   
        }
    
        public static void checkMyRule(Order o) throws Exception{
            if(o!=null){
                Field[] fields=o.getClass().getDeclaredFields();
                for(Field field: fields){
                    if(field.isAnnotationPresent(PxxRequiredRule.class)){
                        String strV=getFieldVaule(o, field);
                        if(strV==null||strV.trim().length()<=0){
                            PxxRequiredRule pxxRequiredRule=field.getAnnotation(PxxRequiredRule.class);
                            throw new Exception ("校验失败,字段【"+field.getName()+"】:"+pxxRequiredRule.exceptionMsg()+",当前值:"+strV);
                        }
                    }
                    if(field.isAnnotationPresent(PxxFixLengthRule.class)){
                        String strV=getFieldVaule(o, field);
                        PxxFixLengthRule pxxFixLengthRule=field.getAnnotation(PxxFixLengthRule.class);
                        if(strV==null||strV.trim().length()!=pxxFixLengthRule.fixLength()){
                            throw new Exception ("校验失败,字段【"+field.getName()+"】:"+pxxFixLengthRule.exceptionMsg()+",当前值:"+strV);
                        }
                    }
                    if(field.isAnnotationPresent(PxxMustNumber.class)){
                        String strV=getFieldVaule(o, field);
                        PxxMustNumber pxxMustNumber=field.getAnnotation(PxxMustNumber.class);
                        try{
                            Double d =Double.valueOf(strV);
                        }catch(Exception e){
                            throw new Exception ("校验失败,字段【"+field.getName()+"】:"+pxxMustNumber.exceptionMsg()+",当前值:"+strV);
                        }
                    }
                }
            }
            
        }
        /**
         * 获取 字段对应的值
         * @param o
         * @param field
         */
        public static String getFieldVaule(Order o, Field field)
                throws NoSuchMethodException, IllegalAccessException,
                InvocationTargetException {
            try{
                String field_methoe_name="get"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
                Method field_methoe=o.getClass().getMethod(field_methoe_name, null);
                return (String) field_methoe.invoke(o, null);
            }catch(Exception e){
                return null;
            }
            
        }
    }
    
    

    6:总结

    通过如上例子实现,就可以比较友好的方式实现校验规则(就算是实习新同学也能看懂各种错误,不会一报错就把一堆报错信息帖给你让你看了)。如果bean中的属性比较复杂,可以使用递归的方式进行校验。

    如有描述不对的地方望不吝赐教,非常感谢。

    相关文章

      网友评论

        本文标题:使用JAVA注解(Annotation)、反射手动实现友好的、可

        本文链接:https://www.haomeiwen.com/subject/vkbdmxtx.html