背景
有时候我们需要做一下审计日志或者操作记录等功能,需要对某条数据变动之后看到变化的数据。
我想到两个实现方法:使用反射(直接舍弃,效率太低),使用阿里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()); } } }
##运行结果
##反射实现方法
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; } }