如何比较两个对象字段的差异,对象比较工具类实现

一、概述

ModelDiffUtil 的工具类,用于比较两个对象之间的差异,并将差异以Map的形式返回。该类的主要方法是diffToMap,它接受两个对象作为输入,并可选地接受一个忽略字段的列表。该方法首先将输入对象转换为JSON字符串,然后将JSON字符串转换为Map,最后比较两个Map的差异并返回结果。该类还包含一些辅助方法,如convertJsonToMapdoCompare,用于处理JSON到Map的转换和比较两个Map的差异。

二、方法说明

1、getDiffMap(T sourceObject, T targetObject)

将两个对象的差异转换为 Map 格式。

调用示例:

class User {
    private String name;
    private int age;

    // 构造函数、getter 和 setter 方法
}

User sourceUser = new User();
sourceUser.setName("Alice");
sourceUser.setAge(25);

User targetUser = new User();
targetUser.setName("Bob");
targetUser.setAge(30);

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceUser, targetUser);

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  },
  "age": {
    "source": "25",
    "target": "30"
  }
}

2、getDiffMap(T sourceObject, T targetObject, List<String> ignoreFields)

将两个对象的差异转换为 Map 格式,可以指定忽略的字段。

调用示例:

List<String> ignoreFields = Arrays.asList("age");
User sourceUser = new User();
sourceUser.setName("Alice");
sourceUser.setAge(25);

User targetUser = new User();
targetUser.setName("Bob");
targetUser.setAge(30);

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceUser, targetUser, ignoreFields);  

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  }
}

3、 getDiffMap(String sourceJsonStr, String targetJsonStr)

从两个 JSON 字符串中提取差异。

调用示例:

String sourceJsonStr = "{\"name\":\"Alice\",\"age\":25}";
String targetJsonStr = "{\"name\":\"Bob\",\"age\":30}";

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceJsonStr, targetJsonStr);  

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  },
  "age": {
    "source": "25",
    "target": "30"
  }
}

4、 diffToMap(String sourceJsonStr, String targetJsonStr, List<String> ignoreFields)

从两个 JSON 字符串中提取差异,可以指定忽略的字段。

调用示例

String sourceJsonStr = "{\"name\":\"Alice\",\"age\":25}";
String targetJsonStr = "{\"name\":\"Bob\",\"age\":30}";

List<String> ignoreFields = Arrays.asList("age");

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceJsonStr, targetJsonStr, ignoreFields);

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  }
}

三、内部方法
1、convertJsonToMap(Object json, String root, Map<String, Object> resultMap, List<String> ignoreFields)

  • 功能:将 JSON 对象转换为 Map ,忽略指定的字段。 - 这是一个内部辅助方法,通常不会被外部直接调用。
    2、doCompare(Map<String, Object> sourceMap, Map<String, Object> targetMap)
  • 功能:执行实际的比较操作,更新 sourceMap 以反映差异。 - 这是一个内部辅助方法,通常不会被外部直接调用。
  1. compareSourceMapWithTargetMap(Map<String, Object> sourceMap)
  • 功能:比较 sourceMaptargetMap ,处理 sourceMap 中独有的项。 - 这是一个内部辅助方法,通常不会被外部直接调用。
  1. compareTargetMapWithSourceMap(Map<String, Object> sourceMap, Map<String, Object> targetMap)
  • 功能:比较 sourceMaptargetMap ,处理 targetMap 中独有的或已更改的项。 - 这是一个内部辅助方法,通常不会被外部直接调用。

    1. processEntry(Map<String, Object> sourceMap, String key, Object value, Object targetValue)
    • 功能:处理单个条目的逻辑,根据提供的值构建差异映射或移除条目。 - 这是一个内部辅助方法,通常不会被外部直接调用。 这个工具类在需要比较对象差异并以特定格式获取结果的场景中非常有用,例如数据同步、版本控制、数据审计等。

二、完整的代码

pom依赖:

<dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
   <version>2.8.8</version>
