Fastjson1 JSONPath 支持
对于 Java 开发者来说,处理 JSON 数据早已是常规操作。但当 JSON 结构变得复杂(比如多层嵌套或动态字段)时,传统的 getJSONObject() 或 getJSONArray() 方法会显得冗长且易出错。这时候,JSONPath 就像一张高效的索引地图,让你用类似 XPath 的表达式快速定位 JSON 中的任意节点。
Fastjson 1.x 版本直接内置了 JSONPath 支持,无需额外依赖。本文会用最简单的方式,带你快速上手。
什么是 JSONPath?
JSONPath 是一种用于从 JSON 文档中提取数据的表达式语言。
例如:
$.store.book[0].title→ 获取store下第一本书的标题。$..author→ 递归查找所有author字段。
在 Fastjson 中,调用方式非常统一:JSONPath.eval(jsonObject, path)。
基本使用步骤
引入 Fastjson
Maven 依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
准备 JSON 数据
String jsonStr = "{\n" +
" \"store\": {\n" +
" \"book\": [\n" +
" { \"title\": \"Java 编程思想\", \"price\": 88 },\n" +
" { \"title\": \"Effective Java\", \"price\": 98 },\n" +
" { \"title\": \"Spring 实战\", \"price\": 78, \"isbn\": \"978-1-234\" }\n" +
" ],\n" +
" \"bicycle\": { \"color\": \"red\", \"price\": 2000 }\n" +
" }\n" +
"}";
JSONObject root = JSON.parseObject(jsonStr);
常用表达式示例
根据索引访问数组元素
// 获取第一本书的标题
String title = (String) JSONPath.eval(root, "$.store.book[0].title");
System.out.println(title); // 输出: Java 编程思想
// 获取最后一本书(索引倒数)
Object lastBook = JSONPath.eval(root, "$.store.book[-1:]");
System.out.println(lastBook); // 输出最后一项
按条件过滤
// 查找价格大于 80 的所有书
List<Object> expensiveBooks = (List<Object>) JSONPath.eval(
root, "$.store.book[?(@.price > 80)]"
);
System.out.println(expensiveBooks.size()); // 2(Java编程思想 + Effective Java)
// 查找有 isbn 字段的书籍
List<Object> withIsbn = (List<Object>) JSONPath.eval(
root, "$.store.book[?(@.isbn)]"
);
System.out.println(withIsbn.get(0)); // 输出第三本书
通配符与深度遍历
// 获取 store 下所有 price(包括 book 和 bicycle)
List<Object> allPrices = (List<Object>) JSONPath.eval(root, "$.store..price");
System.out.println(allPrices); // [2000, 88, 98, 78]
// 递归查找所有字符串类型的 title
List<Object> allTitles = (List<Object>) JSONPath.eval(root, "$..title");
System.out.println(allTitles); // [Java编程思想, Effective Java, Spring实战]
进阶用法:动态路径组合
有时路径中的索引或属性名需要通过变量来确定:
int index = 1;
String property = "price";
// 动态索引
Object book2Price = JSONPath.eval(root, "$.store.book[" + index + "]." + property);
System.out.println(book2Price); // 98 (第二本书的价格)
// 或者用 eval 支持变量拼接(类型安全)
String path = String.format("$.store.book[%d].%s", index, property);
Object result = JSONPath.eval(root, path);
System.out.println(result); // 同上
完整案例:解析复杂响应
假设有一个 API 返回如下嵌套 JSON,我们需要提取所有用户的邮箱:
{
"code": 200,
"data": {
"users": [
{ "name": "Alice", "contacts": { "email": "[email protected]" } },
{ "name": "Bob", "contacts": { "email": "[email protected]" } }
]
}
}
代码实现:
String response = "..."; // 上述JSON字符串
JSONObject obj = JSON.parseObject(response);
// 深度遍历:任意路径下的 email
List<String> emails = (List<String>) JSONPath.eval(obj, "$..email");
System.out.println(emails); // [[email protected], [email protected]]
// 或精确路径
List<String> emails2 = (List<String>) JSONPath.eval(obj, "$.data.users[*].contacts.email");
System.out.println(emails2); // 同上
注意事项
- 类型转换:
eval()返回Object,需要手动转型。建议用泛型集合时加@SuppressWarnings。 - 路径语法:
$代表根节点.访问子节点[]数组索引或条件过滤器?()过滤表达式(支持>,<,==,!=)
- 性能:Fastjson 的 JSONPath 实现经过了优化,千万级数据处理依然高效。
总结
JSONPath 大幅降低了复杂 JSON 的解析难度,尤其适合以下场景:
- 接口响应字段不固定(如
data内动态增减属性) - 需要按条件提取数组子集(例如获取价格区间内的商品)
- 递归搜索任意深度的嵌套字段

