QLExpress的使用

最近公司要统计一些数据,需要定义一些统计数据的计算公式,然后通过计算公式统计数据。于是我去找了找有没有什么好用的工具。说实话,现在做开发,网上能找到许多实用的工具,而且还是开源的,非常感谢大佬们的分享。今天要说的是QLExpress。

QLExpress的简单介绍

​ QLExpress由阿里的电商业务规则、表达式(布尔组合)、特殊数学公式计算(高精度)、语法分析、脚本二次定制等强需求而设计的一门动态脚本引擎解析工具。它具有以下特性:

  1. 线程安全。
  2. 高效执行。
  3. 弱类型脚本语言。
  4. 安全控制。
  5. 代码精简,依赖最小。

简单的例子

  1. 添加依赖
<dependency><groupId>com.alibaba</groupId><artifactId>QLExpress</artifactId><version>3.2.0</version>
</dependency>
  1. 添加代码
public static void main(String[] args) throws Exception{String express = "2 * 3 / 2 + 4 - 5";ExpressRunner runner = new ExpressRunner();Object result = runner.execute(express,null, null, false,false);// 输出结果,结果为2,使用的时候还是挺方便的System.out.println("计算公式的结果:" + result);
}/*** 以下复制于官网的说明* * 执行一段文本* @param expressString 程序文本* @param context 执行上下文,可以扩展为包含ApplicationContext* @param errorList 输出的错误信息List* @param isCache 是否使用Cache中的指令集,建议为true* @param isTrace 是否输出详细的执行指令信息,建议为false* @param aLog 输出的log* @return* @throws Exception*/
Object execute(String expressString, IExpressContext<String,Object> context,List<String> errorList, boolean isCache, boolean isTrace, Log aLog);

​ 当然,这只是一个简单的例子,QLExpress可不止这样。

实战场景

​ 背景之前也说过了,公式需要先设置一个计算公式,而计算公式可不是像"2 * 3 / 2 + 4 - 5"这样直接将需要计算的值直接写死在公式里的,而是像这样:“avg(item_code_f,item_code_b) +item_code_a ÷ item_code_k - 100”,item_code_f这类数据其实就是数据表里的唯一编码。

​ 计算的时候需要先把通过编码去查找对应的数据值,然后带入公式。其中要注意的是avg是我们自定义的计算符号,意为计算平均值。而且为了用户方便理解,乘法计算的符号是用×而不是*,除法则是÷而不是/,所以这些东西都需要自己去处理。

​ 于是我整理了一下思路,想出了解决的办法,下面是我写的一个demo,可能有些地方略显粗糙,但是我总不能把公司代码直接贴出来,将就着看吧 T_T。

  1. 表结构
