FastJson中的JsonPath还挺好用的
我们的SRM系统和ERP系统需要对接很多供应商,以前的业务都是走线下做,那种效率极低。后来就都转为线上,直接调用供应商接口,但是这样做又会有一个问题,就是那么多供应商,每家供应商的接口和字段都不一样,报文结构也会不一样。难不成,我们程序里面要真多每家供应商都写一套逻辑吗?这要是做到业务系统的话,那工作量也确实不小。
后来,我们想了办法,就是加了一个转发应用,不管是内部业务系统调供应商接口,还是供应商调我们内部业务系统,都走这个转发应用,在转发应用中来做每个供应商的接口对接和报文转换,业务系统只需要传接口编号即可,不需要再改业务系统中的代码。
通过分析,每家供应商是鉴权方式是不一样的,但是请求方式基本都是POST,然后报文是JSON放在BODY中。那么这样一来,就是针对每家供应商实现一套登录鉴权,报文基本可以表达式动态转换。这时候,我想到了Jayway JsonPath
,
本来想从
Jayway JsonPath
的源代码中借鉴一下思路,但是看了下代码,算了,还是直接用吧 .
后来又一想,其实FastJson
在1.2版本开始也有JsonPath
,从需求来看,它也能够满足,那就直接用 FastJson JsonPath
吧。
先来看看基本的语法和功能
1. 支持语法
JSONPATH | 描述 |
---|---|
$ | 根对象,例如$.name |
[num] | 数组访问,其中num是数字,可以是负数。例如$[0].leader.departments[-1].name |
[num0,num1,num2…] | 数组多个元素访问,其中num是数字,可以是负数,返回数组中的多个元素。例如$[0,3,-2,5] |
[start:end] | 数组范围访问,其中start和end是开始小表和结束下标,可以是负数,返回数组中的多个元素。例如$[0:5] |
[start:end :step] | 数组范围访问,其中start和end是开始小表和结束下标,可以是负数;step是步长,返回数组中的多个元素。例如$[0:5:2] |
[?(@.key)] | 对象属性非空过滤,例如$.departs[?(@.name)] |
[?(@.key > 123)] | 数值类型对象属性比较过滤,例如$.departs[id >= 123],比较操作符支持=,!=,>,>=,<,<= |
[?(@.key = ‘123’)] | 字符串类型对象属性比较过滤,例如$.departs[?(@..name = ‘123’)],比较操作符支持=,!=,>,>=,<,<= |
[?(@.key like ‘aa%’)] | 字符串类型like过滤, 例如$.departs[?(@..name like ‘sz*’)],通配符只支持%支持not like |
[?(@.key rlike ‘regexpr’)] | 字符串类型正则匹配过滤, |
[?(@.key in (‘v0’, ‘v1’))] | IN过滤, 支持字符串和数值类型 例如: $.departs[?(@.name in (‘wenshao’,’Yako’))] $.departs[id not in (101,102)] |
[?(@.key between 234 and 456)] | BETWEEN过滤, 支持数值类型,支持not between 例如: $.departs[?(@.id between 101 and 201)] $.departs[?(@.id not between 101 and 201)] |
length() 或者 size() | 数组长度。例如$.values.size() 支持类型java.util.Map和java.util.Collection和数组 |
. | 属性访问,例如$.name |
.. | deepScan属性访问,例如$..name |
* | 对象的所有属性,例如$.leader.* |
[‘key’] | 属性访问。例如$[‘name’] |
[‘key0’,’key1’] | 多个属性访问。例如$[‘id’,’name’] |
以下两种写法的语义是相同的:
1 | $.store.book[0].title |
和
1 | $['store']['book'][0]['title'] |
1.1 函数
Function | 返回类型 | Description |
---|---|---|
type | string | 返回对象的类型 |
length/size | integer | 返回集合或者字符串的长度 |
first | Any | 集合中第一个元素 |
last | Any | 集合中最后一个元素 |
values | sequence | Map类型的Values |
entries | sequence | Map类型的EntrySet |
trim | string | 对字符串做trim后返回 |
double | double | 将目标类型转换为double类型 |
ceil | number | 对数值类型做ceil处理返回 |
abs | number | 返回对数值类型的绝对值 |
lower | string | 将字符串转换小写 |
upper | string | 将字符串转换成大写 |
index(x) | int | 其中参数x支持数值和字符串 |
1.2 聚合函数
Function | 返回类型 | Description |
---|---|---|
min | ||
max | ||
first | 返回集合中的第一个元素 | |
last | 返回集合中的最后一个个元素 | |
avg | double |
1.3 Filter Operators
Operator | Description |
---|---|
= | 相等 |
!= or <> | 不等 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
~= | |
like | 类似SQL中LIKE语法 |
not like | |
rlike | |
not rlike | |
in | |
not in | |
between | |
not between | |
starts_with | |
not starts_with | |
ends_with | |
not ends_with | |
contains | |
not contains |
2. 语法举例
JSONPath | 语义 |
---|---|
$ | 根对象 |
$[-1] | 最后元素 |
$[:-2] | 第1个至倒数第2个 |
$[1:] | 第2个之后所有元素 |
$[1,2,3] | 集合中1,2,3个元素 |
接下来就直接干吧。看看我们这个简陋的字段映射界面
在界面上,我们可以设置要转换的字段值类型,日期格式还有简单的字典值转换以及简单的表达式(多个字段合并或者是字段值判断),我们需要取出字段的映射关系,
1 | @Data |
1 | private void setValue(BsFiledsVo bsFiledsVo, JSONObject result, Object eval, List<SupDictVo> supFiledDictVos) { |
这里我原始字段取值表达式$.RECEIVE_INFO_LIST[0].TALK_DESC
,目标表达式$.statementDetails[0].commodityDetails[0].businessNegotiateReason
原始实例报文
1 | { |
转换后的报文
1 | { |
目前基本的字段映射,格式转换能满足了,遇到特殊情况,咱们在特殊处理吧。我们还给这个应用取了名字,叫 供应商直连网关
FastJson中的JsonPath还挺好用的