一、背景
当两个对象有多个字段需要逐个比较时,为了避免使用多个if分支进行比较,需要使用工具类进行包装,减少代码开发量
二、详细方案
方案一:ObjectMapper工具
代码详情
@Data
public static class A {
private Long id;
private String name;
// private LocalDateTime time;
}
@com.fasterxml.jackson.annotation.JsonFilter("myObjectFilter")
private static class ObjectMixin {
}
private static final ObjectMapper MAPPER = new ObjectMapper();
public static void main(String[] args) {
//需要排除字段
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept("id");
//过滤器
FilterProvider filters = new SimpleFilterProvider().addFilter("myObjectFilter", filter);
final LocalDateTime now = LocalDateTime.now();
final A a = new A();
a.setName("haha");
a.setTime(now);
final A b = new A();
b.setName("hehe");
b.setTime(now);
try {
MAPPER.addMixIn(A.class, ObjectMixin.class);
String jsonString1 = MAPPER.writer(filters).writeValueAsString(a);
String jsonString2 = MAPPER.writer(filters).writeValueAsString(b);
System.out.println(jsonString1);
System.out.println(jsonString2);
System.out.println(jsonString1.equals(jsonString2));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
方案二:org.springframework.beans.BeanWrapperImpl工具
代码详情
1、工具类
/**
* 将Bean对象转换为属性映射的键值对
*
* @param oldBean 旧的Bean对象
* @param newBean 新的Bean对象
* @param excludeFields 需要排除的字段列表
* @param <T> Bean对象的类型
* @return 包含旧Bean对象属性映射和新Bean对象属性映射的键值对
*/
private <T> Pair<Map<String, Object>, Map<String, Object>> convertBean(T oldBean,
T newBean,
List<String> excludeFields) {
final BeanWrapperImpl oldBeanWrapper = new BeanWrapperImpl(oldBean);
final BeanWrapperImpl newBeanWrapper = new BeanWrapperImpl(newBean);
Map<String, Object> oldMap = getPropertyMap(oldBeanWrapper, excludeFields);
Map<String, Object> newMap = getPropertyMap(newBeanWrapper, excludeFields);
return Pair.of(oldMap, newMap);
}
/**
* 获取Bean对象的属性映射
* 只需要原生的字段,不需要class字段
*
* @param beanWrapper Bean对象的包装器
* @param excludeFields 需要排除的字段列表
* @return 属性映射的键值对
*/
private Map<String, Object> getPropertyMap(BeanWrapperImpl beanWrapper, List<String> excludeFields) {
Map<String, Object> propertyMap = new HashMap<>();
PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();
for (PropertyDescriptor descriptor : propertyDescriptors) {
String name = descriptor.getName();
if (!excludeFields.contains(name) && !CLASS.equals(name)) {
Object propertyValue = beanWrapper.getPropertyValue(name);
propertyMap.put(name, propertyValue);
}
}
return propertyMap;
}```
2、详细使用
```java
private void compareMiddleData(YqDataMiddleData oldMiddleData,
YqDataMiddleData newMiddleData) {
Long leafId = oldMiddleData.getLeafId();
//排除不比较字段
final List<String> excludeFields = Arrays.asList("id", "washTime", "nluAttitude",
"extraData", "marks", "createTime", "updateTime");
// 将两个对象转换为Map,排除不比较的字段
Pair<Map<String, Object>, Map<String, Object>> mapBeanPair =
convertBean(oldMiddleData, newMiddleData, excludeFields);
Map<String, Object> oldMap = mapBeanPair.getLeft();
Map<String, Object> newMap = mapBeanPair.getRight();
// 比较中间数据表的详细字段,遍历旧数据的Map,如果对应的值与新数据的Map中的值不相等,则记录日志并触发Cat事件。
oldMap.forEach((k, v) -> {
if (!v.equals(newMap.get(k))) {
log.warn("中间数据比对不通过, 字段:{}", k);
Cat.logEvent(MIDDLE_DATA_COMPARE_RESULT, String.valueOf(leafId));
}
});
}``