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

1. 前言

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

2. 扩展操作符

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

实现如下:

/***
     * 需求:扩展+操作符 使用"加"汉字替代+的功能
     * @throws Exception
     */
    @Test
    public void ext() throws Exception{
        ExpressRunner runner = new ExpressRunner(false, true);
//        String expressStr = "20 + 5";
        String expressStr = "20 加 5";
        runner.addOperatorWithAlias("加","+","取模操作符定义异常!");
        // isTrace
        Object 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;
    }
    @Override
    public 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的代码扩展性很好。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/235326.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot实现的毕业设计管理系统

一、 系统架构 前端&#xff1a;html | jquery | vue 后端&#xff1a;springboot | thymeleaf | mybatis 环境&#xff1a;jdk1.8 | mysql | maven 二、代码及数据库 三、功能介绍 01. 登录页 02. 教务管理-控制台 03. 教务管理-选题管理-选题大厅 04. 教务管理-选题…

CS106L2023 and CS106B 环境配置(详细教程)

1.问题&#xff1a; &#xff08;1&#xff09;CS106L 运行./setup.sh 脚本时出错 &#xff08;windows 请下载git&#xff0c;在git bash 打开运行&#xff09; &#xff08;2&#xff09;CS106B&#xff0c;QT构建 构建错误&#xff1a;一般构建错误&#xff0c;例如 Erro…

数据护航:用过这款上海迅软DSE文件加密软件,你再也不用担心文件泄露

企业在业务发展过程中避免不了需要将一些重要文件外发给合作伙伴、代理商等情况&#xff0c;而这些外发出去的明文文件存在着巨大的泄密风险。因此迅软DSE文件加密软件结合文件加密功能及外发文件管控&#xff0c;实现对企业文件不同使用途径的安全保护。 迅软DSE文件加密软件…

`vtkClip`多面裁切之闭裁 `vtkClipClosedSurface`(1)

vtkClip多面裁切之闭裁 vtkClipClosedSurface(1) vtkClipClosedSurface文档 详细说明 使用平面集合剪裁闭合曲面。 vtkClipClosedSurface 将使用剪裁平面集合 vtkPlaneCollection剪裁闭合的多边形数据图面。它将通过创建新的多边形面来生成新的闭合表面&#xff0c;其中输入…

STM32F103时钟树

STM32芯片时钟来源 RCC时钟树简图 RCC时钟树详细图 1&#xff0e;当HSI被用于作为PLL时钟的输入时&#xff0c;系统时钟能得到的最大频率是64MHz。 2&#xff0e;用户可通过多个预分频器配置AHB、高速APB(APB2)和低速APB(APB1)域的频率。AHB和 APB2域的最大频率是72MHz。APB1域…

visual studio历史版本下载

点击比较发行声明 https://visualstudio.microsoft.com/zh-hans/downloads/ 点击当前发行说明 https://learn.microsoft.com/zh-cn/visualstudio/releases/2019/release-notes

JS:让2个li标签排列在同一行

前言 在js中&#xff0c;ul元素中li标签是块级元素&#xff0c;现在需要让2个分行的li元素显示在同一行&#xff0c;并且去掉li元素自带的标记符号 li元素处理前的样式如下&#xff1a; 实现 html代码 <div><ul><li>数据1&#xff1a;</li><li&…

freeRTOS使用

创建第一个FreeRTOS程序 1、官网源码下载 &#xff08;1&#xff09;进入FreeRTOS官网FreeRTOS professional services for application and RTOS development and consulting. FreeRTOS is an Open Source Code RTOS &#xff08;2&#xff09;点击下载FreeRTOS 2、处理目录 &…

Golang channle(管道)基本介绍、快速入门

channel(管道)-基本介绍 为什么需要channel&#xff1f;前面使用全局变量加锁同步来解决goroutine的通讯&#xff0c;但不完美 1)主线程在等待所有goroutine全部完成的时间很难确定&#xff0c;我们这里设置10秒&#xff0c;仅仅是估算。 2)如果主线程休眠时间长了&#xff0c…

