比力两个JSON之间的差异

打印 上一主题 下一主题

主题 546|帖子 546|积分 1638

网上找到的比力JSON工具类,比力两个JSON对象之间的差异,并将差异字段按照原JSON对象的树状结构显现出来,方便对数据举行对比。对原有方法举行了部分优化。
  1. package com.summer.toolkit.util;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.commons.collections4.CollectionUtils;
  7. import java.util.*;
  8. /**
  9. * @author author
  10. */
  11. @Slf4j
  12. public class CompareJsonUtils {
  13.     /**
  14.      * 正则表达式,匹配数组下标,如:[0]、[1]
  15.      */
  16.     public static final String PATTERN = "\\[[0-9]+\\]";
  17.     /**
  18.      * 分隔符
  19.      */
  20.     public static final String REGEX = "\\.";
  21.     /**
  22.      * 连接符
  23.      */
  24.     public static final String CONNECTOR = ".";
  25.     /**
  26.      * 旧的数据Key值
  27.      */
  28.     public static final String OLD_VALUE_KEY = "oldValue";
  29.     /**
  30.      * 新的数据Key值
  31.      */
  32.     public static final String NEW_VALUE_KEY = "newValue";
  33.     /**
  34.      * 将两个JSON对象进行比较
  35.      *
  36.      * @param oldJsonStr 旧的JSON字符串
  37.      * @param newJsonStr 新的JSON字符串
  38.      * @return 比较结果转换为JSON字符串
  39.      */
  40.     public static String compareJsonObject(String oldJsonStr, String newJsonStr) {
  41.         // 默认不排除字段
  42.         List<String> excludes = new ArrayList<>();
  43.         return CompareJsonUtils.compareJsonObject(oldJsonStr, newJsonStr, excludes);
  44.     }
  45.     /**
  46.      * 比较两个JSON对象,排除指定字段后的差异
  47.      *
  48.      * @param oldJsonStr 旧的JSON字符串
  49.      * @param newJsonStr 新的JSON字符串
  50.      * @param excludes   需要排除比较的字段列表
  51.      * @return 返回排除指定字段后的差异JSON对象
  52.      */
  53.     public static String compareJsonObject(String oldJsonStr, String newJsonStr, List<String> excludes) {
  54.         // 将字符串转换为json对象
  55.         JSON oldJson = JSON.parseObject(oldJsonStr);
  56.         JSON newJson = JSON.parseObject(newJsonStr);
  57.         // 递归遍历json对象所有的key-value,将其封装成path:value格式进行比较
  58.         Map<String, Object> oldMap = new LinkedHashMap<>(32);
  59.         Map<String, Object> newMap = new LinkedHashMap<>(32);
  60.         CompareJsonUtils.convertJsonToMap(oldJson, "", oldMap);
  61.         CompareJsonUtils.convertJsonToMap(newJson, "", newMap);
  62.         // 去掉不需要对比的字段
  63.         CompareJsonUtils.excludeFields(oldMap, excludes);
  64.         CompareJsonUtils.excludeFields(newMap, excludes);
  65.         // 比较两个map,返回不同数据
  66.         Map<String, Object> temp = new LinkedHashMap<>(oldMap);
  67.         Map<String, Object> differenceMap = CompareJsonUtils.compareMap(temp, newMap);
  68.         // 将最终的比较结果把不相同的转换为json对象返回
  69.         JSONObject result = CompareJsonUtils.convertMapToJson(differenceMap);
  70.         log.info("对比JSON结果为:{}", result);
  71.         return JSON.toJSONString(result);
  72.     }
  73.     /**
  74.      * 从给定的Map中排除指定的字段
  75.      *
  76.      * @param map      包含字段的Map
  77.      * @param excludes 要排除的字段列表
  78.      */
  79.     public static void excludeFields(Map<String, Object> map, List<String> excludes) {
  80.         if (Objects.nonNull(map) && CollectionUtils.isNotEmpty(excludes)) {
  81.             Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
  82.             while (iterator.hasNext()) {
  83.                 Map.Entry<String, Object> entry = iterator.next();
  84.                 if (Objects.nonNull(entry)) {
  85.                     if (excludes.contains(entry.getKey())) {
  86.                         iterator.remove();
  87.                     }
  88.                 }
  89.             }
  90.         }
  91.     }
  92.     /**
  93.      * 将json数据转换为map存储用于比较
  94.      *
  95.      * @param json      JSON对象
  96.      * @param root      根对象名称
  97.      * @param resultMap 结果
  98.      */
  99.     private static void convertJsonToMap(Object json, String root, Map<String, Object> resultMap) {
  100.         if (json instanceof JSONObject) {
  101.             JSONObject jsonObject = ((JSONObject) json);
  102.             for (String key : jsonObject.keySet()) {
  103.                 Object value = jsonObject.get(key);
  104.                 String newRoot = "".equals(root) ? key + "" : root + CompareJsonUtils.CONNECTOR + key;
  105.                 if (value instanceof JSONObject || value instanceof JSONArray) {
  106.                     CompareJsonUtils.convertJsonToMap(value, newRoot, resultMap);
  107.                 } else {
  108.                     resultMap.put(newRoot, value);
  109.                 }
  110.             }
  111.         } else if (json instanceof JSONArray) {
  112.             JSONArray jsonArray = (JSONArray) json;
  113.             for (int i = 0; i < jsonArray.size(); i++) {
  114.                 Object value = jsonArray.get(i);
  115.                 String newRoot = "".equals(root) ? "[" + i + "]" : root + ".[" + i + "]";
  116.                 if (value instanceof JSONObject || value instanceof JSONArray) {
  117.                     CompareJsonUtils.convertJsonToMap(value, newRoot, resultMap);
  118.                 } else {
  119.                     resultMap.put(newRoot, value);
  120.                 }
  121.             }
  122.         }
  123.     }
  124.     /**
  125.      * 比较两个map,返回不同数据
  126.      *
  127.      * @param oldMap 旧数据MAP对象
  128.      * @param newMap 新数据MAP对象
  129.      * @return 返回值,两者的差异
  130.      */
  131.     private static Map<String, Object> compareMap(Map<String, Object> oldMap, Map<String, Object> newMap) {
  132.         // 遍历newMap,将newMap的不同数据装进oldMap,同时删除oldMap中与newMap相同的数据
  133.         CompareJsonUtils.compareNewToOld(oldMap, newMap);
  134.         // 将旧的有新的没有的数据封装数据结构存在旧的里面
  135.         CompareJsonUtils.compareOldToNew(oldMap);
  136.         return oldMap;
  137.     }
  138.     /**
  139.      * 将旧的有新的没有的数据封装数据结构存在旧的里面
  140.      *
  141.      * @param oldMap 旧数据结构
  142.      */
  143.     private static void compareOldToNew(Map<String, Object> oldMap) {
  144.         // 统一oldMap中newMap不存在的数据的数据结构,便于解析
  145.         for (Map.Entry<String, Object> item : oldMap.entrySet()) {
  146.             String key = item.getKey();
  147.             Object value = item.getValue();
  148.             if (!(value instanceof Map)) {
  149.                 // 此处并没有添加数据,而是将key值对应的value值进行修改,所以并没有改变map的数量
  150.                 Map<String, Object> differenceMap = CompareJsonUtils.buildDifferenceMap(value, "");
  151.                 oldMap.put(key, differenceMap);
  152.             }
  153.         }
  154.     }
  155.     /**
  156.      * 将新的map与旧的比较,并将数据统一存在旧的里面
  157.      *
  158.      * @param oldMap 旧数据
  159.      * @param newMap 新数据
  160.      */
  161.     private static void compareNewToOld(Map<String, Object> oldMap, Map<String, Object> newMap) {
  162.         for (Map.Entry<String, Object> item : newMap.entrySet()) {
  163.             String key = item.getKey();
  164.             Object newValue = item.getValue();
  165.             if (oldMap.containsKey(key)) {
  166.                 Object oldValue = oldMap.get(key);
  167.                 if (newValue.equals(oldValue)) {
  168.                     oldMap.remove(key);
  169.                 } else {
  170.                     Map<String, Object> differenceMap = CompareJsonUtils.buildDifferenceMap(oldValue, newValue);
  171.                     oldMap.put(key, differenceMap);
  172.                 }
  173.             } else {
  174.                 Map<String, Object> differenceMap = CompareJsonUtils.buildDifferenceMap("", newValue);
  175.                 oldMap.put(key, differenceMap);
  176.             }
  177.         }
  178.     }
  179.     /**
  180.      * 将已经找出不同数据的map根据key的层级结构封装成json返回
  181.      *
  182.      * @param map 入参
  183.      * @return 返回值
  184.      */
  185.     private static JSONObject convertMapToJson(Map<String, Object> map) {
  186.         JSONObject resultJsonObject = new JSONObject();
  187.         for (Map.Entry<String, Object> item : map.entrySet()) {
  188.             String key = item.getKey();
  189.             Object value = item.getValue();
  190.             String[] paths = key.split(CompareJsonUtils.REGEX);
  191.             int i = 0;
  192.             // 用于深度标识对象
  193.             Object remarkObject = null;
  194.             int indexAll = paths.length - 1;
  195.             while (i <= paths.length - 1) {
  196.                 String path = paths[i];
  197.                 if (i == 0) {
  198.                     // 初始化对象标识
  199.                     if (resultJsonObject.containsKey(path)) {
  200.                         remarkObject = resultJsonObject.get(path);
  201.                     } else {
  202.                         if (indexAll > i) {
  203.                             if (paths[i + 1].matches(CompareJsonUtils.PATTERN)) {
  204.                                 remarkObject = new JSONArray();
  205.                             } else {
  206.                                 remarkObject = new JSONObject();
  207.                             }
  208.                             resultJsonObject.put(path, remarkObject);
  209.                         } else {
  210.                             resultJsonObject.put(path, value);
  211.                         }
  212.                     }
  213.                     i++;
  214.                     continue;
  215.                 }
  216.                 // 匹配集合对象
  217.                 if (path.matches(CompareJsonUtils.PATTERN)) {
  218.                     int startIndex = path.lastIndexOf("[");
  219.                     int endIndext = path.lastIndexOf("]");
  220.                     int index = Integer.parseInt(path.substring(startIndex + 1, endIndext));
  221.                     if (indexAll > i) {
  222.                         if (paths[i + 1].matches(CompareJsonUtils.PATTERN)) {
  223.                             while (((JSONArray) remarkObject).size() <= index) {
  224.                                 if (((JSONArray) remarkObject).size() == index) {
  225.                                     ((JSONArray) remarkObject).add(index, new JSONArray());
  226.                                 } else {
  227.                                     //((JSONArray) remarkObject).add(null);
  228.                                     ((JSONArray) remarkObject).add(new JSONObject());
  229.                                 }
  230.                             }
  231.                         } else {
  232.                             while (((JSONArray) remarkObject).size() <= index) {
  233.                                 if (((JSONArray) remarkObject).size() == index) {
  234.                                     ((JSONArray) remarkObject).add(index, new JSONObject());
  235.                                 } else {
  236.                                     //((JSONArray) remarkObject).add(null);
  237.                                     ((JSONArray) remarkObject).add(new JSONObject());
  238.                                 }
  239.                             }
  240.                         }
  241.                         remarkObject = ((JSONArray) remarkObject).get(index);
  242.                     } else {
  243.                         while (Objects.nonNull(remarkObject) && ((JSONArray) remarkObject).size() <= index) {
  244.                             if (((JSONArray) remarkObject).size() == index) {
  245.                                 ((JSONArray) remarkObject).add(index, value);
  246.                             } else {
  247.                                 //((JSONArray) remarkObject).add(null);
  248.                                 ((JSONArray) remarkObject).add(new JSONObject());
  249.                             }
  250.                         }
  251.                     }
  252.                 } else {
  253.                     if (indexAll > i) {
  254.                         if (paths[i + 1].matches(CompareJsonUtils.PATTERN)) {
  255.                             if (!((JSONObject) remarkObject).containsKey(path)) {
  256.                                 ((JSONObject) remarkObject).put(path, new JSONArray());
  257.                             }
  258.                         } else {
  259.                             if (!((JSONObject) remarkObject).containsKey(path)) {
  260.                                 ((JSONObject) remarkObject).put(path, new JSONObject());
  261.                             }
  262.                         }
  263.                         remarkObject = ((JSONObject) remarkObject).get(path);
  264.                     } else if (Objects.nonNull(remarkObject)) {
  265.                         ((JSONObject) remarkObject).put(path, value);
  266.                     }
  267.                 }
  268.                 i++;
  269.             }
  270.         }
  271.         return resultJsonObject;
  272.     }
  273.     /**
  274.      * 构建差异Map,用于比较旧值和新值之间的差异
  275.      *
  276.      * @param oldValue 旧值
  277.      * @param newValue 新值
  278.      * @return differenceMap 差异Map,包含'oldValue'和'newValue'两个键值对
  279.      */
  280.     public static Map<String, Object> buildDifferenceMap(Object oldValue, Object newValue) {
  281.         Map<String, Object> differenceMap = new HashMap<>(4);
  282.         differenceMap.put(CompareJsonUtils.OLD_VALUE_KEY, oldValue);
  283.         differenceMap.put(CompareJsonUtils.NEW_VALUE_KEY, newValue);
  284.         return differenceMap;
  285.     }
  286.     /**
  287.      * 比较两个JSON对象并返回它们之间的差异
  288.      */
  289.     public static void main(String[] args) {
  290.         String oldStr = "{a:'aaa',b:'bbb',c:'aaa',d:'bbb'}";
  291.         String newStr = "{a:'aa',b:'bb',e:'bb'}";
  292.         System.out.println(CompareJsonUtils.compareJsonObject(oldStr, newStr));
  293.     }
  294. }
复制代码
以上测试方法结果为:
  1. {
  2.     "b": {
  3.         "newValue": "bb",
  4.         "oldValue": "bbb"
  5.     },
  6.     "c": {
  7.         "newValue": "",
  8.         "oldValue": "aaa"
  9.     },
  10.     "d": {
  11.         "newValue": "",
  12.         "oldValue": "bbb"
  13.     },
  14.     "e": {
  15.         "newValue": "bb",
  16.         "oldValue": ""
  17.     }
  18. }
复制代码
参考链接:【Java】Java对比两个JSON对象(深度广度比力)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表