导语
推荐读者阅读较为官方的Aviator说明文档,本文是笔者使用过程中的笔记小结,知识可能比较零散和片面,敬请谅解
jsonpath 推荐官方文档:https://gitee.com/mirrors/JsonPath?_from=gitee_search
aviator 推荐官方文档:https://www.yuque.com/boyan-avfmj/aviatorscript/ra28g1#9cba8c99
简介
aviator 表达式引擎是一款较为轻量级且高性能的求值引擎
能做什么?
线上环境,部分java硬编码实现的业务逻辑,能够使用aviator进行配置化实现,无需修改java代码,无需重新发布版本
场景举例
搭配 jsonPath 进行取值,使用 aviator 进行求值或逻辑判断,能灵活的应用在指标、变量加工的场合
包依赖
到 maven 仓库中进行查找,仓库地址:https://mvnrepository.com/
- JsonPath
使用 jaway 的,就 jsonPath 的取值功能而言,比旧版本的 fast-json 功能丰富
<!-- https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.7.0</version>
</dependency>
- Aviator
新项目建议使用 5 版本,5 版本最大的改变是将 aviator 从表达式引擎升级为 AviatorScript 通用脚本语言
笔者的项目使用的是 4 版本,所以用 4 版本进行举例说明
<!-- https://mvnrepository.com/artifact/com.googlecode.aviator/aviator -->
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>4.2.10</version>
</dependency>
案例实现
准备json报文
{
"data": {
"books": [
{
"id": 1000, //书本编号
"name": "语文", // 书本名称
"amt": 30 // 书本金额
},
{
"id": 1001,
"name": "数学",
"amt": 35
},
{
"id": 1002,
"name": "英语",
"amt": 40
}
]
}
}
需求场景
1、输出 books 清单
2、一共有基本书?
3、购买语文和数学课本需要花费的总金额?
4、购买所有书本需要花费的总金额?
编程思想
使用 jsonPath 取出待求值计算的数据,放入 Map ,在执行 Aviator表达式 时,将 Map 以参数形式,传入表达式引擎
编程实现
package com.wei.aviator;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.jayway.jsonpath.JsonPath;
import java.io.*;
import java.util.HashMap;
/**
* @author: wei
* @date 2022/5/14 10:17
* 说明:
**/
public class Demo01 {
public static void main(String[] args) throws IOException {
Demo01 demo01 = new Demo01();
// 获取原始报文
String src = demo01.readFile("json/books.json");
HashMap<String, Object> params = new HashMap<>();
// 使用jsonPath 取值
Object books = JsonPath.read(src, "$.data.books");
params.put("books", books);
// 1、直接返回 books 清单
System.out.println("=======================1、直接返回 books 清单=================================");
Expression expression = AviatorEvaluator.compile("books", true); // true - 优先取缓存中编译好的表达式
Object result = expression.execute(params);
System.out.println(result);
// 2、一共有基本书?
System.out.println("=======================2、一共有基本书?========================================================");
expression = AviatorEvaluator.compile("count(books)", true); // true - 优先取缓存中编译好的表达式
result = expression.execute(params);
System.out.println(result);
// 3、购买语文和数学课本需要花费的总金额?
System.out.println("=======================3、购买语文和数学课本需要花费的总金额?========================================================");
/**
* 实现思想:
* 1、先获取语文书的信息,从信息中获取金额
* 2、再获取数学书的信息,从信息中获取金额
* 3、两个金额求和
*/
// 取出语文书的金额
expression = AviatorEvaluator.compile("seq.get(seq.get(filter(books, lambda(item) -> item.name == '语文' end), 0), 'amt')", true); // true - 优先取缓存中编译好的表达式
result = expression.execute(params);
System.out.println("语文书金额:" + result);
// 取出数学书的金额
expression = AviatorEvaluator.compile("seq.get(seq.get(filter(books, lambda(item) -> item.name == '数学' end), 0), 'amt')", true); // true - 优先取缓存中编译好的表达式
result = expression.execute(params);
System.out.println("数学书金额:" + result);
// 求和
expression = AviatorEvaluator.compile("seq.get(seq.get(filter(books, lambda(item) -> item.name == '语文' end), 0), 'amt') + seq.get(seq.get(filter(books, lambda(item) -> item.name == '数学' end), 0), 'amt')", true); // true - 优先取缓存中编译好的表达式
result = expression.execute(params);
System.out.println("求和:" + result);
// 4、购买所有书本需要花费的总金额?
/**
* 实现思想:
* 由于传入 books 数组进去,用 aviator 进行结算,过于复杂
* 所以:
* 1、先使用 jsonpath 取出所有书本的金额,返回数组 [30, 35, 40]
* 2、再使用 aviator 的计算函数 reduce(数组, 运算符,初始值) 进行运算
*/
System.out.println("=======================4、购买所有书本需要花费的总金额?========================================================");
// 使用jsonPath 取值
Object amts = JsonPath.read(src, "$.data.books[*].amt");
expression = AviatorEvaluator.compile("reduce(amts, +, 0)", true); // true - 优先取缓存中编译好的表达式
params.put("amts", amts);
result = expression.execute(params);
System.out.println(result);
}
public String readFile(String filePath) throws IOException {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(filePath);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
StringBuilder builder = new StringBuilder();
while ((line = br.readLine()) != null) {
builder.append(line);
}
br.close();
return builder.toString();
}
}
运行结果:
=======================1、直接返回 books 清单=================================
[{"id":1000,"name":"语文","amt":30},{"id":1001,"name":"数学","amt":35},{"id":1002,"name":"英语","amt":40}]
=======================2、一共有基本书?========================================================
3
=======================3、购买语文和数学课本需要花费的总金额?========================================================
语文书金额:30
数学书金额:35
求和:65
=======================4、购买所有书本需要花费的总金额?========================================================
105
小结:
- 使用 jsonPath 取值,搭配 aviator 求值计算,能实现配置化代码开发