铜仁市网站建设_网站建设公司_jQuery_seo优化
2025/12/29 7:53:07 网站建设 项目流程

在工作中遇到需要对前后两组数据进行比对,并返回比对结果,最终决定使用json进行比对,下面是几种方案。

核心工具对比

1. JSONassert(测试场景首选)

JSONassert 是专为测试设计的 JSON 比对工具,支持 忽略字段顺序、数组顺序、数值精度 等宽松模式,差异会以异常形式抛出,包含具体路径和值的对比。

步骤 1:引入依赖(Maven)

<dependency><groupId>org.skyscreamer</groupId><artifactId>jsonassert</artifactId><version>1.5.1</version><scope>test</scope><!--测试场景建议test scope--></dependency>

步骤 2:实操示例(比对差异并输出)

importorg.skyscreamer.jsonassert.JSONAssert;importorg.skyscreamer.jsonassert.JSONCompareMode;publicclassJsonAssertDemo{publicstaticvoidmain(String[]args){// 待比对的两个JSON字符串(结构相同,值有差异)StringexpectedJson="{\"name\":\"张三\",\"age\":20,\"address\":{\"city\":\"北京\"},\"hobbies\":[\"篮球\",\"游泳\"]}";StringactualJson="{\"name\":\"李四\",\"age\":20,\"address\":{\"city\":\"上海\"},\"hobbies\":[\"篮球\",\"跑步\"]}";try{// 严格模式(字段顺序、数组顺序、值完全一致才通过)JSONAssert.assertEquals(expectedJson,actualJson,JSONCompareMode.STRICT);}catch(AssertionErrore){// 捕获差异并输出System.out.println("JSON差异:\n"+e.getMessage());}}}

输出结果(精准定位差异)

JSON差异:Expected:"张三"got:"李四"at path $["name"]Expected:"北京"got:"上海"at path $["address"]["city"]Expected:"游泳"got:"跑步"at path $["hobbies"][1]

关键配置(JSONCompareMode)

  • STRICT:严格模式(字段顺序、数组顺序、值必须完全一致)
  • LENIENT:宽松模式(忽略字段顺序,数组顺序仍校验)
  • NON_EXTENSIBLE:不允许实际 JSON 包含预期外的字段
  • IGNORE_ARRAY_ORDER:忽略数组元素顺序
  • IGNORE_VALUES:只校验结构,忽略值的差异

2. JsonUnit(更友好的测试 API)

JsonUnit 基于 JSONassert 和 Jackson 封装,API 更简洁,差异输出更易读,支持 assertThat 风格的断言(符合 BDD 测试习惯)。

步骤 1:引入依赖

<dependency><groupId>net.javacrumbs.json-unit</groupId><artifactId>json-unit-core</artifactId><version>2.38.0</version><scope>test</scope></dependency><!--依赖JacksonJsonUnit底层用Jackson解析)--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency>

步骤 2:实操示例

importstaticnet.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;publicclassJsonUnitDemo{publicstaticvoidmain(String[]args){StringexpectedJson="{\"name\":\"张三\",\"age\":20,\"address\":{\"city\":\"北京\"}}";StringactualJson="{\"name\":\"李四\",\"age\":21,\"address\":{\"city\":\"北京\"}}";// 比对并输出差异(AssertJ风格)assertThatJson(actualJson).isEqualTo(expectedJson).onFailure(failure->System.out.println("JSON差异:\n"+failure.getMessage()));}}

输出结果

JSON差异:Expectedvalue<"张三">but was<"李四">at path $['name']Expectedvalue<20>but was<21>at path $['age']

高级用法(忽略指定字段)

// 忽略age字段的差异assertThatJson(actualJson).whenIgnoringPaths("age").isEqualTo(expectedJson);

3. Jackson(业务开发灵活定制)

Jackson 是 Java 最主流的 JSON 处理库,通过 JsonNode 树模型可完全自定义比对逻辑(适合业务开发中需要精细控制差异的场景)。

步骤 1:引入依赖

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency>

步骤 2:自定义比对工具类(输出差异路径和值)

importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;importjava.util.ArrayList;importjava.util.List;publicclassJacksonJsonDiff{privatestaticfinalObjectMapperOBJECT_MAPPER=newObjectMapper();privatestaticfinalList<String>DIFFS=newArrayList<>();// 比对两个JSON字符串,返回差异列表publicstaticList<String>compareJson(StringexpectedJson,StringactualJson)throwsException{DIFFS.clear();JsonNodeexpectedNode=OBJECT_MAPPER.readTree(expectedJson);JsonNodeactualNode=OBJECT_MAPPER.readTree(actualJson);compareNodes("",expectedNode,actualNode);returnDIFFS;}// 递归比对JsonNode节点privatestaticvoidcompareNodes(Stringpath,JsonNodeexpected,JsonNodeactual){// 节点类型不同if(expected.getNodeType()!=actual.getNodeType()){DIFFS.add(path+":类型不一致(预期:"+expected.getNodeType()+",实际:"+actual.getNodeType()+")");return;}// 叶子节点(值节点)if(expected.isValueNode()){if(!expected.equals(actual)){DIFFS.add(path+":值不一致(预期:"+expected.asText()+",实际:"+actual.asText()+")");}return;}// 对象节点(递归比对子字段)if(expected.isObject()){expected.fieldNames().forEachRemaining(fieldName->{StringnewPath=path.isEmpty()?"$."+fieldName:path+"."+fieldName;JsonNodeexpectedChild=expected.get(fieldName);JsonNodeactualChild=actual.get(fieldName);if(actualChild==null){DIFFS.add(newPath+":实际JSON缺失该字段");}else{compareNodes(newPath,expectedChild,actualChild);}});// 检查实际JSON是否有预期外的字段actual.fieldNames().forEachRemaining(fieldName->{if(!expected.has(fieldName)){StringnewPath=path.isEmpty()?"$."+fieldName:path+"."+fieldName;DIFFS.add(newPath+":实际JSON包含预期外的字段");}});}// 数组节点(递归比对数组元素)if(expected.isArray()){intexpectedSize=expected.size();intactualSize=actual.size();if(expectedSize!=actualSize){DIFFS.add(path+":数组长度不一致(预期:"+expectedSize+",实际:"+actualSize+")");}// 比对数组元素(按索引)intmaxSize=Math.max(expectedSize,actualSize);for(inti=0;i<maxSize;i++){StringnewPath=path+"["+i+"]";JsonNodeexpectedChild=i<expectedSize?expected.get(i):null;JsonNodeactualChild=i<actualSize?actual.get(i):null;if(expectedChild==null){DIFFS.add(newPath+":实际数组多出元素");}elseif(actualChild==null){DIFFS.add(newPath+":实际数组缺失元素");}else{compareNodes(newPath,expectedChild,actualChild);}}}}// 测试publicstaticvoidmain(String[]args)throwsException{StringexpectedJson="{\"name\":\"张三\",\"age\":20,\"address\":{\"city\":\"北京\"},\"hobbies\":[\"篮球\",\"游泳\"]}";StringactualJson="{\"name\":\"李四\",\"age\":20,\"address\":{\"city\":\"上海\"},\"hobbies\":[\"篮球\",\"跑步\"]}";List<String>diffs=compareJson(expectedJson,actualJson);System.out.println("JSON差异列表:");diffs.forEach(diff->System.out.println("- "+diff));}}

输出结果

JSON差异列表:-$.name:值不一致(预期:张三,实际:李四)-$.address.city:值不一致(预期:北京,实际:上海)-$.hobbies[1]:值不一致(预期:游泳,实际:跑步)

4. Diffuse(轻量级结构化差异输出)

Diffuse 是轻量级工具,可输出 JSON 格式的结构化差异报告(包含添加 / 修改 / 删除的节点),适合需要将差异持久化或传输的场景。

步骤 1:引入依赖

<dependency><groupId>me.snov</groupId><artifactId>diffuse</artifactId><version>0.2.0</version></dependency>

步骤 2:实操示例

importme.snov.diffuse.Diffuse;importme.snov.diffuse.JsonDiff;publicclassDiffuseDemo{publicstaticvoidmain(String[]args){StringexpectedJson="{\"name\":\"张三\",\"age\":20}";StringactualJson="{\"name\":\"李四\",\"age\":21,\"gender\":\"男\"}";// 生成结构化差异报告JsonDiffdiff=Diffuse.diff(expectedJson,actualJson);System.out.println("结构化差异报告:\n"+diff.toJson());}}

输出结果(JSON 格式)

{"changed":[{"path":"/name","from":"张三","to":"李四"},{"path":"/age","from":20,"to":21}],"added":[{"path":"/gender","value":"男"}],"removed":[]}

选型建议

  1. 测试场景:优先选 JsonUnit(API 友好)或 JSONassert(轻量);
  2. 业务开发:优先选 Jackson(灵活自定义比对规则);
  3. 需要结构化差异输出:选 Diffuse;
  4. 特殊需求(如忽略数值精度、时间格式):基于 Jackson 扩展自定义比对逻辑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询