记录日志详细变更

本文介绍了一种用于记录用户修改字段详细日志的方法,通过创建FieldDiff和BeanDiff实体类,比较旧对象和新对象的属性差异。在比较过程中,考虑了对象包含复杂类型如Person、List、Map的情况,以及如何忽略特定属性如updateTime。通过自定义注解FieldAlias实现了对不需要比较的属性的处理,并提供了动态排除新对象中为null字段的功能。
摘要由CSDN通过智能技术生成

需求:记录出用户修改的字段,做详细日志记录。
思路:

  1. 创建FeildDiff、BeanDiff实体类,FeildDiff包括字段英文名、字段中文名、旧值、新值、目录五个属性,BeanDiff包括FeildDiff集合一个属性。
  2. 获取旧对象数据。
  3. 获取新对象数据。
  4. 新旧对象属性对比,存进FeildDiff实体类。把每一个属性对比得到的FeildDiff存进BeanDiff。

难点:

  • 对象里面包含复杂对象,比如属性为Person,List,Map应如何比较?
  • 不想比较对象的某些属性,比如updatetime,应如何实现?
  • 动态实现不想要比较的某些属性,比如新对象的一些属性为null,表示不更新此字段,但是不能记录日志该字段的新值就是null,该如何实现?

伪代码:
FieldDiff.java

/**
 * @description:两个对象差异-字段新旧值
 * @create: 2021-09-02 11:01
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FieldDiff {

    /**
     * 字段英文名
     */
    @JsonProperty(value = "field_en_name")
    private String fieldENName;

    /**
     * 字段中文名
     */
    @JsonProperty(value = "field_cn_name")
    private String fieldCNName;

    /**
     * 旧值
     */
    @JsonProperty(value = "old_value")
    private Object oldValue;

    /**
     * 新值
     */
    @JsonProperty(value = "new_value")
    private Object newValue;

    /**
     * 目录
     */
    @JsonProperty(value = "catalog")
    private String catalog;

    @Override
    public String toString() {
        String oldVal = this.oldValue == null ? "" : this.oldValue.toString();
        String newVal = this.newValue == null ? "" : this.newValue.toString();
        return "将 " + this.fieldCNName + " 从“" + oldVal + "” 修改为 “" + newVal + "”";
    }
}

BeanDiff.java

/**
 * @description: 两个对象差异
 * @create: 2021-09-02 11:03
 **/
public class BeanDiff {

    /**
     * 所有差异字段list
     */
    private List<FieldDiff> fieldDiffList = new ArrayList<>();

    public void addFieldDiff(FieldDiff fieldDiff) {
        this.fieldDiffList.add(fieldDiff);
    }

    public List<FieldDiff> getFieldDiffList() {
        return fieldDiffList;
    }

}

BeanCompareUtils.java

/**
 * 实例字段差异比较工具类
 * @author test
 */
public class BeanCompareUtils {

