文章目录
- 前言
- 一、如何对比
- 二、开始编码
- 三、使用结果示例
- 总结
前言
需求如下:
对比两个bean中的内容,返回其中属性的值不一致的完整信息,包括: 属性 新值 旧值
一、如何对比
例如我有一个这的类型:
public class Tel {
private String name;
private String tel;
}
我new 两个出来,然后比对
Tel tel = new Tel("小明","123)
Tel tel2 = new Tel("小红","123)
比对后应该输出: name 小明 小红
二、开始编码
package xx.main;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.test.bean.Res;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ClassUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 对线属性值对比
*
* @author: fulin
* @since: 2024-08-02
**/
@Slf4j
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanCompareUtil {
/**
* 全量比对两个对线
*
* @param source 来源对象
* @param target 目标对象
* @return 对比结果
*/
public static List<Res> compareBean(Object source, Object target) {
List<Res> resList = CollUtil.newArrayList();
handleCompare(source, target, resList, source.getClass().getSimpleName());
return resList;
}
/**
* 部分比对
*
* @param source 来源对象
* @param target 目标对象
* @param fileList 需要比对的字段
* @return 对比结果
*/
public static List<Res> compareBean(Object source, Object target, String... fileList) {
List<Res> resList = CollUtil.newArrayList();
handleCompare(source, target, resList, source.getClass().getSimpleName(), fileList);
return resList;
}
private static void handleCompare(Object source, Object target, List<Res> resList, String className, String... fileList) {
if (ObjectUtil.isNull(source) || ObjectUtil.isNull(target)) {
return;
}
Field[] declaredFields = source.getClass().getDeclaredFields();
if (ObjectUtil.isNotEmpty(declaredFields) && ObjectUtil.isNotEmpty(fileList)) {
declaredFields = Arrays.stream(declaredFields).filter(field -> Arrays.stream(fileList).distinct().anyMatch(file -> file.equals(field.getName()))).toArray(Field[]::new);
}
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
Class<?> type = declaredField.getType();
Object fieldValue = BeanUtil.getFieldValue(source, declaredField.getName());
Object fieldValue2 = BeanUtil.getFieldValue(target, declaredField.getName());
String classNameStr = className + StrUtil.DASHED + declaredField.getName();
if (!ClassUtils.isPrimitiveOrWrapper(type) && !type.equals(String.class)) {
if (fieldValue instanceof List) {
List<Object> list = (List<Object>) fieldValue;
List<Object> list2 = (List<Object>) fieldValue2;
for (int i = 0; i < list.size(); i++) {
handleCompare(list.get(i), list2.get(i), resList, classNameStr, fileList);
}
} else if (fieldValue instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) fieldValue;
Map<Object, Object> map2 = (Map<Object, Object>) fieldValue2;
map.forEach((k, v) -> {
handleCompare(v, map2.get(k), resList, classNameStr, fileList);
});
} else {
handleCompare(fieldValue, fieldValue2, resList, classNameStr, fileList);
}
} else {
Object property = BeanUtil.getProperty(source, declaredField.getName());
Object property2 = BeanUtil.getProperty(target, declaredField.getName());
if (ObjectUtil.notEqual(property, property2)) {
log.info("字段: {},旧值:{},新值:{}", classNameStr, property, property2);
resList.add(new Res(declaredField.getName(), property, property2));
}
}
}
}
}
三、使用结果示例
根据一个复杂的类 ,构造两个属性值不同的对象,然后测试
package xx.main;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.example.test.bean.Res;
import com.example.test.bean.Student;
import com.example.test.bean.Tel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.util.ClassUtils;
import xx.bean.CpuInfo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* @author fulin
* @since 2024/8/2 16:17
*/
@Slf4j
public class 比对 {
public static void main(String[] args) {
Tel tel = new Tel();
tel.setTel("123456789");
tel.setName("张3");
Tel tel2 = new Tel();
tel2.setTel("1234589");
tel2.setName("张三");
CpuInfo cpuInfo = new CpuInfo();
cpuInfo.setCpu(2);
cpuInfo.setMem(8);
cpuInfo.setDisk(100);
cpuInfo.setStudent(new Student(1, "张三", 45, Collections.singletonList(tel)));
CpuInfo cpuInfo2 = new CpuInfo();
cpuInfo2.setCpu(20);
cpuInfo2.setMem(81);
cpuInfo2.setDisk(100);
cpuInfo2.setStudent(new Student(1, "李四", 41, Collections.singletonList(tel2)));
System.out.println(JSONUtil.toJsonStr(cpuInfo));
System.out.println(JSONUtil.toJsonStr(cpuInfo2));
List<Res> resList = BeanCompareUtil.compareBean(cpuInfo, cpuInfo2);
System.out.println(JSONUtil.toJsonStr(resList));
List<Res> resList2 = BeanCompareUtil.compareBean(cpuInfo, cpuInfo2, "cpu", "mem");
System.out.println(JSONUtil.toJsonStr(resList2));
}
}
- 执行结果如下:
{"student":{"tels":[{"name":"张3","tel":"123456789"}],"name":"张三","id":1,"age":45},"cpu":2,"disk":100,"mem":8} {"student":{"tels":[{"name":"张三","tel":"1234589"}],"name":"李四","id":1,"age":41},"cpu":20,"disk":100,"mem":81} 20:54:07.624 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-cpu,旧值:2,新值:20 20:54:07.626 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-mem,旧值:8,新值:81 20:54:07.627 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-student-name,旧值:张三,新值:李四 20:54:07.627 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-student-age,旧值:45,新值:41 20:54:07.627 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-student-tels-name,旧值:张3,新值:张三 20:54:07.627 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-student-tels-tel,旧值:123456789,新值:1234589 [{"old":2,"file":"cpu","now":20},{"old":8,"file":"mem","now":81},{"old":"张三","file":"name","now":"李四"},{"old":45,"file":"age","now":41},{"old":"张3","file":"name","now":"张三"},{"old":"123456789","file":"tel","now":"1234589"}] 20:54:07.632 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-cpu,旧值:2,新值:20 20:54:07.632 [main] INFO xx.main.BeanCompareUtil - 字段: CpuInfo-mem,旧值:8,新值:81 [{"old":2,"file":"cpu","now":20},{"old":8,"file":"mem","now":81}]
总结
找了很多工具类都没有找到,然后自己动手封装了一个,希望能给后来人带来参考;
虽说是自己封装的,但实际也是站在巨人的肩膀,基于 hutool jdk 等工具类