import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Data; import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.util.*; @Slf4j public class JsonComparatorUtils { private static final ObjectMapper mapper = new ObjectMapper(); public static void main(String[] args) throws IOException { String jsonBefore = "{"internal": false, "data": {"f8e37381-b7d6-4475-95d3-e763b64306e8": "33", "mw_instanceName": "kkkkkk", "flag": true}, "instanceName": "kkkkkk", "modelId": "104730838641410048", "groupId": "102706472617508864", "templateSearchParam": {"isExportTemp": false}, "type": "instance", "path": ["77170433597636608", "102706472617508864", "104730838641410048"], "itemName": "kkkkkk", "orgIds": [1]}"; String jsonAfter = "{"internal": true, "data": {"f8e37381-b7d6-4475-95d3-e763b64306e8": "33", "mw_instanceName": "llllll", "flag": false}, "instanceName": "kkkkkk", "modelId": "104730838641410048", "groupId": "102706472617508864", "templateSearchParam": {"isExportTemp": false}, "type": "instance", "path": ["77170433597636608", "102706472617508864", "104730838641410048"], "itemName": "kkkkkk", "orgIds": [1]}"; List<String> fieldsToMonitor = Arrays.asList("internal", "instanceName", "mw_instanceName"); JsonNode jsonBeforeNode = mapper.readTree(jsonBefore); JsonNode jsonAfterNode = mapper.readTree(jsonAfter); DiffResult diffResult = generateHtmlWithHighlights(jsonBeforeNode, jsonAfterNode); System.out.println("HTML for json1Before: " + diffResult.getBefore()); System.out.println("HTML for jsonAfter: " + diffResult.getAfter()); } private static DiffResult generateHtmlWithHighlights(JsonNode jsonBeforeNode, JsonNode jsonAfterNode, List<String> fieldsToMonitor) { String jsonBefore = highlightDifference(jsonBeforeNode, jsonAfterNode, fieldsToMonitor); String jsonAfter = highlightDifference(jsonAfterNode, jsonBeforeNode, fieldsToMonitor); return new DiffResult(jsonBefore, jsonAfter); } private static String highlightDifference(JsonNode node1, JsonNode node2, List<String> fieldsToMonitor) { StringBuilder html = new StringBuilder(); if (node1.isObject() && node2.isObject()) { ObjectNode objectNode1 = (ObjectNode) node1; ObjectNode objectNode2 = (ObjectNode) node2; for (String field : fieldsToMonitor) { JsonNode fieldNode1 = findField(objectNode1, field); JsonNode fieldNode2 = findField(objectNode2, field); if (fieldNode1 != null && fieldNode2 != null) { if (!fieldNode1.equals(fieldNode2)) { html.append("<span style='background-color: yellow;'>").append(field).append(": ").append(fieldNode1.asText()).append("</span><br>"); } } else if (fieldNode1 != null) { html.append("<span style='background-color: yellow;'>").append(field).append(": ").append(fieldNode1.asText()).append("</span><br>"); } else if (fieldNode2 != null) { html.append("<span style='background-color: yellow;'>").append(field).append(": ").append(fieldNode2.asText()).append("</span><br>"); } } } return html.toString(); } private static JsonNode findField(ObjectNode node, String fieldName) { if (node.has(fieldName)) { return node.get(fieldName); } for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) { String key = it.next(); JsonNode childNode = node.get(key); if (childNode.isObject()) { JsonNode result = findField((ObjectNode) childNode, fieldName); if (result != null) { return result; } } } return null; } public static DiffResult generateHtmlWithHighlights(JsonNode node1, JsonNode node2) { try { // 获取差异并进行高亮处理 Map<String, String> differences = getDifferences(node1, node2); ObjectMapper newMapper = new ObjectMapper(); ObjectNode highlightedNode = newMapper.createObjectNode(); highlightDifference(node1, differences, highlightedNode, ""); // 将差异节点转换为字符串 String beforeStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(highlightedNode); highlightedNode = newMapper.createObjectNode(); highlightDifference(node2, differences, highlightedNode, ""); // 将差异节点转换为字符串 String afterStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(highlightedNode); // 创建 DiffResult 对象并返回 return new DiffResult(beforeStr, afterStr); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取两个 JSON 对象的差异 * @param node1 before 节点 * @param node2 after 节点 * @return */ private static Map<String, String> getDifferences(JsonNode node1, JsonNode node2) { Map<String, String> differences = new LinkedHashMap<>(); compareJsonNodes(node1, node2, differences); return differences; } /** * 递归比较两个 JSON 节点的差异 * @param node1 before 节点 * @param node2 after 节点 * @param differences 差异字段 */ private static void compareJsonNodes(JsonNode node1, JsonNode node2, Map<String, String> differences) { Iterator<String> fieldNames = node1.fieldNames(); while (fieldNames.hasNext()) { String fieldName = fieldNames.next(); JsonNode fieldValue1 = node1.get(fieldName); JsonNode fieldValue2 = node2.get(fieldName); // 如果是对象类型,则继续比较 if (fieldValue1.isObject() && fieldValue2.isObject()) { compareJsonNodes(fieldValue1, fieldValue2, differences); // 跳过本次后续操作 continue; } if (!Objects.equals(fieldValue1, fieldValue2)) { differences.put(fieldName, fieldValue1.toString()); } } } private static void highlightDifference(JsonNode node, Map<String, String> differences, ObjectNode highlightedNode, String key) { try { Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); ObjectNode objectNode = null; while (fields.hasNext()) { Map.Entry<String, JsonNode> field = fields.next(); String fieldName = field.getKey(); JsonNode fieldValue = field.getValue(); if (fieldValue.isObject()) { // 如果是对象,递归查看内部属性;TODO 其实可以将内部value转map,查看是否存在differences中的字段。是则递归 log.info("key: {}, fieldName: {}", key, fieldName); highlightDifference(fieldValue, differences, highlightedNode, fieldName); } if (StrUtil.isNotEmpty(key)) { if (ObjUtil.isEmpty(objectNode)) { // 初始化 objectNode objectNode = new ObjectMapper().createObjectNode(); } // 差异化包含 fieldName 设置html元素 if (differences.containsKey(fieldName)) { objectNode.put(fieldName, "<span style='background-color: yellow;'>" + differences.get(fieldName) + "</font>"); } else { // 差异化不包含正常添加数据 objectNode.set(fieldName, fieldValue); } } else { if (differences.containsKey(fieldName)) { highlightedNode.put(fieldName, "<span style='background-color: yellow;'>" + differences.get(fieldName) + "</font>"); } else { // 避免原生对象数据后期替换掉之前设置的 objectNode if (highlightedNode.get(fieldName) == null) { highlightedNode.set(fieldName, fieldValue); } } } } if (ObjUtil.isNotEmpty(objectNode) && StrUtil.isNotEmpty(key)) { highlightedNode.set(key, objectNode); } } catch (Exception e) { e.printStackTrace(); } } @Data public static class DiffResult { private String before; private String after; public DiffResult(String before, String after) { this.before = before; this.after = after; } } }
标签:JsonNode,String,differences,差异化,多层,JSON,fieldName,node1,append From: https://www.cnblogs.com/xxsdnol/p/18102758