作为每天和接口打交道的开发者,你是否也遇到过这种情况:面对嵌套了七八层的 JSON 响应,为了取一个price
字段,不得不写一堆getJSONObject()
和for
循环,代码冗长又容易出错?
直到我用上了jquickpath------ 这款被称为 "JSON 解析瑞士军刀" 的工具,才发现处理 JSON 原来可以这么优雅。今天就带大家全方位解锁这个效率神器!
先上关键信息:Maven 坐标
直接在pom.xml
引入依赖,5 分钟就能跑通第一个示例:
xml
xml
<dependency>
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-path</artifactId>
<version>最新版本请查看GitHub发布页</version>
</dependency>
最新版本获取:github.com/paohaijiao/...
8 个高频场景实战:一行代码解决问题
场景 1:提取深层嵌套字段(最常用)
需求 :从接口返回的 JSON 中,提取所有书籍的标题(嵌套在store->books
数组中)
json
json
{
"store": {
"books": [
{"title": "Java编程思想", "price": 108},
{"title": "深入理解Java虚拟机", "price": 99}
]
}
}
传统做法 :需要先获取store
对象,再获取books
数组,然后循环遍历每个元素取title
,至少 5 行代码。
jquickpath 实现:
java
运行
javascript
// 路径表达式:$.store.books.title
JSONPathResult result = JSONPathQueryBuilder.from(jsonData)
.path("$.store.books.title")
.execute();
// 结果:["Java编程思想", "深入理解Java虚拟机"]
场景 2:递归提取所有符合条件的字段
需求 :JSON 中有多个层级的price
字段(可能在books
和magazines
中),需要一次性提取所有价格。
json
json
{
"store": {
"books": [{"price": 108}, {"price": 99}],
"magazines": [{"price": 20}, {"price": 15}]
}
}
jquickpath 实现:
java
运行
javascript
// 递归下降语法:.. 匹配所有子节点
JSONPathResult result = JSONPathQueryBuilder.from(jsonData)
.path("$.store..price")
.execute();
// 结果:[108, 99, 20, 15]
场景 3:数组切片与范围选择
需求:获取数组中第 2 到第 4 个元素(支持正向 / 反向索引)
json
json
{
"list": ["A", "B", "C", "D", "E"]
}
jquickpath 实现:
java
运行
lua
// 切片语法:[start:end:step]
JSONPathResult result1 = JSONPathQueryBuilder.from(jsonData)
.path("$.list[1:4]") // 索引1到3(左闭右开)
.execute(); // 结果:["B", "C", "D"]
// 倒序取最后2个
JSONPathResult result2 = JSONPathQueryBuilder.from(jsonData)
.path("$.list[-2:]")
.execute(); // 结果:["D", "E"]
场景 4:多条件过滤数据
需求 :筛选出价格大于 50 且有isbn
编号的书籍
json
json
{
"books": [
{"title": "Book1", "price": 60, "isbn": "123"},
{"title": "Book2", "price": 40, "isbn": "456"},
{"title": "Book3", "price": 70}
]
}
jquickpath 实现:
java
运行
lua
// 过滤表达式:?() 中使用逻辑运算符
JSONPathResult result = JSONPathQueryBuilder.from(jsonData)
.path("$.books[?(@.price>50 && @.isbn)]")
.execute();
// 结果:[{"title":"Book1", "price":60, "isbn":"123"}]
场景 5:用表达式计算数组下标
需求:获取数组的最后一个元素(动态计算下标)
json
json
{
"items": ["first", "second", "third"]
}
jquickpath 实现:
java
运行
javascript
// 表达式下标:使用 @.length() 获取数组长度length 是JEvaluator中内置的方法,更多函数请移步Javelin 项目
JSONPathResult result = JSONPathQueryBuilder.from(jsonData)
.path("$.items[(@.length())-1]")
.execute();
// 结果:"third"
场景 6:通配符匹配所有字段
需求:获取对象中所有子字段的值(无需知道字段名)
json
json
{
"user": {
"name": "张三",
"age": 25,
"gender": "男"
}
}
jquickpath 实现:
java
运行
javascript
// 通配符 * 匹配所有属性
JSONPathResult result = JSONPathQueryBuilder.from(jsonData)
.path("$.user.*")
.execute();
// 结果:["张三", 25, "男"]
场景 7:字符串字面量下标访问
需求:访问包含特殊字符的字段名(如带空格的字段)
json
json
{
"data": {
"user name": "李四",
"user age": 30
}
}
jquickpath 实现:
java
运行
javascript
// 字符串字面量下标:用单引号包裹特殊字段名
JSONPathResult result = JSONPathQueryBuilder.from(jsonData)
.path("$.data['user name']")
.execute();
// 结果:"李四"
场景 8:取反逻辑筛选
需求 :筛选出没有isbn
编号的书籍
json
json
{
"books": [
{"title": "Book1", "isbn": "123"},
{"title": "Book2"},
{"title": "Book3"}
]
}
jquickpath 实现:
java
运行
lua
// 取反表达式:! 符号
JSONPathResult result = JSONPathQueryBuilder.from(jsonData)
.path("$.books[?(!@.isbn)]")
.execute();
// 结果:[{"title":"Book2"}, {"title":"Book3"}]
插件函数扩展指南
quickpath
支持通过插件函数扩展功能,基于 JEvaluator
组件实现函数的注册与调用。插件函数分为内置函数 (框架预定义)和自定义函数 (用户按需扩展),可用于数据处理、类型转换、逻辑计算等场景。用法可参考场景5中用表达式计算数组下标中的内置方法length
一、内置插件函数
JEvaluator
已内置多种常用函数,覆盖类型转换、数学运算、字符串处理、日期操作等场景,可直接调用。
1. 类型转换函数
toInteger
:转换为整数。入参为待转换的数字或字符串。示例:evaluateFunction("toInteger", Arrays.asList("123"))
返回123
。toDouble
:转换为双精度浮点数。入参为待转换的数字或字符串。示例:evaluateFunction("toDouble", Arrays.asList("3.14"))
返回3.14
。parseToDate
:将字符串解析为日期。入参为日期字符串和格式字符串。示例:evaluateFunction("parseToDate", Arrays.asList("2023-01-01", "yyyy-MM-dd"))
返回Date
对象。toFloat
:转换为单精度浮点数。入参为待转换的数字或字符串。示例:evaluateFunction("toFloat", Arrays.asList(1.5))
可完成相应转换。toString
:转换为字符串。入参为任意可转换为字符串的对象。示例:evaluateFunction("toString", Arrays.asList(1.5))
返回"1.5"
。
2. 数学函数
sum
:计算多个数字的和。入参为可变长度的数字列表。示例:evaluateFunction("sum", Arrays.asList(1, 2, 3))
返回6
。max
:求最大值。入参为可变长度的数字列表。示例:evaluateFunction("max", Arrays.asList(1, 5, 3))
返回5
。min
:求最小值。入参为可变长度的数字列表。示例:evaluateFunction("min", Arrays.asList(1, 5, 3))
返回1
。avg
:求平均值。入参为可变长度的数字列表。示例:evaluateFunction("avg", Arrays.asList(1, 2, 3, 4, 5))
返回3.0
。round
:四舍五入保留指定精度。入参为数字和保留小数位数。示例:evaluateFunction("round", Arrays.asList(3.1415, 2))
返回3.14
。ceil
:向上取整。入参为数字。示例:evaluateFunction("ceil", Arrays.asList(1.5))
返回2.0
。floor
:向下取整。入参为数字。示例:evaluateFunction("floor", Arrays.asList(1.5))
返回1.0
。
3. 字符串函数
toLower
:将字符串转为小写。入参为字符串。示例:evaluateFunction("toLower", Arrays.asList("HELLO"))
返回"hello"
。toUpper
:将字符串转为大写。入参为字符串。示例:evaluateFunction("toUpper", Arrays.asList("hello"))
返回"HELLO"
。join
:拼接列表元素。入参为列表和分隔符。示例:evaluateFunction("join", Arrays.asList(Arrays.asList("a", "b"), ","))
返回"a,b"
。split
:按分隔符拆分字符串。入参为字符串和分隔符。示例:evaluateFunction("split", Arrays.asList("123,12344", ","))
返回包含拆分后元素的列表。substring
:截取子字符串。入参为原字符串、起始索引和长度。示例:evaluateFunction("substring", Arrays.asList("substring", 1, 3))
返回"ub"
。replace
:替换字符串内容。入参为原字符串、目标子串和替换子串。示例:evaluateFunction("replace", Arrays.asList("abc", "a", "x"))
返回"xbc"
。contains
:判断字符串是否包含子串。入参为原字符串和子串。示例:evaluateFunction("contains", Arrays.asList("Hello World", "Hello"))
返回true
。startsWith
:判断字符串是否以指定前缀开头。入参为原字符串和前缀。示例:evaluateFunction("startsWith", Arrays.asList("Hello World", "Hel"))
返回true
。endsWith
:判断字符串是否以指定后缀结尾。入参为原字符串和后缀。示例:evaluateFunction("endsWith", Arrays.asList("Hello World", "World"))
返回true
。length
:获取字符串、列表或数组的长度。入参为字符串、列表或数组。示例:evaluateFunction("length", Arrays.asList("Hello World"))
返回11
。
4. 日期函数
dateFormat
:对日期进行格式化。入参为Date
对象和格式字符串。示例:evaluateFunction("dateFormat", Arrays.asList(new Date(), "yyyy-MM-dd"))
返回"2023-10-01"
。
5. 集合函数
trans
:根据上下文参数进行转换。入参为上下文参数和键。示例:JContext contextParams = new JContext(); contextParams.put("1","男"); evaluateFunction("trans", Arrays.asList(contextParams, "1"))
返回"男"
。
二、自定义插件函数
若内置函数无法满足需求,可通过 JEvaluator.registerFunction
方法注册自定义函数,支持 Function
(单参数)、BiFunction
(双参数)或多参数函数(通过 List<Object>
接收参数)。
1. 注册与调用流程
步骤 1:定义函数实现
根据参数数量选择函数接口:
- 单参数:使用
Function<Object, Object>
- 双参数:使用
BiFunction<Object, Object, Object>
- 多参数:使用
Function<List<Object>, Object>
(通过列表接收所有参数)
步骤 2:注册函数
通过 JEvaluator.registerFunction(String functionName, Object function)
注册函数,例如:
java
运行
javascript
// 注册双参数函数:计算两个日期相差的天数
JEvaluator.registerFunction("daysBetween", (BiFunction<Object, Object, Object>) (date1, date2) -> {
long diff = ((Date) date2).getTime() - ((Date) date1).getTime();
return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
});
// 注册多参数函数:计算多个数字的乘积
JEvaluator.registerFunction("multiply", (Function<List<Object>, Object>) args -> {
double result = 1;
for (Object arg : args) {
result *= ((Number) arg).doubleValue();
}
return result;
});
步骤 3:调用自定义函数
通过 JEvaluator.evaluateFunction(String functionName, List<Object> args)
调用,例如:
java
运行
ini
// 调用 daysBetween 函数
Date today = new Date();
Date nextWeek = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000);
Object dayDiff = JEvaluator.evaluateFunction("daysBetween", Arrays.asList(today, nextWeek));
System.out.println(dayDiff); // 输出:7
// 调用 multiply 函数
Object product = JEvaluator.evaluateFunction("multiply", Arrays.asList(2, 3, 4));
System.out.println(product); // 输出:24
为什么选择 jquickpath?
用过其他 JSON 解析工具的同学可能会问:市面上类似的库不少,jquickpath 有什么特别之处?
- 语法更全面 :支持递归下降(
..
)、表达式下标、多条件过滤等高级特性,覆盖 90%+ 实际场景 - API 更直观:链式调用设计,无论是用字符串路径还是 Java API 构建路径,都能保持代码简洁
- 兼容性更强:无缝对接 JSON 字符串、JSONObject、JSONArray 等常见格式
- 性能更优异:底层做了表达式预编译和缓存优化,大数据量解析也不卡顿
最后说句掏心窝的话
自从用了 jquickpath,我处理 JSON 的代码量至少减少了 60%,调试时间也大幅缩短。最爽的是,面对产品经理临时变更的字段提取需求,我再也不用改一堆代码,只需要调整一下路径表达式就行。
如果你也经常跟复杂 JSON 打交道,真心建议试试这个工具 ------ 毕竟,谁不想少写代码早下班呢?
👉 官网地址:github.com/paohaijiao/...(含完整语法文档和更多示例)
觉得有用的话,别忘了点赞收藏,下次处理 JSON 时就能立马用上啦~