    /**
     * bean比较
     * @param oldBean
     * @param newBean
     * @return
     */
    public static BeanDiff compare(Object oldBean, Object newBean) {
        BeanDiff beanDiff = new BeanDiff();

        Class oldClass = oldBean.getClass();
        Class newClass = newBean.getClass();

        if (oldClass.equals(newClass)) {
            List<Field> fieldList = new ArrayList<>();

            fieldList = getCompareFieldList(fieldList, newClass);

            for (int i = 0; i < fieldList.size(); i ++) {
                //要比较对象的属性
                Field field = fieldList.get(i);
                //设置最高权限
                field.setAccessible(true);

                FieldAlias alias = field.getAnnotation(FieldAlias.class);

                try {
                    Object oldValue = field.get(oldBean);
                    Object newValue = field.get(newBean);

                    //如果新旧值不相等,则放入集合里
                    if (nullableNotEquals(oldValue, newValue)) {
                        FieldDiff fieldDiff = new FieldDiff(field.getName(), alias.value(), oldValue, newValue, alias.catalog());

                        beanDiff.addFieldDiff(fieldDiff);
                    }

                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return beanDiff;
    }

    /**
     * bean比较,忽略一些指定字段,比如修改实体的null字段
     * @param oldBean
     * @param newBean
     * @return
     */
    public static BeanDiff compareExcludeFieldList(Object oldBean, Object newBean, List<String> ignoreFieldList) {
        BeanDiff beanDiff = new BeanDiff();

        Class oldClass = oldBean.getClass();
        Class newClass = newBean.getClass();

        if (oldClass.equals(newClass)) {
            List<Field> fieldList = new ArrayList<>();

            fieldList = getCompareFieldListWithIgnore(fieldList, newClass, ignoreFieldList);

            for (int i = 0; i < fieldList.size(); i ++) {
                //要比较对象的属性
                Field field = fieldList.get(i);
                //设置最高权限
                field.setAccessible(true);

                FieldAlias alias = field.getAnnotation(FieldAlias.class);

                try {
                    Object oldValue = field.get(oldBean);
                    Object newValue = field.get(newBean);

                    //如果新旧值不相等,则放入集合里
                    if (nullableNotEquals(oldValue, newValue)) {
                        FieldDiff fieldDiff = new FieldDiff(field.getName(), alias.value(), oldValue, newValue, alias.catalog());

                        beanDiff.addFieldDiff(fieldDiff);
                    }

                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return beanDiff;
    }

    /**
     * 获取需要比较的字段list
     * @param fieldList
     * @param clazz
     * @return
     */
    private static List<Field> getCompareFieldList(List<Field> fieldList, Class clazz) {
        Field[] fieldArray = clazz.getDeclaredFields();

        List<Field> list = Arrays.asList(fieldArray);

        for (int i = 0; i < list.size(); i ++) {
            Field field = list.get(i);
            FieldAlias alias = field.getAnnotation(FieldAlias.class);
            if (alias != null) {
                fieldList.add(field);
            }
        }

        Class superClass = clazz.getSuperclass();
        if (superClass != null) {
            getCompareFieldList(fieldList, superClass);
        }
        return fieldList;
    }

    /**
     * 获取添加注解的字段list,但是忽略一些字段
     * @param fieldList
     * @param clazz
     * @return
     */
    private static List<Field> getCompareFieldListWithIgnore(List<Field> fieldList, Class clazz, List<String> ignoreFieldList) {
        Field[] fieldArray = clazz.getDeclaredFields();

        List<Field> list = Arrays.asList(fieldArray);

        for (int i = 0; i < list.size(); i ++) {
            Field field = list.get(i);
            FieldAlias alias = field.getAnnotation(FieldAlias.class);
            if (alias != null && !ignoreFieldList.contains(field.getName())) {
                fieldList.add(field);
            }
        }

        Class superClass = clazz.getSuperclass();
        if (superClass != null) {
            getCompareFieldListWithIgnore(fieldList, superClass, ignoreFieldList);
        }
        return fieldList;
    }


    /**
     * 比较值是否不相等
     * @param oldValue
     * @param newValue
     * @return
     */
    private static boolean nullableNotEquals(Object oldValue, Object newValue) {

        if (oldValue == null && newValue == null) {
            return false;
        }

        if (oldValue != null && oldValue.equals(newValue)) {
            return false;
        }

        if (("".equals(oldValue) && newValue == null) || ("".equals(newValue) && oldValue == null)) {
            return false;
        }

        return true;
    }

}

使用:
添加自定义注解FieldAlias

/**
 * 字段中文别名
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAlias {
    /**
     * 所在目录
     * @return
     */
    String catalog() default "";
    /**
     * 中文名称
     * @return
     */
    String value() default "";
}

SkuDetailCnDTO.java

/**
 * @description:
 * @create: 2021-09-10 14:12
 **/
@Data
public class SkuDetailCnDTO {
    /**
     * SKU名称
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "SKU名称")
    private String skuName;

    /**
     * 品牌描述
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "品牌描述")
    private String description;

    /**
     * 物品规格描述
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "物品规格描述")
    private String standardDescription;

    /**
     * 质检标准
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "质检标准")
    private String qc;

    /**
     * SKU长(cm)
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "SKU长(cm)")
    private BigDecimal skuLength;

    /**
     * SKU宽(cm)
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "SKU宽(cm)")
    private BigDecimal skuWidth;

    /**
     * SKU高(cm)
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "SKU高(cm)")
    private BigDecimal skuHeight;

    /**
     * SKU重量(g)
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "SKU重量(g)")
    private BigDecimal skuWeight;

    /**
     * 数量单位
     */
    @FieldAlias(catalog = "商品管理-编辑SKU", value = "数量单位")
    private String quantityUm;
    }
		//新对象数据
		SkuDetailCnDTO dbSkuClone = skuDao2CN(dbSkuDetail);
		//旧对象数据
        SkuDetailCnDTO editSkuClone = skuDao2CN(editSkuDetail);
        //获取编辑实体为null的字段,排除这些字段,不修改
        String[] nullPropertyNames = BeanUtil.getNullPropertyNames(editSkuClone);
        //获得两个对象中不相等属性的详细数据
        List<FieldDiff> fieldDiffList = BeanCompareUtils.compareExcludeFieldList(dbSkuClone, editSkuClone, Arrays.asList(nullPropertyNames)).getFieldDiffList();

难点解决:

  • 对象里面包含复杂对象。当前方式不支持嵌套,可以把复杂对象的属性平铺在新对象同一层实体属性里,这样只需要关心新对象的属性即可。
  • 不想比较对象的某些属性。通过加自定义注解的形式遍历对象属性来得到哪些属性需要比较,同时也解决了各个属性的中文名称不一致的问题。
  • 动态实现不想要比较的某些属性。首先获取到新对象为null的属性列表,在工具类里添加新方法传进该集合,遍历对象属性时如果该属性既有自定义注解又不在此集合里,则进行比较。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值