java记录对象前后修改的内容(工具类)

2019-04-09 16:28:15 浏览数 (2)

有时候业务需要,需记录一条记录的修改历史,但是不能为完成任务而硬编码,不靠谱

这种情况可以使用java反射来完成

对对象属性的描述可以通过自定义注解来完成,读取里面的属性进而记录修改历史。

在对象的属性上面加上注解,value设置为属性的中文描述

工具了代码如下

util类(BeanChangeUtil)

代码语言:javascript复制
 1 import java.beans.PropertyDescriptor;
 2 import java.lang.reflect.Field;
 3 import java.lang.reflect.Method;
 4 import java.util.Arrays;
 5 
 6 public class BeanChangeUtil<T> {
 7     public String contrastObj(Object oldBean, Object newBean) {
 8         // 创建字符串拼接对象
 9         StringBuilder str = new StringBuilder();
10         // 转换为传入的泛型T
11         T pojo1 = (T) oldBean;
12         T pojo2 = (T) newBean;
13         // 通过反射获取类的Class对象
14         Class clazz = pojo1.getClass();
15         // 获取类型及字段属性
16         Field[] fields = clazz.getDeclaredFields();
17         return jdk8Before(fields, pojo1, pojo2, str,clazz);
18 //        return jdk8OrAfter(fields, pojo1, pojo2, str,clazz);
19     }
20 
21     // jdk8 普通循环方式
22     public String jdk8Before(Field[] fields,T pojo1,T pojo2,StringBuilder str,Class clazz){
23         int i = 1;
24         try {
25             for (Field field : fields) {
26                 if(field.isAnnotationPresent(PropertyMsg.class)){
27                     PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
28                     // 获取对应属性值
29                     Method getMethod = pd.getReadMethod();
30                     Object o1 = getMethod.invoke(pojo1);
31                     Object o2 = getMethod.invoke(pojo2);
32                     if (o1 == null || o2 == null) {
33                         continue;
34                     }
35                     if (!o1.toString().equals(o2.toString())) {
36                         str.append(i   "、"   field.getAnnotation(PropertyMsg.class).value()   ":"   "修改前=>"   o1   ",修改后=>"   o2   "n");
37                         i  ;
38                     }
39                 }
40             }
41         } catch (Exception e) {
42             e.printStackTrace();
43         }
44         return str.toString();
45     }
46 
47     // lambda表达式,表达式内部的变量都是final修饰,需要传入需要传入final类型的数组
48     public String jdk8OrAfter(Field[] fields, T pojo1, T pojo2, StringBuilder str, Class clazz){
49         final int[] i = {1};
50         Arrays.asList(fields).forEach(f -> {
51             if(f.isAnnotationPresent(PropertyMsg.class)){
52                 try {
53                     PropertyDescriptor pd = new PropertyDescriptor(f.getName(), clazz);
54                     // 获取对应属性值
55                     Method getMethod = pd.getReadMethod();
56                     Object o1 = getMethod.invoke(pojo1);
57                     Object o2 = getMethod.invoke(pojo2);
58                     if (o1 == null || o2 == null) {
59                         return;
60                     }
61                     if (!o1.toString().equals(o2.toString())) {
62                         str.append(i[0]   "、"   f.getAnnotation(PropertyMsg.class).value()   ":"   "修改前=>"   o1   "t修改后=>"   o2   "n");
63                         i[0]  ;
64                     }
65                 }catch (Exception e){
66                     e.printStackTrace();
67                 }
68             }
69         });
70         return str.toString();
71     }
72 }

自定义注解(PropertyMsg)

@Target

表示该注解可以用于什么地方,可能的ElementType参数有:

  CONSTRUCTOR:构造器的声明

  FIELD:域声明(包括enum实例)

  LOCAL_VARIABLE:局部变量声明

  METHOD:方法声明

  PACKAGE:包声明

  PARAMETER:参数声明

  TYPE:类、接口(包括注解类型)或enum声明

@Retention

表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

  SOURCE:注解将被编译器丢弃

  CLASS:注解在class文件中可用,但会被VM丢弃

  RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。

@Document

将注解包含在Javadoc中

@Inherited

允许子类继承父类中的注解

代码语言:javascript复制
1 import java.lang.annotation.*;
2 
3 @Target(ElementType.FIELD)
4 @Retention(RetentionPolicy.RUNTIME)
5 @Documented
6 @Inherited
7 public @interface PropertyMsg {
8     String value();
9 }

使用方式test

代码语言:javascript复制
public class TestChange {

    public static void main(String[] args) {
        TestChange u1 = new TestChange("我是谁", "ok", 30,"刘德华");
        TestChange u2 = new TestChange("我在哪", "no", 20,"郭富城");
        BeanChangeUtil<TestChange> t = new BeanChangeUtil<>();
        String str = t.contrastObj(u1, u2);
        if (str.equals("")) {
            System.out.println("未有改变");
        } else {
            System.out.println(str);
        }
    }

    public TestChange() {
    }

    public TestChange(String about, String lock, Integer age, String name) {
        this.about = about;
        this.lock = lock;
        this.age = age;
        this.name = name;
    }

    @PropertyMsg("关于")
    private String about;

    private String lock;

    @PropertyMsg("年龄")
    private Integer age;

    @PropertyMsg("姓名")
    private String name;

    public String getAbout() {
        return about;
    }

    public void setAbout(String about) {
        this.about = about;
    }

    public String getLock() {
        return lock;
    }

    public void setLock(String lock) {
        this.lock = lock;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

0 人点赞