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;
    }
}

OK,到位

https://github.com/chywx/JavaSE_chy

原文地址:https://www.cnblogs.com/chywx/p/10630457.html

时间: 2024-10-07 10:33:21

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

JAVA对象任意深度克隆clone工具类分享

原文:JAVA对象任意深度克隆clone工具类分享 源代码下载地址:http://www.zuidaima.com/share/1550463408114688.htm package com.zuidaima.n_app.util; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import jav

java二维码编码和解析工具类

用到两个jar包: QRCode.jar Qrcodeen.jar package com.banmacoffee.utils; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; imp

HTTP 输出响应内容工具类

ResponseUtils.java package javax.utils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import javax.servlet.http.HttpServletRespons

使用HashMap对象传递url参数实用工具类

代码如下: package com.yanek.util; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; public class HttpUtil { /** * @param args

java关闭资源,自制关闭资源工具类

在网上看到一篇关于关闭资源的正确方式:http://blog.csdn.net/bornforit/article/details/6896775 该博文中的总结: (1)使用finally块来关闭物理资源(非托管资源),保证关闭操作始终会被执行: (2)关闭每个资源之前首先保证引用该资源的引用变量不为null: (3)为每个物理资源使用单独的trycatch块关闭资源,保证关闭资源时引发的异常不会影响其他资源的关闭. 在资源过多的时候,我们要在finally块中写很多的非空判断.以及try-c

java打开文件夹(含判断操作系统工具类和解压缩工具类)

1.Runtime.getRuntime().exec("explorer D:\\Java"); 2.java.awt.Desktop.getDesktop().open(new File("D:\\Java")); 4.java.awt.Desktop.getDesktop().browse(...) 3. try { String[] cmd = new String[5]; cmd[0] = "cmd"; cmd[1] = "/

Java语言Lang包下常用的工具类介绍_java - JAVA

文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 无论你在开发哪中 Java 应用程序,都免不了要写很多工具类/工具函数.你可知道,有很多现成的工具类可用,并且代码质量都很不错,不用你写,不用你调试,只要你发现. 在 Apache Jakarta Common 中, Lang 这个 Java 工具包是所有 Apache Jakarta Common 项目中被使用最广泛的,几乎你所知道的名气比较大的软件里面都有用到它,包括 Tomcat, Weblogic, Webs

java总结第二次(剩余内容)//类和对象1

7.成员变量和局部变量 成员变量:在类中定义,用来描述对象将要有什么 局部变量:在类的方法中定义,在方法中保存临时数据 区别:作用域不同 局部变量的作用域仅限于定义它的方法 成员变量的作用域在整个类内部都是可见的 8.信息的封装和隐藏 Java中通过将数据声明为私有的(private),再提供公开的(public)方法:getXXX和setXXX实现对该属性的操作,以实现下述目的: 隐藏一个类的实现细节: 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作:

java springboot调用第三方接口 借助hutoool工具类 爬坑

楼主是个后端小白一枚,之前没接触过后端,只学了java基本语法,还是在学校老师教的,学的很浅,什么ssh.ssm框架都没有学,最近在自学spring boot,看书学也看不是很懂,就在b站上看教学视频,大概看了几个老师讲的,最后选了尚硅谷的视频,老师讲的很好,有点偏向底层源码解析,讲的很细,对我这个新手小白来说也不知道好不好,反正我就是跟着看了.最近接到超哥布置的一个任务,spring boot调用第三方接口,下面就讲讲我这个新手小白是怎么一步一步磕出来结果的,顺便记录一下,免得我后面忘了. 首