JsonPath 搭配 Aviator 表达式引擎使用案例

导语

推荐读者阅读较为官方的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 求值计算,能实现配置化代码开发
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值