java通过反射+注解获取两个对象改变的内容

来源:互联网 发布:mysql sys refcursor 编辑:程序博客网 时间:2024/05/23 02:26

项目需要保存编辑日志,初始想法是每一个字段都判断一遍,后来发现每个类都要写一遍判断方法,如果增删字段会非常麻烦,最后的想法是通过注解+反射来完成这个判断

首先,定义一个注解类
package org.anno;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/**  * 自定义注解  *@Documented:指明该注解可以用于生成doc  *@Inherited:该注解可以被自动继承  *@Retention:指明在什么级别显示该注解:  *  RetentionPolicy.SOURCE 注解存在于源代码中,编译时会被抛弃     RetentionPolicy.CLASS 注解会被编译到class文件中,但是JVM会忽略     RetentionPolicy.RUNTIME JVM会读取注解,同时会保存到class文件中   @Target:指明该注解可以注解的程序范围     ElementType.TYPE 用于类,接口,枚举但不能是注解     ElementType.FIELD 作用于字段,包含枚举值     ElementType.METHOD 作用于方法,不包含构造方法     ElementType.PARAMETER 作用于方法的参数     ElementType.CONSTRUCTOR 作用于构造方法     ElementType.LOCAL_VERIABLE 作用于本地变量或者catch语句     ElementType.ANNOTATION_TYPE 作用于注解     ElementType.PACKAGE 作用于包  */  @Documented@Target(ElementType.FIELD)@Inherited@Retention(RetentionPolicy.RUNTIME)public @interface Change {    //字段名称    public String fieldName() default "字段:";    //分隔符    public String separator() default ",";    //扩展字段    public String expand() default "";    //中间拼接字符    public String extra() default "改为";    //时间格式化类型    public String pattern() default "yyyy-MM-dd";}
其次,定义一个实体类
package org.entity;import java.util.Date;import org.anno.Change;public class User {    @Change(fieldName="编号:")    private int id;    @Change(fieldName="姓名:")    private String name;    @Change(fieldName="生日:")    private Date birth;    @Change(fieldName="年龄",expand="岁")    private int age;    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public Date getBirth() {        return birth;    }    public void setBirth(Date birth) {        this.birth = birth;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}
最后
package org.test;import java.lang.reflect.Field;import java.text.SimpleDateFormat;import java.util.Date;import org.anno.Change;import org.entity.User;public class RefectTest {    public static void main(String[] args) throws Exception {        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");        User u1 = new User();        u1.setId(1);        u1.setName("张三");        u1.setBirth(sdf.parse("2017-08-16"));        u1.setAge(1);        User u2 = new User();        u2.setId(2);        u2.setName("李四");        u2.setBirth(sdf.parse("2017-08-15"));        u2.setAge(21);        System.out.println(compare(u1,u2));    }    @SuppressWarnings({ "rawtypes", "unchecked" })    public static String compare(Object co,Object mo)throws Exception{        StringBuilder sb = new StringBuilder();        if(null == co || null == mo){            return sb.toString();        }        if(co.getClass() != mo.getClass()){            return sb.toString();        }        //获取对象的class        Class cc = co.getClass();        Class mc = mo.getClass();        //获取声明的变量        Field[] cfs = cc.getDeclaredFields();        Field[] mfs = mc.getDeclaredFields();        for (int i = 0; i < cfs.length; i++) {            Field cfield = cfs[i];            for(int j = 0; j < mfs.length; j++){                Field mfield = mfs[j];                //判断两个变量名是否一致                if(cfield.getName().equals(mfield.getName())){                    //判断变量是否有自定义注解                    boolean flag = cfield.isAnnotationPresent(Change.class);                    if(flag){                        //获取变量名称                        String fieldName = cfield.getName();                        //组合变量的对应get方法 getId                        String method = "get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1,fieldName.length());                        //根据方法名称调用对象方法获取变量值                        Object v1 = cc.getMethod(method).invoke(co);                        Object v2 = mc.getMethod(method).invoke(mo);                        //判断变量值是否为空                        if(null == v1 || null == v2){                            break;                        }                        //获取对象的自定义注解内容                        Change f = cfield.getAnnotation(Change.class);                        //判断变量值是否相同                        if(!v1.equals(v2)){                            //拼接字符串,如编号:1改为2,姓名:张三改为李四,                            sb.append(f.fieldName()+getString(v1,f.pattern())+f.expand()+f.extra()+getString(v2,f.pattern())+f.expand()+f.separator());                            break;                        }                    }                }            }        }        return sb.toString();    }    /**     * 变量处理     * @param str     * @param pattern     * @return     */    public static String getString(Object str,String pattern){        if(str instanceof Date){            SimpleDateFormat sdf = new SimpleDateFormat(pattern);            return sdf.format(str);        }        return str.toString();    }}
原创粉丝点击