比较两个JavaBean属性是否相同

比较两个JavaBean属性是否相同 原创2022-01-26 23:17·CTO修炼之路 最近有个需求,需要记录数据修改前后的变化值。所以就想,通过反射的方式前后两个JavaBean对比一下属性来实现。其中主要功能包括:

1.对比出修改的数据,并知道其修改前后的值;

2.可以对一些字段进行屏蔽,不做比较;

3.字段属性要能知到其业务含义,在页面展示。

工具类


public class ObjCompareUtil {
    /**
     * 比较两个实体属性值,返回一个map以有差异的属性名为key,value为一个Map分别存oldObject,newObject此属性名的值
     *
     * @param oldObject      进行属性比较的对象1
     * @param newObject      进行属性比较的对象2
     * @param ignoreArr 忽略比较的字段
     * @return 属性差异比较结果map
     */
    public static Map<String, List<Object>> compareFields(Object oldObject, Object newObject, boolean userAnno, String[] ignoreArr) {
        try {
            Map<String, List<Object>> map = new HashMap<>();
            List<String> ignoreList = null;
            if (ignoreArr != null && ignoreArr.length > 0) {
                // array转化为list
                ignoreList = Arrays.asList(ignoreArr);
            }
            if (oldObject.getClass() != newObject.getClass()) {
                return map;
            }
            Class clazz = oldObject.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;
                }
                // get方法
                Method readMethod = pd.getReadMethod();
                // 获取值
                Object oldValue = readMethod.invoke(oldObject);
                Object newValue = readMethod.invoke(newObject);
                //获取注解备注
                if (userAnno) {
                    //根据字段名来获取字段
                    Field f = clazz.getDeclaredField(name);
                    FieldInfo annotation = f.getAnnotation(FieldInfo.class);
                    if (annotation != null) {
                        name = annotation.desc();
                    }
                }
                //放置结果
                if (oldValue == null || !oldValue.equals(newValue)) {
                    List<Object> list = new ArrayList<>(2);
                    list.add(oldValue);
                    list.add(newValue);
                    map.put(name, list);
                }
            }
            return map;
        } catch (Exception e) {
            return null;
        }
    }
}

自定义注解

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FieldInfo {
      String desc() default "";
}

使用介绍

接下来做一个测试,首先定义一个实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;

    @FieldInfo(desc = "年龄")
    private Integer age;

    private Byte status;

    private Date birthday;
}

跑一个main方法做一下测试:


public static void main(String[] args) throws InterruptedException {
      User user1 = new User("liwei", 18, (byte) 1, new Date());
      Thread.sleep(100);
      User user2 = new User("liwei", 19, (byte) 1, new Date());
      String[] ignor = {"age"};
      Map<String, List<Object>> stringListMap = ObjCompareUtil.compareFields(user1, user2, true, null);
      System.out.println(stringListMap);
  }
  

输出结果:

{birthday=[Wed Jan 26 22:42:26 CST 2022, Wed Jan 26 22:42:26 CST 2022], 年龄=[18, 19]}