基本思路:遇到节点是JSONObject和JSONArray,就递归
1、工具类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* @title 断言两个json串(判断一个json串是否包含另一个)
* @@date 2022/2/23 5:22 下午
*/
public class JsonCompareUtil {
private static final Logger log = LoggerFactory.getLogger(JsonCompareUtil.class);
/**
* 判断实际结果和预期结果是否一致,在预期结果中可以去除不需要验证的key
*
* @param actualJson
* @param exceptedJson
* @return
*/
public static String diffJsonObject(String actualJson, String exceptedJson) {
JSONObject actualJsonObj = JSONObject.parseObject(actualJson);
JSONObject exceptedJsonObj = JSONObject.parseObject(exceptedJson);
List<Map<String, Object>> compareResult = getCompareResult(actualJsonObj, exceptedJsonObj, null);
StringBuffer sb = new StringBuffer();
sb.append("共有").append(compareResult.size()).append("处不匹配: ").append(Arrays.toString(compareResult.toArray()));
return sb.toString();
}
private static List<Map<String, Object>> getCompareResult(JSONObject actualJson, JSONObject exceptedJson, String listKey) {
List<Map<String, Object>> mapDiffs = new ArrayList<>();
for (Map.Entry<String, Object> actualEntry : actualJson.entrySet()) {
for (Map.Entry<String, Object> exceptedEntry : exceptedJson.entrySet()) {
if (actualEntry.getKey().equals(exceptedEntry.getKey())) {
Object actualEntryValue = actualEntry.getValue();
Object exceptedEntryValue = exceptedEntry.getValue();
String finalKey = StringUtils.isNotEmpty(listKey) ? listKey + "." + actualEntry.getKey() : actualEntry.getKey();
if(actualEntryValue instanceof JSONObject && exceptedEntryValue instanceof JSONObject) {
mapDiffs.addAll(cmpJsonObject((JSONObject)actualEntryValue, (JSONObject)exceptedEntryValue, finalKey));
} else if(actualEntryValue instanceof JSONArray && exceptedEntryValue instanceof JSONArray) {
mapDiffs.addAll(cmpJsonArray((JSONArray)actualEntryValue, (JSONArray)exceptedEntryValue, finalKey));
} else {
if (!actualEntryValue.equals(exceptedEntryValue)) {
Map<String, Object> diffMap = new LinkedHashMap<>();
String prefix = "";
if(StringUtils.isNotEmpty(listKey)) {
prefix = listKey + ".";
}
diffMap.put("key", prefix + actualEntry.getKey());
diffMap.put("实际值", actualEntryValue);
diffMap.put("预期值", exceptedEntryValue);
mapDiffs.add(diffMap);
}
}
}
}
}
return mapDiffs;
}
public static List<Map<String, Object>> cmpJsonObject(JSONObject actualJsonObj, JSONObject exceptedJsonObj, String listKey) {
List<Map<String, Object>> compareResult = getCompareResult(actualJsonObj, exceptedJsonObj, listKey);
return compareResult;
}
/**
* @param actualJsonArray
* @param exceptedJsonArray
* @return
*/
public static List<Map<String, Object>> cmpJsonArray(JSONArray actualJsonArray, JSONArray exceptedJsonArray, String listKey) {
List<Map<String, Object>> mapDiffs = new ArrayList<>();
if (actualJsonArray.size() == exceptedJsonArray.size()) {
for (int i = 0; i < actualJsonArray.size(); i++) {
String actualJsonArrayString = actualJsonArray.getString(i);
String exceptedJsonArrayString = exceptedJsonArray.getString(i);
if (verifyJsonObject(actualJsonArrayString) && verifyJsonObject(exceptedJsonArrayString)) {
mapDiffs.addAll(cmpJsonObject(actualJsonArray.getJSONObject(i), exceptedJsonArray.getJSONObject(i), listKey + "[" + i + "]"));
} else if(verifyJsonArray(actualJsonArrayString) && verifyJsonArray(exceptedJsonArrayString)) {
mapDiffs.addAll(cmpJsonArray(actualJsonArray.getJSONArray(i), exceptedJsonArray.getJSONArray(i), listKey + "[" + i + "]"));
} else {
if (!actualJsonArrayString.equals(exceptedJsonArrayString)) {
Map<String, Object> diffMap = new LinkedHashMap<>();
diffMap.put("key", listKey + "[" + i + "]");
diffMap.put("实际值", actualJsonArrayString);
diffMap.put("预期值", exceptedJsonArrayString);
mapDiffs.add(diffMap);
}
}
}
}
return mapDiffs;
}
public static Boolean isEquals(String actual, String excepted) {
JSONObject actualJson = JSONObject.parseObject(actual);
JSONObject exceptedJson = JSONObject.parseObject(excepted);
List<Map<String, Object>> compareResult = getCompareResult(actualJson, exceptedJson, null);
if(compareResult.size() > 0) {
return false;
}
return true;
}
/**
* 校验是否是json串
*
* @param jsonString
* @return Boolean
*/
private static Boolean verifyJson(String jsonString) {
try {
JSON.parse(jsonString);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 校验是否是JSONObject类型的json
*
* @param jsonString
* @return Boolean
*/
public static Boolean verifyJsonObject(String jsonString) {
if (!verifyJson(jsonString)) {
return false;
}
try {
JSONObject.parseObject(jsonString);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 校验是否是JSONArray类型的json
*
* @param jsonString
* @return Boolean
*/
public static Boolean verifyJsonArray(String jsonString) {
if (!verifyJson(jsonString)) {
return false;
}
try {
JSONArray.parseArray(jsonString);
return true;
} catch (Exception e) {
return false;
}
}
}
2、测试方法
@Test
public void testJsonCompare() {
String srcJson = "{\n" +
" \"channelDtoList\":[\n" +
" {\n" +
" \"amount\":110,\n" +
" \"accountingFlag\":\"ACCOUNTING\",\n" +
" \"orderNo\":\"orderNo354463\",\n" +
" \"feeFlag\":\"FEE\",\n" +
" \"bankSuccessDate\":\"2019-09-02 00:00:00.000\",\n" +
" \"interfaceCode\":\"BJ_PSBC_KUAIPAY_J_Z001\",\n" +
" \"marketType\":\"PAY\",\n" +
" \"heelo2\":{\n" +
" \"kk\":{\n" +
" \"kkk\":\"vv\"\n" +
" }\n" +
" },\n" +
" \"heelo3\":{\n" +
" \"kk3\":{\n" +
" \"kkk3\":[\n" +
" 666,\n" +
" 777\n" +
" ]\n" +
" }\n" +
" },\n" +
" \"ll\":[\n" +
" 1,\n" +
" 2,\n" +
" 3\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"chunList\":[\n" +
" [\n" +
" 1,\n" +
" 2,\n" +
" 3\n" +
" ],\n" +
" [\n" +
" 4,\n" +
" 5\n" +
" ]\n" +
" ],\n" +
" \"basicsProductThird\":\"FeePro4\",\n" +
" \"feeMerchantNo\":\"\",\n" +
" \"clearExecutor\":\"\",\n" +
" \"bizCode\":\"OPR\",\n" +
" \"yeepayFlowNo\":\"TrxFlowNo616636\",\n" +
" \"customerFee\":\"\",\n" +
" \"prepaidFlag\":\"Y\",\n" +
" \"basicsProductSecond\":\"FeePro3\",\n" +
" \"marketingProduct\":\"FeePro11\",\n" +
" \"merchantOrderNo\":\"merchantOrderNo258238\",\n" +
" \"computeFeeMerchantNo\":\"10040028946\",\n" +
" \"orderAmount\":100,\n" +
" \"marketFlag\":\"NO_MARKETING\",\n" +
" \"profitFlag\":\"NO_PROFIT\",\n" +
" \"trxTime\":\"2022-02-23 19:17:47\",\n" +
" \"parentMerchantNo\":\"10012052646\",\n" +
" \"basicsProductFirst\":\"FeePro2\",\n" +
" \"merchantNo\":\"10040028946\",\n" +
" \"hello\":{\n" +
" \"k\":1\n" +
" }\n" +
"}";
String expectJson = "{\n" +
" \"channelDtoList\":[\n" +
" {\n" +
" \"amount\":120,\n" +
" \"accountingFlag\":\"ACCOUNTING\",\n" +
" \"orderNo\":\"orderNo354463\",\n" +
" \"feeFlag\":\"FEE\",\n" +
" \"bankSuccessDate\":\"2019-09-02 00:00:00.000\",\n" +
" \"interfaceCode\":\"BJ_PSBC_KUAIPAY_J_Z001\",\n" +
" \"marketType\":\"PAY\",\n" +
" \"heelo2\":{\n" +
" \"kk\":{\n" +
" \"kkk\":\"vvv\"\n" +
" }\n" +
" },\n" +
" \"heelo3\":{\n" +
" \"kk3\":{\n" +
" \"kkk3\":[\n" +
" 666,\n" +
" 999\n" +
" ]\n" +
" }\n" +
" },\n" +
" \"ll\":[\n" +
" 1,\n" +
" 2,\n" +
" 3\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"chunList\":[\n" +
" [\n" +
" 1,\n" +
" 2,\n" +
" 3\n" +
" ],\n" +
" [\n" +
" 4,\n" +
" 5\n" +
" ]\n" +
" ],\n" +
" \"basicsProductThird\":\"FeePro4\",\n" +
" \"feeMerchantNo\":\"\",\n" +
" \"clearExecutor\":\"\",\n" +
" \"bizCode\":\"OPR\",\n" +
" \"yeepayFlowNo\":\"TrxFlowNo616636\",\n" +
" \"customerFee\":\"\",\n" +
" \"prepaidFlag\":\"Y\",\n" +
" \"basicsProductSecond\":\"FeePro3\",\n" +
" \"marketingProduct\":\"FeePro11\",\n" +
" \"merchantOrderNo\":\"merchantOrderNo258238\",\n" +
" \"computeFeeMerchantNo\":\"10040028946\",\n" +
" \"orderAmount\":200,\n" +
" \"marketFlag\":\"NO_MARKETING\",\n" +
" \"profitFlag\":\"NO_PROFIT\",\n" +
" \"trxTime\":\"2022-02-23 19:17:47\",\n" +
" \"parentMerchantNo\":\"10012052646\",\n" +
" \"basicsProductFirst\":\"FeePro2\",\n" +
" \"merchantNo\":\"10040028946\",\n" +
" \"hello\":{\n" +
" \"k\":2\n" +
" }\n" +
"}";
System.out.println(JsonCompareUtil.diffJsonObject(srcJson, expectJson));
System.out.println(JsonCompareUtil.isEquals(srcJson, expectJson));
}