比较2个对象字段值的变化情况,这里不关注字段类型,仅比较值
修改类型-增删改
@Getter
public enum DataChangeType {
// 属性变更类型枚举
DELETE("DELETE", "删除"),
UPDATE("UPDATE", "修改"),
SAVE("SAVE", "新增");
private String code;
private String name;
DataChangeType(String code, String name) {
this.code = code;
this.name = name;
}
}
变更结果集
@Data
public class ComparableResult {
/**
* 变更字段
*/
private String fieldName;
/**
* 变更前类的内容容
*/
private Object oldFieldContent;
/**
* 变更后类的内容容
*/
private Object newFieldContent;
/**
* 变更的枚举类型
*/
private String DataChangeType;
}
比较工具类
public class ComparableUtils {
/**
* 返回所有字段
*
* @param target 目标
* @return 字段
*/
public static Map<String, Field> getFields(Object target) {
if (target == null) {
return new HashMap<>();
}
Field[] fields = target.getClass().getDeclaredFields();
Map<String, Field> rsMap = new HashMap<>(fields.length);
Stream.of(fields).forEach(field -> {
field.setAccessible(true);
rsMap.put(field.getName(), field);
});
return rsMap;
}
/**
* 比较两个对象属性值是否相同,如果不同返回修改过的属性信息集合,包括:字段名,原始数据值,新值,更改类型
*
* @param source 原始对象
* @param target 新对象
* @return List<ComparableResult> 变化后的数据集合
*/
public static List<ComparableResult> compareInstance(Object source, Object target) {
List<ComparableResult> compareResultList = new ArrayList<>();
try {
// 获取字段集合
Map<String, Field> fieldsSource = getFields(source);
Map<String, Field> fieldsTarget = getFields(target);
// 1.先遍历source集合,处理两种情况:
// 1.1 source中有的,target中没有的->字段被删除
// 1.2 source中有的,target中有但是内容变化->字段内容被更新
for (Field field : fieldsSource.values()) {
// 如果字段添加了忽略比较注解,则跳过比较
if (field.getAnnotation(IgnoreCompare.class) != null) {
continue;
}
ComparableResult comparableResult = new ComparableResult();
Object v1 = field.get(source);
// 1.1 source中有的,target中没有的->字段被删除
if (!fieldsTarget.containsKey(field.getName())) {
comparableResult.setOldFieldContent(v1);
comparableResult.setFieldName(field.getName());
comparableResult.setDataChangeType(DataChangeType.DELETE.getCode());
compareResultList.add(comparableResult);
continue;
}
// 1.2 source中有的,target中有但是内容变化->字段内容被更新
Object v2 = fieldsTarget.get(field.getName()).get(target);
// 如果都是null 跳过
if (v1 == null && v2 == null) {
continue;
}
if (v1 == null || !v1.equals(v2)) {
comparableResult.setFieldName(field.getName());
comparableResult.setOldFieldContent(v1);
comparableResult.setNewFieldContent(v2);
comparableResult.setDataChangeType(DataChangeType.UPDATE.getCode());
compareResultList.add(comparableResult);
}
}
// 2. 遍历target集合,处理一种情况
// 2.1 source中没有,target有的->新增字段
for (Field field : fieldsTarget.values()) {
ComparableResult comparableResult = new ComparableResult();
// 如果字段添加了忽略比较注解,则跳过比较
if (field.getAnnotation(IgnoreCompare.class) != null) {
continue;
}
if (!fieldsSource.containsKey(field.getName())) {
comparableResult.setFieldName(field.getName());
comparableResult.setNewFieldContent(field.getName());
comparableResult.setOldFieldContent(field.get(target));
comparableResult.setDataChangeType(DataChangeType.SAVE.getCode());
compareResultList.add(comparableResult);
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return compareResultList;
}
}
有些字段业务需求会忽略变换,这里添加一个注解,标记不参与比较的字段
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface IgnoreCompare {
}
测试数据
@Data
public class Menu {
@IgnoreCompare
private Integer id;
private Integer parentId;
private int sort;
}
测试代码
public static void main(String[] args) {
Menu menu1 = new Menu();
menu1.setSort(11);
menu1.setParentId(3);
menu1.setId(2);
MenuTest1 menu2 = new MenuTest1();
menu2.setSort("aa");
menu2.setParentId(3);
menu2.setId(21);
List<ComparableResult> results = ComparableUtils.compareInstance(menu1, menu2);
for (ComparableResult result : results) {
System.out.print("字段:" + result.getFieldName());
System.out.print(" 由:" + result.getOldFieldContent());
System.out.print(" 变更成:" + result.getNewFieldContent());
System.out.println(" 变更类型:" + DataChangeType.valueOf(result.getDataChangeType()).getName());
System.out.println("-------------------------");
}
}
测试结果
字段:sort 由:11 变更成:aa 变更类型:修改
-------------------------