码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Java对比对象修改前与修改后字段发生的变化


    1.   开发过程中,我们通常会对系统操作人对系统的操作进行记录,记录操作前后某个字段的变化,如下图  

     2.   提供一个工具类,可以比较一个对象里面,源对象,与修改后的对象,有哪些字段发生了改变, 第一步 

    1. /**
    2. * @author qiankun.hu
    3. * @version 1.0.0
    4. * @createTime 2023年09月20日 17:00:00
    5. * @Description TODO
    6. */
    7. @Target({ElementType.FIELD})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. public @interface ColumnInfo {
    10. /**
    11. * 字段code
    12. */
    13. String columnCode() default "";
    14. /**
    15. * 字段名称
    16. */
    17. String columnName() default "";
    18. /**
    19. * 字段类型
    20. */
    21. String columnType() default "";
    22. }

    工具类代码

    1. import com.example.demo.config.ColumnInfo;
    2. import org.apache.commons.lang3.StringUtils;
    3. import org.springframework.beans.BeanUtils;
    4. import java.beans.Introspector;
    5. import java.beans.PropertyDescriptor;
    6. import java.lang.reflect.Field;
    7. import java.lang.reflect.Method;
    8. import java.sql.Timestamp;
    9. import java.util.*;
    10. /**
    11. * @author qiankun.hu
    12. * @version 1.0.0
    13. * @createTime 2023年09月20日 17:00:00
    14. * @Description TODO
    15. */
    16. public class MyBeanUtils extends BeanUtils {
    17. /**
    18. * 比较两个实体属性值,返回一个map以有差异的属性名为key,value为一个list分别存obj1,obj2此属性名的值
    19. *
    20. * @param obj1 源值
    21. * @param obj2 最新值
    22. * @param ignoreArr 选择忽略比较的属性数组
    23. * @return 属性差异比较结果map
    24. *

    25. * 后面考虑添加注解字段名和中文名称,已达到提示对应的中文信息
    26. */
    27. public static Map> compareFields(Object obj1, Object obj2, String[] ignoreArr) {
    28. try {
    29. Map> map = new HashMap>();
    30. List ignoreList = null;
    31. if (ignoreArr != null && ignoreArr.length > 0) {
    32. // array转化为list
    33. ignoreList = Arrays.asList(ignoreArr);
    34. }
    35. if (obj1 == null) {
    36. Class clazz = obj2.getClass();
    37. // 获取object的属性描述
    38. PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz,
    39. Object.class).getPropertyDescriptors();
    40. // 这里就是所有的属性了
    41. for (PropertyDescriptor pd : pds) {
    42. // 属性名
    43. String name = pd.getName();
    44. // 如果当前属性选择忽略比较,跳到下一次循环
    45. if (ignoreList != null && ignoreList.contains(name)) {
    46. continue;
    47. }
    48. // Field field = clazz.getDeclaredField(name);
    49. Field field;
    50. try {
    51. field = clazz.getDeclaredField(name);
    52. } catch (NoSuchFieldException e) {
    53. try {
    54. //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
    55. field = clazz.getSuperclass().getDeclaredField(name);
    56. } catch (NoSuchFieldException ee) {
    57. //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
    58. field = clazz.getSuperclass().getSuperclass().getDeclaredField(name);
    59. }
    60. }
    61. ColumnInfo columnInfo = field.getAnnotation(ColumnInfo.class);
    62. if (columnInfo != null) {
    63. String columName = columnInfo.columnName();
    64. String columnCode = columnInfo.columnCode();
    65. String columnType = columnInfo.columnType();
    66. name = name + "_" + columName + "_" + columnCode + "_" + columnType;
    67. } else {
    68. continue;
    69. }
    70. // get方法
    71. Method readMethod = pd.getReadMethod();
    72. Object o2 = readMethod.invoke(obj2);
    73. if (o2 != null) {
    74. List list = new ArrayList();
    75. list.add(null);
    76. list.add(o2);
    77. map.put(name, list);
    78. }
    79. }
    80. } else {
    81. // 只有两个对象都是同一类型的才有可比性
    82. if (obj1.getClass() == obj2.getClass()) {
    83. Class clazz = obj1.getClass();
    84. // 获取object的属性描述
    85. PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz,
    86. Object.class).getPropertyDescriptors();
    87. // 这里就是所有的属性了
    88. for (PropertyDescriptor pd : pds) {
    89. // 属性名
    90. String name = pd.getName();
    91. // 如果当前属性选择忽略比较,跳到下一次循环
    92. if (ignoreList != null && ignoreList.contains(name)) {
    93. continue;
    94. }
    95. //Field field = clazz.getDeclaredField(name);
    96. Field field;
    97. try {
    98. field = clazz.getDeclaredField(name);
    99. } catch (NoSuchFieldException e) {
    100. try {
    101. //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
    102. field = clazz.getSuperclass().getDeclaredField(name);
    103. } catch (NoSuchFieldException ee) {
    104. //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
    105. field = clazz.getSuperclass().getSuperclass().getDeclaredField(name);
    106. }
    107. }
    108. ColumnInfo columnInfo = field.getAnnotation(ColumnInfo.class);
    109. if (columnInfo != null) {
    110. String columName = columnInfo.columnName();
    111. String columnCode = columnInfo.columnCode();
    112. String columnType = columnInfo.columnType();
    113. name = name + "_" + columName + "_" + columnCode + "_" + columnType;
    114. } else {
    115. continue;
    116. }
    117. // get方法
    118. Method readMethod = pd.getReadMethod();
    119. // 在obj1上调用get方法等同于获得obj1的属性值
    120. Object o1 = readMethod.invoke(obj1);
    121. // 在obj2上调用get方法等同于获得obj2的属性值
    122. Object o2 = readMethod.invoke(obj2);
    123. if (o1 instanceof Timestamp) {
    124. o1 = new Date(((Timestamp) o1).getTime());
    125. }
    126. if (o2 instanceof Timestamp) {
    127. o2 = new Date(((Timestamp) o2).getTime());
    128. }
    129. if (o1 == null && o2 == null) {
    130. continue;
    131. } else if (o1 == null && o2 != null) {
    132. List list = new ArrayList();
    133. list.add(o1);
    134. list.add(o2);
    135. if (o2 instanceof String && StringUtils.isBlank(String.valueOf(o2))) {
    136. o2 = null;
    137. }
    138. if (o2 != null) {
    139. map.put(name, list);
    140. }
    141. continue;
    142. }
    143. // 比较这两个值是否相等,不等就可以放入map了
    144. if (!o1.equals(o2)) {
    145. List list = new ArrayList();
    146. list.add(o1);
    147. list.add(o2);
    148. if(o2!=null){
    149. o1 = o1 instanceof String && StringUtils.isBlank(String.valueOf(o1)) ? "" : o1;
    150. Object info = (o2 instanceof String && StringUtils.isBlank(String.valueOf(o2)) ? "" : o2);
    151. o2 = o2 == null ? "" : info;
    152. if(!o1.equals(o2)){
    153. map.put(name, list);
    154. }
    155. }
    156. }
    157. }
    158. }
    159. }
    160. return map;
    161. } catch (Exception e) {
    162. return null;
    163. }
    164. }
    165. }
    166. 3  进行测试

      1. import com.alibaba.fastjson.JSON;
      2. import com.example.demo.config.ColumnInfo;
      3. import com.example.demo.util.MyBeanUtils;
      4. import java.util.*;
      5. /**
      6. * @author qiankun.hu
      7. * @version 1.0.0
      8. * @createTime 2022年10月14日 13:35:00
      9. * @Description TODO
      10. */
      11. public class StudentDto {
      12. @ColumnInfo(columnCode = "name", columnName = "名称")
      13. private String name;
      14. @ColumnInfo(columnCode = "name", columnName = "名称")
      15. private String age;
      16. @ColumnInfo(columnCode = "studentNum", columnName = "学号")
      17. private Integer studentNum;
      18. @ColumnInfo(columnCode = "classNum", columnName = "班级号")
      19. private String classNum;
      20. public static void main(String[] args) {
      21. //老数据
      22. StudentDto s1 = new StudentDto();
      23. s1.setName("张三");
      24. s1.setAge("18");
      25. s1.setStudentNum(9001);
      26. s1.setClassNum("高一二班");
      27. //修改后的数据
      28. StudentDto s2 = new StudentDto();
      29. s2.setName("张三");
      30. s2.setAge("19");
      31. s2.setStudentNum(9002);
      32. s2.setClassNum("高一三班");
      33. //忽略对比的字段
      34. String[] arr = new String[1];
      35. arr[0] = "studentNum";
      36. //对比哪些字段发生改变,K 是发生改变的字段 value 是字段前后的变化
      37. Map> stringListMap = MyBeanUtils.compareFields(s1, s2, null);
      38. System.out.println( JSON.toJSONString(stringListMap) );
      39. }
      40. public String getName() {
      41. return name;
      42. }
      43. public void setName(String name) {
      44. this.name = name;
      45. }
      46. public String getAge() {
      47. return age;
      48. }
      49. public void setAge(String age) {
      50. this.age = age;
      51. }
      52. public Integer getStudentNum() {
      53. return studentNum;
      54. }
      55. public void setStudentNum(Integer studentNum) {
      56. this.studentNum = studentNum;
      57. }
      58. public String getClassNum() {
      59. return classNum;
      60. }
      61. public void setClassNum(String classNum) {
      62. this.classNum = classNum;
      63. }
      64. }

      输出结果如下:
      {
          "age_名称_name_": ["18", "19"],
          "studentNum_学号_studentNum_": [9001, 9002],
          "classNum_班级号_classNum_": ["高一二班", "高一三班"]
      }

      我们可以看到,对象修改后与修改后,相关字段产生的变化,如果有不需要对比的字段,传入相同的参数既可

    167. 相关阅读:
      MySQL之账号管理、建库以及四大引擎
      springboot整合mybatis实现增删改查(xml)--项目阶段1
      centos执行systemctl restart命令报连接超时
      数据中台实战(00)-大数据的尽头是数据中台吗?
      代码随想录算法训练营第五十六天 |1143.最长公共子序列、1035.不相交的线、53. 最大子序和动态规划
      并发知识点总结: 共享模型之内存
      限制相关算法
      Nginx跨域解决方案
      腾讯云服务器南京地域详细介绍、测试IP和Ping值测速
      < 今日份知识点:浅述对 “ Vue 插槽 (slot) ” 的理解 以及 插槽的应用场景 >
    168. 原文地址:https://blog.csdn.net/huqiankunlol/article/details/133170284
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号