</dependency>

完整代码:

import com.ecwid.consul.json.GsonFactory;
import com.google.gson.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;

/**
 * @author: fhey
 * @create: 2022-04-26 15:29
 * @description: 对象比较工具类
 */
@Slf4j
public class ModelDiffUtil {

    private static final Gson gson = GsonFactory.getGson();
    private final static String SOURCE_VALUE = "source";
    private final static String TARGET_VALUE = "target";
    private final static String DOT_SEPARATOR = ".";

    /**
     * 将两个对象的差异转换为Map格式。
     *
     * @param sourceObject  原始对象
     * @param targetObject 当前对象
     * @return 包含差异的Map
     */
    public static<T> Map<String, Map<String, String>> getDiffMap(T sourceObject, T targetObject) {
        return getDiffMap(sourceObject, targetObject, null);
    }

    /**
     * 将两个对象的差异转换为Map格式,可以指定忽略的字段。
     *
     * @param sourceObject  原始对象
     * @param targetObject 当前对象
     * @param ignoreFields  忽略的字段列表
     * @return 包含差异的Map
     */
    public static <T> Map<String, Map<String, String>> getDiffMap(T sourceObject, T targetObject, List<String> ignoreFields) {
        try {
            String sourceJsonStr = gson.toJson(sourceObject);
            String targetJsonStr = gson.toJson(targetObject);
            return getDiffMap(sourceJsonStr, targetJsonStr, ignoreFields);
        } catch (JsonSyntaxException e) {
            log.error("Failed to parse object to JSON", e);
            return new HashMap<>();
        }
    }

    /**
     * 从JSON字符串中提取差异。
     *
     * @param sourceJsonStr  原始JSON字符串
     * @param targetJsonStr 当前JSON字符串
     * @return 包含差异的Map
     */
    public static Map<String, Map<String, String>> getDiffMap(String sourceJsonStr, String targetJsonStr) {
        return getDiffMap(sourceJsonStr, targetJsonStr, null);
    }

    /**
     * 从JSON字符串中提取差异,可以指定忽略的字段。
     *
     * @param sourceJsonStr  原始JSON字符串
     * @param targetJsonStr 当前JSON字符串
     * @param ignoreFields   忽略的字段列表
     * @return 包含差异的Map
     */
    public static Map<String, Map<String, String>> getDiffMap(String sourceJsonStr, String targetJsonStr, List<String> ignoreFields) {
        try {
            JsonObject sourceJson = new JsonParser().parse(sourceJsonStr).getAsJsonObject();
            JsonObject targetJson = new JsonParser().parse(targetJsonStr).getAsJsonObject();
            Map<String, String> sourceMap = new LinkedHashMap<>();
            Map<String, String> targetMap = new LinkedHashMap<>();
            convertJsonToMap(sourceJson, StringUtils.EMPTY, sourceMap, ignoreFields);
            convertJsonToMap(targetJson, StringUtils.EMPTY, targetMap, ignoreFields);
            return doCompare(sourceMap, targetMap);
        } catch (JsonSyntaxException e) {
            log.error("Failed to parse JSON string", e);
            return new HashMap<>();
        }
    }