解决idea 通过build project 手动触发热部署失败

在debug运行项目的过程中&#xff0c;并且保证&#xff08;不添加方法&#xff0c;不修改方法名&#xff09;一定的规则的情况下&#xff0c;可以通过build project 来手动热部署项目&#xff0c;也就是会交换class文件与resouces文件。 设置项 Edit Configurations Modify Op…

MyBatis 四大核心组件之 ResultSetHandler 源码解析

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

【数学建模】《实战数学建模:例题与讲解》第八讲-回归分析(含Matlab代码)

【数学建模】《实战数学建模&#xff1a;例题与讲解》第八讲-回归分析&#xff08;含Matlab代码&#xff09; 回归分析基本概念经典多元线性回归&#xff08;MLR&#xff09;主成分回归&#xff08;PCR&#xff09;偏最小二乘回归&#xff08;PLS&#xff09;建模过程应用和优势…

1688跨境寻源通计划后,都有哪些接口值得我们关注

1688跨境是什么? 最近火出圈的一个新词 今天我带大家走近1688跨境 首先为什么会出现1688跨境&#xff1f; 因为&#xff1a; 新型服务商崛起&#xff0c;反向海淘成趋势 在过去三年&#xff0c;1688涌现了一批新型的服务商: 他们帮助海外B类买家到1688采购&#xff0c…

宝宝洗衣机好吗?婴儿专用洗衣机推荐

我们都知道刚出生的宝宝抵抗力非常弱&#xff0c;接触宝宝的东西&#xff0c;我们要更加重视&#xff0c;而且宝宝的衣服是接触最多的&#xff0c;如果清洗不干净很容易造成细菌感染&#xff0c;所以对于宝妈来说有一款小型可以自动杀菌的洗衣机真的非常重要但现在市面上婴儿洗…

企业如何选择MES系统?

一、技术架构 虽然绝大多数的用户不会关心MES设计的技术架构&#xff0c;但如果是好的MES系统&#xff0c;需首先必须具备先进的技术支撑&#xff0c;只有先进的开发平台配合上可配置的模块模组&#xff0c;才可快速构建出符合不同用户场景的业务功能。 试想一下&#xff1a;在…

基于Springboot+Vue前后端分离的电影推荐系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

17、类模板

17、类模板 类模板类模板的声明类模板的使用类模板的静态成员类模板的递归实例化 类模板扩展数值型的模板参数模板型成员变量模板型成员函数模板型成员类型模板型模板参数 典型模板错误嵌套依赖依赖模板参数访问成员函数模板子类模板访问基类模板类模板中的成员虚函数 类模板 …

Jquery easyui异步提交表单的两种方式

这篇文章分享一下easyui常用的两种表单异步提交的方式。 目录 开始前的准备工作 方式一&#xff1a;利用jquery ajax提交 $.post() $.ajax() 方式二&#xff1a;使用easyui提供的表单提交方式 开始前的准备工作 1、使用HBuilderX创建一个简单的html项目&#xff0c;删除i…

ppt编辑密码如何设置?

大家在PPT中设置了限制编辑&#xff0c;发现后面任然可以编辑文件。那么如何将PPT文件设置成禁止修改模式呢&#xff1f;今天分享几个方法给大家。 方法一 将PPT文件直接保存或者另存为一份文件&#xff0c;在保存时&#xff0c;将文件格式选择为PowerPoint图片演示文稿 方法…

精通TypeScript:打造一个炫酷的天气预报插件

前言 ​ 随着数字化和信息化的发展&#xff0c;数据大屏使用越来越广泛&#xff0c;我们不仅需要展示数据&#xff0c;更需要以一种更加美观的方式展示数据。这就必然需要使用到各种图表组件&#xff0c;比如柱状图、饼图、折线图等等。但是有一些效果不太适合通过这种常规图表…