专栏首页面朝大海春暖花开java记录对象前后修改的内容(工具类)

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

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

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

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

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

工具了代码如下

util类(BeanChangeUtil)

 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

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

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

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 条评论
登录 后参与评论

相关文章

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

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

    陈灬大灬海
  • java反射,代码优化

    比如getAnswerA getAnswerB,这怎么动态调用。反射这个时候就用到了。

    陈灬大灬海
  • java浅拷贝和深拷贝(基础也是很重要的)

    对于的github基础代码https://github.com/chywx/JavaSE

    陈灬大灬海
  • StringUtils的源码解析

    爱撒谎的男孩
  • 建造者模式浅析

    建造者模式是一种创建型的模式,其意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    孟君
  • 夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战

    本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看

    黄小斜
  • Java类库之正则表达式(重点)

    但是现在一个简单的问题就出现了,这个验证应该算是不难的,但是面对这样一个不麻烦的验证,代码写了9行代码,如果是一些更为复杂的验证呢?那么对于整体操作就更加的麻烦...

    葆宁
  • Java 代码精简之道

    其中:“道”指“规律、道理、理论”,“术”指“方法、技巧、技术”。意思是:“道”是“术”的灵魂,“术”是“道”的肉体;可以用“道”来统管“术”,也可以从“术”中...

    JAVA葵花宝典
  • 阅读开源框架,总结Java类的定义

    即使我们明白Java的类,也未必清楚该如何正确地定义一个Java类。阅读一些开源框架的源代码,会启发我们灵感,并给出好代码的规范,提炼设计原则与模式。

    张逸
  • java学习:调用 java web service

    先写一个java的class:AwbModel(相当于要在web service中传输的实体对象) package webservicesample; pub...

    菩提树下的杨过

扫码关注云+社区

领取腾讯云代金券