    /**
     * 将JSON对象转换为Map,忽略指定的字段。
     *
     * @param json         JSON对象
     * @param root         当前JSON路径
     * @param resultMap    存储转换结果的Map
     * @param ignoreFields 忽略的字段列表
     */
    /**
     * 将JSON对象转换为Map,忽略指定的字段。
     *
     * @param json         JSON对象
     * @param root         当前JSON路径
     * @param resultMap    存储转换结果的Map
     * @param ignoreFields 忽略的字段列表
     */
    private static void convertJsonToMap(JsonElement json, String root, Map<String, String> resultMap, List<String> ignoreFields) {
        if (json.isJsonObject()) {
            JsonObject jsonObject = json.getAsJsonObject();
            for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
                String key = entry.getKey();
                if (CollectionUtils.isNotEmpty(ignoreFields) && ignoreFields.contains(key)) {
                    continue;
                }
                JsonElement value = entry.getValue();
                String newRoot = (root.isEmpty())? key : root + DOT_SEPARATOR + key;
                if (value.isJsonObject() || value.isJsonArray()) {
                    convertJsonToMap(value, newRoot, resultMap, ignoreFields);
                } else if(value.isJsonPrimitive()){
                    resultMap.put(newRoot, value.getAsJsonPrimitive().getAsString());
                }
            }
        } else if (json.isJsonArray()) {
            JsonArray jsonArray = json.getAsJsonArray();
            for (int i = 0; i < jsonArray.size(); i++) {
                JsonElement value = jsonArray.get(i);
                String newRoot = (root.isEmpty())? "[" + i + "]" : root + "[" + i + "]";
                if (value.isJsonObject() || value.isJsonArray()) {
                    convertJsonToMap(value, newRoot, resultMap, ignoreFields);
                } else if(value.isJsonPrimitive()){
                    resultMap.put(newRoot, value.getAsJsonPrimitive().getAsString());
                }
            }
        }
    }

    /**
     * 执行实际的比较操作,返回包含差异的Map
     *
     * @param sourceMap  原始Map
     * @param targetMap 当前Map
     * @return 包含差异的Map
     */
    private static Map<String, Map<String, String>> doCompare(Map<String, String> sourceMap, Map<String, String> targetMap) {
        Map<String, Map<String, String>> diffMap = new HashMap<>();
        for (Map.Entry<String, String> entry : targetMap.entrySet()) {
            String key = entry.getKey();
            String newValue = entry.getValue();
            String oldValue = sourceMap.get(key);
            if (sourceMap.containsKey(key)) {
                if (!ObjectUtils.equals(newValue, oldValue)) {
                    addDiffMap(diffMap, key, oldValue, newValue);
                }
            } else {
                addDiffMap(diffMap, key, StringUtils.EMPTY, newValue);
            }
        }
        return diffMap;
    }


    /**
     * 将差异项添加到差异映射中。
     *
     * 此方法用于在处理两个数据集的差异时,将特定的差异项添加到一个映射中,
     * 其中每个差异项由一个键值对表示,包括源值和目标值。
     *
     * @param diffMap 保存差异项的映射,其中键是差异项的标识,值是包含源值和目标值的映射。
     * @param key 差异项的标识,用于在diffMap中作为键。
     * @param value 源对象中的值,表示差异的起始点。
     * @param targetValue 目标对象中的值,表示与源值不同的目标值。
     */
    private static void addDiffMap(Map<String, Map<String, String>> diffMap, String key, String value, String targetValue) {
        Map<String, String> diffItemMap = new HashMap<>();
        diffItemMap.put(SOURCE_VALUE, value);
        diffItemMap.put(TARGET_VALUE, targetValue);
        diffMap.put(key, diffItemMap);
    }
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 可以这样实现:首先,比较两个实体类字段值,如果不同,则使用ES API更新索引;其次,可以使用Java 8流式编程的方式,对实体类属性进行对比,不同则进行更新操作;最后,使用Apache Commons Lang库提供的ObjectUtils工具类,可以实现Java对象以JSON格式插入ES索引。 ### 回答2: 以下是一个用Java编写的示例代码,用于比较两个对象实体类的字段值并进行更新操作,并插入ES索引: ```java import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.client.RequestOptions; import java.io.IOException; public class ObjectComparisonDemo { public static void main(String[] args) { YourEntityClass object1 = getObject1(); // 第一个对象实例 YourEntityClass object2 = getObject2(); // 第二个对象实例 if (!object1.equals(object2)) { // 检查两个对象是否不同 // 更新对象1的字段值为对象2的字段值 object1.setField1(object2.getField1()); object1.setField2(object2.getField2()); // ... 更新其他字段 // 插入ES索引 RestHighLevelClient client = createElasticsearchClient(); IndexRequest request = new IndexRequest("your_index_name"); request.source(object1.toJson(), XContentType.JSON); try { IndexResponse response = client.index(request, RequestOptions.DEFAULT); if (response.getResult() == IndexResponse.Result.CREATED) { System.out.println("数据插入ES索引成功!"); } else { System.out.println("数据插入ES索引失败!"); } } catch (IOException e) { e.printStackTrace(); } finally { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 创建Elasticsearch客户端 private static RestHighLevelClient createElasticsearchClient() { // 根据实际情况配置Elasticsearch连接参数并创建客户端 return new RestHighLevelClient(/* Elasticsearch连接参数配置 */); } // 返回第一个对象实例的示例方法,请根据实际情况替换成自己的实现 private static YourEntityClass getObject1() { YourEntityClass object1 = new YourEntityClass(); // 设置对象1的字段值 object1.setField1("value1"); object1.setField2("value2"); // ... 设置其他字段的值 return object1; } // 返回第二个对象实例的示例方法,请根据实际情况替换成自己的实现 private static YourEntityClass getObject2() { YourEntityClass object2 = new YourEntityClass(); // 设置对象2的字段值 object2.setField1("updatedValue1"); object2.setField2("updatedValue2"); // ... 设置其他字段的值 return object2; } } // 你的实体类示例,请根据实际情况替换成自己的实现 class YourEntityClass { private String field1; private String field2; // ... 其他字段 // getter和setter方法 public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } // JSON序列化方法 public String toJson() { // 根据实际情况将对象转为JSON字符串 // 使用第三方库,如Gson、Jackson等 return /* 返回JSON字符串 */; } } ``` 这个示例程序包含了以下内容: 1. `YourEntityClass`类:代表你的实体类,其中包含了需要对比的字段和相关的getter和setter方法。 2. `getObject1()`和`getObject2()`方法:实例化第一个和第二个对象实例的示例方法,你需要根据实际情况替换成自己的实现。 3. `RestHighLevelClient`类:用于与Elasticsearch服务进行交互,你需要根据实际情况配置Elasticsearch连接参数并创建客户端。 4. 对象实例的字段值对比逻辑:通过比较两个对象实例的字段值是否相等,如果不相等,则将对象1的字段值更新为对象2的字段值。 5. 在字段值更新后,将对象1的内容插入到Elasticsearch索引中。 ### 回答3: 在Java中,对比两个对象实体类字段的值并进行更新操作,然后插入ES索引的示例代码如下: 首先,我们假设有一个实体类Person,它有几个字段:id、name、age。 ```java public class Person { private long id; private String name; private int age; // 省略构造函数、getter和setter方法 } ``` 接下来,我们使用一个新的Person对象实例来和已有的Person对象进行对比,判断是否有字段值不同,然后进行更新操作和插入ES索引。 ```java Person existingPerson = ...; // 已有的Person对象 Person newPerson = ...; // 新的Person对象 // 对比id字段 if (existingPerson.getId() != newPerson.getId()) { existingPerson.setId(newPerson.getId()); } // 对比name字段 if (!existingPerson.getName().equals(newPerson.getName())) { existingPerson.setName(newPerson.getName()); } // 对比age字段 if (existingPerson.getAge() != newPerson.getAge()) { existingPerson.setAge(newPerson.getAge()); } // 更新操作 update(existingPerson); // 插入ES索引 insertIntoES(existingPerson); ``` 上述代码逐个字段对比,如果字段值不同就进行更新操作。在实际应用中,可能需要根据具体的业务需求来调整对比逻辑。 更新操作和插入ES索引的具体实现方法根据使用的技术栈不同而有所差异,比如使用Hibernate时,可以使用`Session.update()`方法来更新数据库记录;使用Elasticsearch时,可以使用相应的Java客户端库来插入ES索引。 总之,以上示例代码提供了一个基本的框架,通过对比字段值的方式来实现更新操作和插入ES索引。根据具体的业务需求和技术栈选择相应的实现方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知北游z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值