香港特别行政区网站建设_网站建设公司_RESTful_seo优化
2026/1/17 12:31:15 网站建设 项目流程

前言

在日常开发中,我们经常需要处理 JSON 数据,特别是从复杂的 JSON 结构中提取特定字段。传统的处理方式如 Gson、Jackson 的 API 虽然功能强大,但在处理复杂路径提取时代码往往显得冗长且不易维护。

今天给大家介绍一个更优雅的解决方案 ——JSONPath,它就像 JSON 界的 XPath,让我们可以用简洁的路径表达式来定位和提取 JSON 数据。

什么是 JSONPath?

JSONPath 是一种用于从 JSON 文档中提取特定数据的查询语言。它的语法简洁直观,类似于 JavaScript 对象属性的访问方式。

常用 JSONPath 语法

表达式

说明

$

根节点

@

当前节点

.

[]

子节点操作符

..

递归下降(任意深度)

*

通配符,匹配所有成员/元素

[]

下标运算符

[start:end]

数组切片

[?()]

过滤表达式

Spring Boot 集成 JSONPath

1. 添加依赖

pom.xml中添加 JSONPath 依赖:

<dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>2.9.0</version> </dependency>

2. 基础使用示例

首先准备一个 JSON 示例:

{ "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 } ], "bicycle": { "color": "red", "price": 19.95 } } }
读取数据
import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.PathNotFoundException; public class JsonPathExample { private String json = "..."; // 上述 JSON 字符串 @Test public void testReadJson() { // 获取所有书籍的作者 List<String> authors = JsonPath.parse(json) .read("$.store.book[*].author"); // 获取第一本书的价格 Double price = JsonPath.parse(json) .read("$.store.book[0].price"); // 获取所有价格低于10元的书籍 List<Map> cheapBooks = JsonPath.parse(json) .read("$.store.book[?(@.price < 10)]"); // 获取最后一本书 Map lastBook = JsonPath.parse(json) .read("$.store.book[-1]"); } }
在 Spring Boot 中的实际应用
import org.springframework.web.bind.annotation.*; import com.jayway.jsonpath.JsonPath; @RestController @RequestMapping("/api") public class BookController { @PostMapping("/extract") public ResponseEntity<?> extractData(@RequestBody String jsonString) { try { // 提取所有书籍标题 List<String> titles = JsonPath.parse(jsonString) .read("$.store.book[*].title"); // 提取价格区间内的书籍 List<Map> books = JsonPath.parse(jsonString) .read("$.store.book[?(@.price >= 8 && @.price <= 12)]"); return ResponseEntity.ok(Map.of( "titles", titles, "filteredBooks", books )); } catch (PathNotFoundException e) { return ResponseEntity.badRequest() .body("JSON路径不存在: " + e.getMessage()); } } @GetMapping("/authors") public ResponseEntity<?> getAuthors(@RequestParam String jsonData) { List<String> authors = JsonPath.parse(jsonData) .read("$.store.book[*].author"); return ResponseEntity.ok(authors); } }

3. 高级用法

自定义配置
import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.Option; @Configuration public class JsonPathConfig { public Configuration jsonPathConfiguration() { return Configuration.builder() // 抑制异常,返回 null .options(Option.SUPPRESS_EXCEPTIONS) // 默认值为空集合 .options(Option.DEFAULT_PATH_LEAF_TO_NULL) // 总是返回列表 .options(Option.ALWAYS_RETURN_LIST) // 缓存 .options(Option.CACHE) .build(); } }
缓存解析结果
@Service public class JsonPathCacheService { private final Map<String, Object> cache = new ConcurrentHashMap<>(); public Object readWithCache(String json, String path) { return JsonPath.using(Configuration.defaultConfiguration()) .parse(json) .read(path); } // 预编译路径,提升性能 private final JsonPath compiledPath = JsonPath.compile("$.store.book[*]"); public List<Map> readOptimized(String json) { return compiledPath.read(json); } }
与 REST 调用结合
@Service public class ExternalApiService { private final RestTemplate restTemplate; public List<String> extractFromExternalApi(String url, String jsonPath) { String response = restTemplate.getForObject(url, String.class); return JsonPath.parse(response).read(jsonPath); } }
过滤表达式详解
// 价格大于10的书籍 $.store.book[?(@.price > 10)] // category 为 fiction 的书籍 $.store.book[?(@.category == 'fiction')] // 包含 isbn 字段的书籍 $.store.book[?(@.isbn)] // 正则匹配 $.store.book[?(@.author =~ /.*Melville.*/)] // 多条件组合 $.store.book[?(@.price < 10 && @.category == 'fiction')]

除了 Jayway JsonPath,常见的 JSON 处理库也有各自的 JSONPath 或类似功能实现。

FastJSON - 内置 JSONPath

FastJSON 内置了 JSONPath 支持,使用起来非常简洁。

添加依赖

<dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.53</version> </dependency>

使用示例

import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONPath; import com.alibaba.fastjson2.JSONObject; public class FastJsonPathExample { private String json = "..."; // 同上 JSON 示例 @Test public void testFastJsonPath() { JSONObject object = JSON.parseObject(json); // 获取所有书籍作者 List<String> authors = (List<String>) JSONPath.eval(object, "$.store.book[*].author"); // 获取第一本书价格 Double price = (Double) JSONPath.eval(object, "$.store.book[0].price"); // 过滤价格小于10的书籍 List books = (List) JSONPath.eval(object, "$.store.book[?(@.price < 10)]"); // size 方法 Integer size = (Integer) JSONPath.eval(object, "$.store.book.size()"); // 获取所有包含 isbn 的书籍 List booksWithIsbn = (List) JSONPath.eval(object, "$.store.book[?(@.isbn)]"); } }

FastJSON JSONPath 多种查询方式

FastJSON 提供了多种查询方式,适应不同场景:

import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONPath; import com.alibaba.fastjson2.JSONObject; public class FastJsonPathQueryExample { private JSONObject object = JSON.parseObject(json); @Test public void testDifferentQueryMethods() { // ========== 方式一:JSONPath.eval(静态方法,最常用)========== List authors1 = (List) JSONPath.eval(object, "$.store.book[*].author"); // ========== 方式二:JSONPath.of + extract(推荐,性能更好)========== // 预编译路径表达式,性能更优(适合重复使用) JSONPath path = JSONPath.of("$.store.book[*].author"); List authors2 = (List) path.extract(object); // ========== 方式三:compile + eval(另一种编译方式)========== JSONPath compiledPath = JSONPath.compile("$.store.book[*].author"); List authors3 = (List) compiledPath.eval(object); // ========== 方式四:路径对象直接调用 set(修改操作)========== JSONPath pricePath = JSONPath.of("$.store.book[0].price"); pricePath.set(object, 88.88); // ========== 方式五:contains(判断是否包含路径)========== boolean hasBook = JSONPath.contains(object, "$.store.book"); boolean hasIsbn = JSONPath.contains(object, "$.store.book[2].isbn"); // ========== 方式六:size(获取数组大小)========== Integer arraySize = (Integer) JSONPath.eval(object, "$.store.book.size()"); // 或者使用编译后的路径 JSONPath sizePath = JSONPath.of("$.store.book.size()"); Integer size = (Integer) sizePath.eval(object); } }

FastJSON JSONPath 修改操作

FastJSON 的 JSONPath 不仅可以读取数据,还支持修改数据,这是它的一个强大特性。

import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONPath; import com.alibaba.fastjson2.JSONObject; public class FastJsonPathModifyExample { @Test public void testJsonPathSet() { JSONObject object = JSON.parseObject(json); // 修改第一本书的价格 JSONPath.set(object, "$.store.book[0].price", 99.99); // 修改自行车的颜色 JSONPath.set(object, "$.store.bicycle.color", "blue"); // 批量修改所有书籍价格 JSONPath.set(object, "$.store.book[*].price", 15.88); // 修改包含 isbn 的书籍的 category JSONPath.set(object, "$.store.book[?(@.isbn)].category", "classic"); // 添加新字段 JSONPath.set(object, "$.store.book[0].publisher", "Tech Press"); // 数组末尾添加元素(通过路径获取数组后操作) JSONArray bookArray = (JSONArray) JSONPath.eval(object, "$.store.book"); bookArray.add(JSON.parseObject("{\"title\":\"New Book\",\"price\":9.99}")); // 删除字段 JSONPath.remove(object, "$.store.bicycle"); System.out.println(JSON.toJSONString(object)); } }

FastJSON JSONPath 其他操作

// 获取集合大小 Integer size = (Integer) JSONPath.eval(object, "$.store.book.size()"); // 获取集合第一个 Object first = JSONPath.eval(object, "$.store.book.first()"); // 获取集合最后一个 Object last = JSONPath.eval(object, "$.store.book.last()"); // 获取属性所有值 Collection values = (Collection) JSONPath.eval(object, "$.store.book.values()");

Jackson - JsonPointer / Jackson JsonPath

Jackson 原生支持JsonPointer(RFC 6901),但不是完整的 JSONPath 实现。若要使用 JSONPath 功能,可以通过以下两种方式:

方式一:使用 JsonPointer(原生支持)

<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.2</version> </dependency>
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.JsonPointer; public class JacksonJsonPointerExample { private String json = "..."; private ObjectMapper mapper = new ObjectMapper(); @Test public void testJsonPointer() throws Exception { JsonNode root = mapper.readTree(json); // 使用 JsonPointer 定位节点 JsonPointer ptr = JsonPointer.compile("/store/book/0/author"); JsonNode authorNode = root.at(ptr); String author = authorNode.asText(); // 链式写法 String title = root.at("/store/book/1/title").asText(); Double price = root.at("/store/bicycle/price").asDouble(); } }

JsonPointer 限制

  • • 语法较简单,不支持通配符、过滤表达式

  • • 无法一次获取多个值

  • • 不支持数组切片

方式二:使用 Jackson-JsonPath(第三方扩展)

<dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>2.9.0</version> </dependency>
import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider; import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; public class JacksonJsonPathExample { // 配置使用 Jackson private Configuration configuration = Configuration.builder() .jsonProvider(new JacksonJsonNodeJsonProvider()) .mappingProvider(new JacksonMappingProvider()) .build(); @Test public void testJacksonJsonPath() { List<String> authors = JsonPath.using(configuration) .parse(json) .read("$.store.book[*].author"); } }

Gson - 无原生 JSONPath

Gson 本身不提供 JSONPath 支持,这是 Gson 的一个局限。建议搭配 Jayway JsonPath 使用。

<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>2.9.0</version> </dependency>
import com.google.gson.Gson; import com.google.gson.JsonElement; import com.jayway.jsonpath.JsonPath; public class GsonJsonPathExample { private Gson gson = new Gson(); private String json = "..."; @Test public void testGsonWithJsonPath() { // 使用 JsonPath 提取数据 List<String> authors = JsonPath.parse(json) .read("$.store.book[*].author"); // 将结果转回 Gson 对象 JsonElement element = gson.toJsonTree(authors); } }

三种方案对比

特性

FastJSON

Jackson + JsonPointer

Jayway JsonPath

JSONPath 支持

原生支持

仅 JsonPointer

完整支持

过滤表达式

支持

不支持

支持

通配符

支持

不支持

支持

性能

优秀

优秀

良好

生态稳定性

曾有安全漏洞

最稳定

社区活跃

Spring Boot 集成

需手动配置

默认集成

需添加依赖

选型建议

已有 FastJSON 项目:直接使用 FastJSON 的 JSONPath
使用 Jackson 的项目:简单场景用 JsonPointer,复杂场景引入 Jayway JsonPath
使用 Gson 的项目:建议搭配 Jayway JsonPath 使用
新项目:推荐 Jackson + Jayway JsonPath 组合

总结

JSONPath 是处理 JSON 数据的利器,通过简洁的路径表达式实现复杂字段提取、条件过滤和动态查询。在 Spring Boot 中集成 JSONPath 可大幅简化代码、提升可读性,是处理复杂 JSON 结构和第三方 API 数据的一种可选技术方案。

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

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

立即咨询