05.仿简道云公式函数实战-扩展和自定义操作符和函数

2023-12-11 10:44

本文主要是介绍05.仿简道云公式函数实战-扩展和自定义操作符和函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 前言

在上一篇文章中我们学习了QLExpress的基础操作符和java对象的操作,通过大量的测试用例,我们学习了QLExpress的基础语法与使用,本篇文章,我们介绍使用QLExpress的进阶内容,主要知识点是扩展操作符和自定义操作符。

2. 扩展操作符

需求:实现一个操作符"加",它的功能具备与操作符"+"的功能一样。你是不是想到要用addOperatorWithAlias方法?

实现如下:

/**** 需求:扩展+操作符 使用"加"汉字替代+的功能* @throws Exception*/@Testpublic void ext() throws Exception{ExpressRunner runner = new ExpressRunner(false, true);
//        String expressStr = "20 + 5";String expressStr = "20 加 5";runner.addOperatorWithAlias("加","+","取模操作符定义异常!");// isTraceObject rst = runner.execute(expressStr, null, null, true, true);System.out.println(rst);}

QLExpress是如何实现"加"替换"+"的这个功能呢?首先我们进入addOperatorWithAlias方法的源码

public void addOperatorWithAlias(String aliasName, String name, String errorInfo) throws Exception {if (!this.operatorMap.containsKey(name)) {throw new QLException(name + " 不是系统级别的操作符号,不能设置别名");} else {OperatorBase originalOperator = this.operatorMap.get(name);if (originalOperator == null) {throw new QLException(name + " 不能被设置别名");}OperatorBase destOperator;if (originalOperator instanceof CanClone) {destOperator = ((CanClone)originalOperator).cloneMe(aliasName, errorInfo);} else {Class<OperatorBase> opClass = (Class<OperatorBase>)originalOperator.getClass();Constructor<OperatorBase> constructor;try {constructor = opClass.getConstructor(String.class, String.class, String.class);} catch (Exception e) {throw new QLException(name + " 不能被设置别名:" + e.getMessage());}if (constructor == null) {throw new QLException(name + " 不能被设置别名");}destOperator = constructor.newInstance(aliasName, name, errorInfo);}if (this.operatorMap.containsKey(aliasName)) {throw new RuntimeException("操作符号:\"" + aliasName + "\" 已经存在");}this.addOperator(aliasName, destOperator);}
}

通过这个逻辑我们可知,首先QLExpress根据"+"符号操作符找到OperatorAdd作为originalOperator,然后通过originalOperator.getClass();获取opClass,根据opClass.getConstructor(String.class, String.class, String.class);找到构造函数,根据constructor.newInstance(aliasName, name, errorInfo);反射生成destOperator,最后调用this.addOperator(aliasName, destOperator)等同于addOperator("加",newOperatorAdd("+"));

3.自定义操作符

尽管QLExpress表达式引擎封装了好多操作符,常规的使用没有问题,但是总归项目或者产品上有个性化的操作符。那么这个时候我们应该怎么使用QLExpress来满足需求,这也是我想强调的一个地方就是QLExpress引擎的扩展性很强,我们可以借助QLExpress引擎扩展实现自定义操作符。

首先,我们还是模拟一个需求,比如我们想实现一个操作符union,该操作符功能为所有以参数形式给出的值拼接结果返回。

/**** 自定义操作符 * @throws Exception*/
@Test
public void union() throws Exception{ExpressRunner runner = new ExpressRunner(false, true);String expressStr = "'a' union 'b' union 3";runner.addOperator("union",new OperatorUnion());Object rst = runner.execute(expressStr, null, null, true, true);System.out.println(rst);
}

4. 自定义函数

使用QLExpress如何自定义函数以及QLExpress相关API。在这里我首先给一个简单的列子,通过这个例子我们引出知识点。

需求:实现一个sum函数,通过sum函数计算求和。

/**** 自定义函数* @throws Exception*/
@Test
public void sum() throws Exception{ExpressRunner runner = new ExpressRunner(false, true);String expressStr = "sum(1,2,3)";runner.addFunction("sum",new OperatorSum("sum"));Object rst = runner.execute(expressStr, null, null, true, true);System.out.println(rst);
}

runner.addFunction("sum",new OperatorSum("sum"));我们自定义的函数,要添加到ExpressRunner中,这样在使用sum函数的时候,就能执行我们在OperatorSum这个类中的逻辑。

OperatorSum类的代码就是自定义函数的内容

import com.ql.util.express.Operator;
import com.ql.util.express.OperatorOfNumber;
import com.ql.util.express.exception.QLException;/*** 类描述: 类描述: SUM(number1, [number2], …)函数使所有以参数形式给出的数字相加并返回和。* @author admin* @version 1.0.0* @date 2023/11/20 15:39*/
public class OperatorSum extends Operator {public OperatorSum(String name) {this.name = name;}@Overridepublic Object executeInner(Object[] lists) throws Exception {if (lists.length == 0) {throw new QLException("操作数异常");}Object result = 0;for (int i = 0; i < lists.length; i++) {result = OperatorOfNumber.add(result, lists[i], isPrecise);}return result;}
}

我们在来看QLExpress中addFunction做了什么处理。以下为addFunction方法代码

/*** 添加函数定义** @param name 函数名称* @param op   对应的操作实现类*/
public void addFunction(String name, OperatorBase op) {// 操作符的管理器this.operatorManager.addOperator(name, op);// 语法定义的管理器this.manager.addFunctionName(name);
}

此类位于

语法分析和计算的入口类ExpressRunner中。

咱们暂且先理解到这,就是自定义的函数最后通过addFunction交给了ExpressRunner类中,这样ExpressRunner中调用execute方法就能执行到我们自定义的逻辑。

5.总结

本篇文章主要介绍了使用QLExpress扩展操作符,自定义操作符和自定义函数。从侧面也能反映出来QLExpress的代码扩展性很好。

最近笔者创建了一个圈子纷传

欢迎大家加入一起交流学习。

这篇关于05.仿简道云公式函数实战-扩展和自定义操作符和函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/480413

相关文章

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Pandas中统计汇总可视化函数plot()的使用

《Pandas中统计汇总可视化函数plot()的使用》Pandas提供了许多强大的数据处理和分析功能,其中plot()函数就是其可视化功能的一个重要组成部分,本文主要介绍了Pandas中统计汇总可视化... 目录一、plot()函数简介二、plot()函数的基本用法三、plot()函数的参数详解四、使用pl

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI