对比相同类对象字段的变化(可用于审计或者轨迹)

简介: 对比相同类对象字段的变化(可用于审计或者轨迹)

背景

有时候我们需要做一下审计日志或者操作记录等功能,需要对某条数据变动之后看到变化的数据。

我想到两个实现方法:使用反射(直接舍弃,效率太低),使用阿里fastjson的JSONObject

所需东西:维护一个对象字段及字段含义的枚举,每条数据的对象模版

maven依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.69</version>
</dependency>

对象模版

@Data
@NoArgsConstructor
public class OptRecord {
    private String type;
    private Double ammount;
    private List<String> urls;
    private String remark;
}

枚举

public enum OptRecordEnum {
    URLS("urls", "图片凭证"),
    TYPE("type", "操作款项类型"),
    AMMOUNT("ammount", "金额"),
    REMARK("remark", "备注");
    private String filedName;
    private String filedMean;
    public static OptRecordEnum getOptRecordEnumByFiledName(String filedName){
        for (OptRecordEnum optRecordEnum : values()) {
            if (optRecordEnum.getFileName().equals(filedName)){
                return optRecordEnum;
            }
        }
        return null;
    }
    OptRecordEnum(final String filedName, final String filedMean) {
        this.filedName = filedName;
        this.filedMean = filedMean;
    }
    public String getFileName() {
        return this.filedName;
    }
    public String getFiledMean() {
        return this.filedMean;
    }
}

测试demo

public class TestCompare {
    public static void main(String[] args) throws Exception {
        OptRecord optRecord1 = new OptRecord();
        optRecord1.setRemark("321");
        optRecord1.setAmmount(123.00);
        optRecord1.setType("123");
        optRecord1.setUrls(Arrays.asList("321", "123"));
        OptRecord optRecord2 = new OptRecord();
        optRecord2.setRemark("123");
        optRecord2.setAmmount(124.00);
        optRecord2.setType("123");
        optRecord2.setUrls(Arrays.asList("1", "123"));
        JSONObject jsonObject1 = JSON.parseObject(JSON.toJSONString(optRecord1));
        JSONObject jsonObject2 = JSON.parseObject(JSON.toJSONString(optRecord2));
        List<Comparison> comparisons = new ArrayList<>();
        for (Map.Entry<String, Object> stringObjectEntry : jsonObject1.entrySet()) {
            if (!stringObjectEntry.getValue().equals(jsonObject2.get(stringObjectEntry.getKey()))){
                String key = stringObjectEntry.getKey();
                comparisons.add(new Comparison(key, OptRecordEnum.getOptRecordEnumByFiledName(key).getFiledMean(), jsonObject1.get(key), jsonObject2.get(key)));
            }
        }
        for (Comparison comparison : comparisons) {
            OptRecordEnum optRecordEnumByFiledName = OptRecordEnum.getOptRecordEnumByFiledName(comparison.getFiledName());
            //此处可以save db
            System.out.println(optRecordEnumByFiledName.getFiledMean() + ":" + comparison.getBeforeValue() + "->" + comparison.getAfterValue());
        }
    }
}

##运行结果

1.png

##反射实现方法

public class TestCompare {
    public static List<Comparison> compareObj(Object beforeObj, Object afterObj) throws Exception{
        List<Comparison> diffs = new ArrayList<>();
        if(beforeObj == null) {
            throw new RuntimeException("原对象不能为空");
        }
        if(afterObj == null) {
            throw new RuntimeException("新对象不能为空");
        }
        if(!beforeObj.getClass().isAssignableFrom(afterObj.getClass())){
            throw new RuntimeException("两个对象不相同,无法比较");
        }
        //取出属性
        Field[] beforeFields = beforeObj.getClass().getDeclaredFields();
        Field[] afterFields = afterObj.getClass().getDeclaredFields();
        Field.setAccessible(beforeFields, true);
        Field.setAccessible(afterFields, true);
        //遍历取出差异值
        if(beforeFields != null && beforeFields.length > 0){
            for(int i=0; i<beforeFields.length; i++){
                System.out.println(JSON.toJSONString(beforeFields[i].getName()) + ":" + JSON.toJSONString(afterFields[i].getName()));
                Object beforeValue = beforeFields[i].get(beforeObj);
                Object afterValue = afterFields[i].get(afterObj);
                if((beforeValue != null && !"".equals(beforeValue) && !beforeValue.equals(afterValue)) || ((beforeValue == null || "".equals(beforeValue)) && afterValue != null)){
                    Comparison comparison = new Comparison();
                    comparison.setFiledName(beforeFields[i].getName());
                    comparison.setBeforeValue(beforeValue);
                    comparison.setAfterValue(afterValue);
                    diffs.add(comparison);
                }
            }
        }
        return diffs;
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class Comparison{
        private String filedName;
        private String filedMean;
        private Object beforeValue;
        private Object afterValue;
    }
}
相关文章
|
3月前
|
分布式计算 DataWorks 数据处理
DataWork数据处理问题之属性覆盖掉如何解决
DataWork数据处理是指使用DataWorks平台进行数据开发、数据处理和数据治理的活动;本合集将涵盖DataWork数据处理的工作流程、工具使用和问题排查,帮助用户提高数据处理的效率和质量。
28 0
|
8月前
基于参数关联关系动态呈现参数
本场景以计费方式为例,为您介绍资源编排如何在计费方式为包年包月时动态呈现包年包月的单位和时长。
30 0
|
数据采集 机器学习/深度学习 算法
②数据预处理之数据清理,数据集成,数据规约,数据变化和离散化
数据预处理之数据清理,数据集成,数据规约,数据变化和离散化
601 0
②数据预处理之数据清理,数据集成,数据规约,数据变化和离散化
|
10月前
|
PHP
php清洗数据实战案例(4):按照关联数组相同值名称进行筛选后对不同的指标予以合并计算的解决方案
php清洗数据实战案例(4):按照关联数组相同值名称进行筛选后对不同的指标予以合并计算的解决方案
41 0
|
10月前
ArcGIS:如何对要素类进行查询要素属性、更改符号、标记?
ArcGIS:如何对要素类进行查询要素属性、更改符号、标记?
230 1
|
10月前
|
定位技术 Windows
ArcGIS:按属性选择要素、按位置选择要素、空间和属性的组合查询;属性表中长度、面积等的量算
ArcGIS:按属性选择要素、按位置选择要素、空间和属性的组合查询;属性表中长度、面积等的量算
228 0
|
数据可视化
【数据篇】34 # 如何处理多元变量?
【数据篇】34 # 如何处理多元变量?
131 0
【数据篇】34 # 如何处理多元变量?
关于属性数据的捕获
关于属性数据的捕获
55 0
|
Ubuntu Linux
用户操作轨迹记录
用户操作轨迹记录
149 1
用户操作轨迹记录
|
数据采集 NoSQL 大数据
数据预处理-航线类型操作类型-更新规则|学习笔记
快速学习数据预处理-航线类型操作类型-更新规则
317 0