Java对比对象修改前与修改后字段发生的变化

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

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


/**
 * @author qiankun.hu
 * @version 1.0.0
 * @createTime 2023年09月20日 17:00:00
 * @Description TODO
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnInfo {

    /**
     * 字段code
     */
    String columnCode() default "";

    /**
     * 字段名称
     */
    String columnName() default "";

    /**
     * 字段类型
     */
    String columnType() default "";
}

工具类代码

import com.example.demo.config.ColumnInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.*;

/**
 * @author qiankun.hu
 * @version 1.0.0
 * @createTime 2023年09月20日 17:00:00
 * @Description TODO
 */
public class MyBeanUtils extends BeanUtils {

    /**
     * 比较两个实体属性值,返回一个map以有差异的属性名为key,value为一个list分别存obj1,obj2此属性名的值
     *
     * @param obj1      源值
     * @param obj2      最新值
     * @param ignoreArr 选择忽略比较的属性数组
     * @return 属性差异比较结果map
     * <p>
     * 后面考虑添加注解字段名和中文名称,已达到提示对应的中文信息
     */
    public static Map<String, List<Object>> compareFields(Object obj1, Object obj2, String[] ignoreArr) {
        try {
            Map<String, List<Object>> map = new HashMap<String, List<Object>>();
            List<String> ignoreList = null;
            if (ignoreArr != null && ignoreArr.length > 0) {
                // array转化为list
                ignoreList = Arrays.asList(ignoreArr);
            }
            if (obj1 == null) {
                Class clazz = obj2.getClass();
                // 获取object的属性描述
                PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz,
                        Object.class).getPropertyDescriptors();
                // 这里就是所有的属性了
                for (PropertyDescriptor pd : pds) {
                    // 属性名
                    String name = pd.getName();
                    // 如果当前属性选择忽略比较,跳到下一次循环
                    if (ignoreList != null && ignoreList.contains(name)) {
                        continue;
                    }
                    // Field field = clazz.getDeclaredField(name);
                    Field field;
                    try {
                        field = clazz.getDeclaredField(name);
                    } catch (NoSuchFieldException e) {
                        try {
                            //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
                            field = clazz.getSuperclass().getDeclaredField(name);
                        } catch (NoSuchFieldException ee) {
                            //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
                            field = clazz.getSuperclass().getSuperclass().getDeclaredField(name);
                        }
                    }
                    ColumnInfo columnInfo = field.getAnnotation(ColumnInfo.class);
                    if (columnInfo != null) {
                        String columName = columnInfo.columnName();
                        String columnCode = columnInfo.columnCode();
                        String columnType = columnInfo.columnType();
                        name = name + "_" + columName + "_" + columnCode + "_" + columnType;
                    } else {
                        continue;
                    }
                    // get方法
                    Method readMethod = pd.getReadMethod();
                    Object o2 = readMethod.invoke(obj2);
                    if (o2 != null) {
                        List<Object> list = new ArrayList<Object>();
                        list.add(null);
                        list.add(o2);
                        map.put(name, list);
                    }
                }
            } else {
                // 只有两个对象都是同一类型的才有可比性
                if (obj1.getClass() == obj2.getClass()) {
                    Class clazz = obj1.getClass();
                    // 获取object的属性描述
                    PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz,
                            Object.class).getPropertyDescriptors();
                    // 这里就是所有的属性了
                    for (PropertyDescriptor pd : pds) {
                        // 属性名
                        String name = pd.getName();
                        // 如果当前属性选择忽略比较,跳到下一次循环
                        if (ignoreList != null && ignoreList.contains(name)) {
                            continue;
                        }
                        //Field field = clazz.getDeclaredField(name);
                        Field field;
                        try {
                            field = clazz.getDeclaredField(name);
                        } catch (NoSuchFieldException e) {
                            try {
                                //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
                                field = clazz.getSuperclass().getDeclaredField(name);
                            } catch (NoSuchFieldException ee) {
                                //此处用于解决继承导致的getDeclaredField不能直接获取父类属性的问题
                                field = clazz.getSuperclass().getSuperclass().getDeclaredField(name);
                            }

                        }
                        ColumnInfo columnInfo = field.getAnnotation(ColumnInfo.class);
                        if (columnInfo != null) {
                            String columName = columnInfo.columnName();
                            String columnCode = columnInfo.columnCode();
                            String columnType = columnInfo.columnType();
                            name = name + "_" + columName + "_" + columnCode + "_" + columnType;
                        } else {
                            continue;
                        }
                        // get方法
                        Method readMethod = pd.getReadMethod();
                        // 在obj1上调用get方法等同于获得obj1的属性值
                        Object o1 = readMethod.invoke(obj1);
                        // 在obj2上调用get方法等同于获得obj2的属性值
                        Object o2 = readMethod.invoke(obj2);
                        if (o1 instanceof Timestamp) {
                            o1 = new Date(((Timestamp) o1).getTime());
                        }
                        if (o2 instanceof Timestamp) {
                            o2 = new Date(((Timestamp) o2).getTime());
                        }
                        if (o1 == null && o2 == null) {
                            continue;
                        } else if (o1 == null && o2 != null) {
                            List<Object> list = new ArrayList<Object>();
                            list.add(o1);
                            list.add(o2);
                            if (o2 instanceof String && StringUtils.isBlank(String.valueOf(o2))) {
                                o2 = null;
                            }
                            if (o2 != null) {
                                map.put(name, list);
                            }
                            continue;
                        }
                        // 比较这两个值是否相等,不等就可以放入map了
                        if (!o1.equals(o2)) {
                            List<Object> list = new ArrayList<Object>();
                            list.add(o1);
                            list.add(o2);
                            if(o2!=null){
                                o1 = o1 instanceof String && StringUtils.isBlank(String.valueOf(o1)) ? "" : o1;
                                Object info = (o2 instanceof String && StringUtils.isBlank(String.valueOf(o2)) ? "" : o2);
                                o2 = o2 == null ? "" : info;
                                if(!o1.equals(o2)){
                                    map.put(name, list);
                                }
                            }

                        }
                    }
                }
            }
            return map;
        } catch (Exception e) {
            return null;
        }
    }
}