CREATE TABLE `calculation_rules` (`id` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '主键',`module_id` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '数据板块id',`rule` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '计算公式',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='计算公式表';
CREATE TABLE `data_item_table` (`id` varchar(32) NOT NULL COMMENT '主键',`item_code` varchar(10) NOT NULL COMMENT '数据项编码',`item_name` varchar(255) NOT NULL COMMENT '数据项名称',PRIMARY KEY (`id`),UNIQUE KEY `uk_item_code` (`item_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='数据项表';
CREATE TABLE `commodity_price` (`id` varchar(32) NOT NULL COMMENT '主键',`item_code` varchar(32) NOT NULL COMMENT '数据项编码',`insert_time` datetime NOT NULL COMMENT '日期',`amount` decimal(13,2) NOT NULL COMMENT '数量/金额,这里反正根据需求,就是一个计算要用到的值',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品价格表';
  1. 如何通过表id去查找对应的数据值,然后带入公式。
public static void main(String[] args) {// 统计时,会传递日期和数据板块id,数据板块id的用处就是获取计算公式// 假如这就是我们获取到的某一个数据板块的公式String str = "avg(item_code_f,item_code_b) +item_code_a ÷ item_code_k - 100";// 处理一下÷和×,毕竟是以*和/作为乘法除法符号的str = str.replace("÷","/");str = str.replace("×","*");// 定义一个正则表达式,过滤掉计算符号String regex = "[()*+/-]";Pattern p = Pattern.compile(regex);Matcher m = p.matcher(str);List<String> list = new ArrayList<>();// 这里注意要先转成Set然后再转成List,因为有可能计算的时候要使用一个数据项的值多次,但是其实都是同一个值list.addAll(Arrays.asList(m.replaceAll(" ").split(" ")).stream().filter(s->{// 通过流来单独过滤avg和数字return !s.equals("avg")&&!s.equals("")&&!isNumeric(s);}).collect(Collectors.toSet()));// 输出一下结果:[item_code_f,item_code_b,item_code_a,item_code_k],这样就成功的将数据项编码给分离出来System.out.println(list.toString());// 然后通过数据项编码可以把对应的统计日期下,对应的数据项编码的数量或者金额获取到,然后通过replace()方法替换调即可// 具体从数据库里取值和替换的代码省略。。。嘿嘿,偷个懒 >_<||| // 最后得到大概这样的数据:avg(1000,2000)+30/2-100String express = "avg(1000,2000)+30/2-100";// 接下来就是使用QLExpress了ExpressRunner runner = new ExpressRunner();// 先定义我们需要的avg函数runner.addFunction("avg",new Operator(){@Overridepublic Object executeInner(Object[] objArray) throw Exception{Double total=0.0;Double average=0.0;for(Double obj: objArray){Double num=Double.valueOf(obj.toString());total = total + num;}average = total/objArray.length;return average;}});// 计算结果,这里是一个重载方法,没有logObject result = runner.execute(express,null, null, false,false);// 顺利拿到结果:1415Double resultNum = Double.valueOf(result.toString());
}/*** 判断是否是数字*/
public static boolean isNumeric(String str){Pattern pattern = Pattern.compile("[0-9]*");Matcher isNum = pattern.matcher(str);if( !isNum.matches() ){return false;}return true;
}

​ QLExpress使用还是挺方便的,而且也很简单,而我上面展示的也只是它的一小部分。实战是最好的老师,有兴趣的同学可以自己去敲上一段代码,另附上官网地址:QLExpress官网。

使用QLExpress动态制定计算公式相关推荐

  1. QLExpress-阿里规则引擎

    QLExpress:GitHub - alibaba/QLExpress: QLExpress is a powerful, lightweight, dynamic language for the ...

  2. 动态展开所有_库存与市场需求之间如何“动态”共舞?库存计划动态模型构建分享...

    库存(Stock)是用来提高交货速度.缓冲需求到单高峰的常用手段,通过按库存生产(MTS)的方法,用储备库存来满足客户需求.并按一定规则补货,无需等待生产周期,可极快地交付.相比按订单生产(MTO)的 ...

  3. 【渝粤题库】陕西师范大学164111 Java及JSP动态网页编程与应用 作业 (高起专)

    <JAVA与JSP动态网页编程与应用>作业 一.单选题 1.以下哪项都是关键字( ) A.package privati protect throw B. false final fina ...

  4. jdk和cglib动态代理介绍

    动态代理介绍: 作用:功能增强:代理可以提供额外的功能控制访问:代理可以控制不让你访问目标 分类:静态代理:简单容易理解例如模拟用户购买U盘的行为用户是客户端,商家是代理,厂家是目标类客户端--代理- ...

  5. 数字IC笔试题---千题解,量大管饱,图文并茂

    前言 出笔试题汇总,是为了总结秋招可能遇到的问题,做题不是目的,在做题的过程中发现自己的漏洞,巩固基础才是目的. 所有题目结果和解释由笔者给出,答案主观性较强,若有错误欢迎评论区指出,资料整理来自于& ...

  6. 携程如何从海量数据中构建精准用户画像?

    摘要: 用户画像作为"大数据"的核心组成部分,在众多互联网公司中一直有其独特的地位. 作为国内旅游OTA的领头羊,携程也有着完善的用户画像平台体系.目前用户画像广泛用于个性化推荐, ...

  7. tensorflow实现基于LSTM的文本分类方法

    http://blog.csdn.net/u010223750/article/details/53334313?locationNum=7&fps=1 引言 学习一段时间的tensor fl ...

  8. 设计模式学习笔记(六:责任链模式)

    1.1概述 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.这就是责任链模式. 责任链模式是使用多个对象 ...

  9. 系统分析与设计 复习

    文章目录 系统分析与设计 复习 第 1 章 系统分析与设计概述 系统特性 DevOps 第 2 章 系统规划 **系统规划步骤** 规划模型 诺兰模型 **CMM 模型** 系统规划方法 战略集合转换 ...

最新文章

  1. 第十五届全国大学生智能车全国总决赛获奖信息-华北赛区
  2. 安卓高级6 拍照或者从相册获取图片 并检测旋转角度或者更新画册扫描
  3. linux下mkdir头文件_Linux部分常用命令学习记录
  4. 28、OSPF配置实验之负载均衡
  5. JavaScript实现数乘以二multiplyByTwo算法(附完整源码)
  6. 架构之:软件架构漫谈
  7. MVC 无法将带 [] 的索引应用于“System.Dynamic.DynamicObject”类型的表达式
  8. mysql5.7卸载语句_MySQL5.7完全卸载
  9. 常见的SQL错误和解决方法
  10. 中国省份城市列表(汉字+拼音)
  11. VS2010 旗舰版和专业版 下载
  12. JavaScript到底应该怎么用?
  13. 如何以CMMI或ISO为指导实施过程改进(黑纸系列一)
  14. VMware 安装WIN10 WIN7
  15. 智慧园区一体化信息管理平台设计方案
  16. 计算机应用基础2004版,计算机应用基础2004年上半年全国试题
  17. java 小数乘法_java复习题69151-_人人文库网
  18. 从指数构建原理看待A股的三千点魔咒
  19. Docker 高级篇
  20. 数据流图 visio

热门文章

  1. CAD初学者如何快速画圆?
  2. repo 错误contains uncommitted changes解决方法
  3. 《你要相信 没有到不了的明天》支撑我走过无数艰难岁月
  4. 火猴浏览器3.0的语义解析突破
  5. yolov4直接调用zed相机实现三维测距(免标定)
  6. 记数排序 桶排序 基数排序
  7. Ubuntu编译Seetaface
  8. 二世古新世界·羽·度假村将于2023年盛大揭幕
  9. Banana Pi BPI-M5 与 Raspberry Pi 4性能测试比较
  10. python串口通信的接收与发送_31.用python中的serial向串口发送和接收数据(案例一)...