3  进行测试

import com.alibaba.fastjson.JSON;
import com.example.demo.config.ColumnInfo;
import com.example.demo.util.MyBeanUtils;
import java.util.*;


/**
 * @author qiankun.hu
 * @version 1.0.0
 * @createTime 2022年10月14日 13:35:00
 * @Description TODO
 */
public class StudentDto {

    @ColumnInfo(columnCode = "name", columnName = "名称")
    private String name;
    @ColumnInfo(columnCode = "name", columnName = "名称")
    private String age;
    @ColumnInfo(columnCode = "studentNum", columnName = "学号")
    private Integer studentNum;
    @ColumnInfo(columnCode = "classNum", columnName = "班级号")
    private String classNum;

    public static void main(String[] args) {
        //老数据
        StudentDto s1 = new  StudentDto();
        s1.setName("张三");
        s1.setAge("18");
        s1.setStudentNum(9001);
        s1.setClassNum("高一二班");

        //修改后的数据
        StudentDto s2 = new  StudentDto();
        s2.setName("张三");
        s2.setAge("19");
        s2.setStudentNum(9002);
        s2.setClassNum("高一三班");

        //忽略对比的字段
        String[] arr = new String[1];
        arr[0] = "studentNum";

        //对比哪些字段发生改变,K 是发生改变的字段  value 是字段前后的变化
        Map<String, List<Object>> stringListMap = MyBeanUtils.compareFields(s1, s2, null);

        System.out.println( JSON.toJSONString(stringListMap) );
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public Integer getStudentNum() {
        return studentNum;
    }

    public void setStudentNum(Integer studentNum) {
        this.studentNum = studentNum;
    }

    public String getClassNum() {
        return classNum;
    }

    public void setClassNum(String classNum) {
        this.classNum = classNum;
    }
}

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

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值