RuleEngine规则引擎底层改造AviatorScript 之函数执行

https://gitee.com/aizuda/rule-engine-open
需求:使用上述开源框架进行改造,底层更换成AviatorScript ,函数实现改造。
原本实现方式

    @Override
    public Object run(ExecuteFunctionRequest executeTestRequest) {
        Integer functionId = executeTestRequest.getId();
        RuleEngineFunction engineFunction = this.ruleEngineFunctionManager.getById(functionId);
        if (engineFunction == null) {
            throw new ApiException(ErrorCodeEnum.RULE9999404.getCode(),"不存在函数:{}", functionId);
        }
        String executor = engineFunction.getExecutor();
        if (this.applicationContext.containsBean(executor)) {
            Object abstractFunction = this.applicationContext.getBean(executor);
            // 函数测试均为固定值
            List<ParamValue> paramValues = executeTestRequest.getParamValues();
            Map<String, Value> param = new HashMap<>(paramValues.size());
            for (ParamValue paramValue : paramValues) {
                Constant constant = new Constant(paramValue.getValue(), ValueType.getByValue(paramValue.getValueType()));
                param.put(paramValue.getCode(), constant);
            }
            Function function = new Function(functionId, abstractFunction, ValueType.STRING, param);
            // 无规则参数 input==null
            return function.getValue(null, new RuleEngineConfiguration());
        } else {
            throw new ApiException("容器中找不到{}函数", executor);
        }
    }

可以看到的是,他们首先拿到函数id,然后判断函数是否存在,然后去已经预制好的数据库表中去读取固定的函数名称,然后根据入参进行入参的判断,然后是执行。
因为我们要进行底层改造,我也就是了解了他的实现方式,并没有深入的去了解他的底层是如何实现的。
我们的话,可能入参没有那么复杂,我是自己新建了一个表来存储入参的,具体的实现也是不一样。

@Function
public class LetterToLowerCaseFunction extends AbstractFunction {

    @Executor
    public String executor(@Param(value = "letter",required = false) String letter) {
        if (letter == null) {
            return null;
        }
        return letter.toLowerCase();
    }

    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1) {
        String letter = String.valueOf(arg1.getValue(env));
        if (letter == null) {
            return null;
        }

        return new AviatorString(letter.toLowerCase());
    }
    @Override
    public String getName() {
        return "letterToLowerCaseFunction";
    }
}

这是他们原本的函数实现,是通过Function接口,将实体类注册到spring框架中,然后将类的名字预制到数据中,通过读取某个函数将函数名读取出来,处理问题。

public class TestAviator {
    public static void main(String[] args) {
            //注册函数
            AviatorEvaluator.addFunction(new AddFunction());
            System.out.println(AviatorEvaluator.execute("add(1, 2)"));           // 3.0
            System.out.println(AviatorEvaluator.execute("add(add(1, 2), 100)")); // 103.0
        }
    }
    class AddFunction extends AbstractFunction {
        @Override
        public AviatorObject call(Map<String, Object> env, 
                                  AviatorObject arg1, AviatorObject arg2) {
            Number left = FunctionUtils.getNumberValue(arg1, env);
            Number right = FunctionUtils.getNumberValue(arg2, env);
            return new AviatorDouble(left.doubleValue() + right.doubleValue());
        }
        public String getName() {
            return "add";
        }
    }

AviatorScript 这个是他官方的一个实例文档,可以看的出来实现方式大大的不一样了
其实这个项目的首先的问题是,我们需要将rule-engine 的三个项目合到一个项目中,基于这块只有繁琐但是没有难度我这边就不再提了。

@Override
    public Object runFunction(ExecuteFunctionRequest executeTestRequest) throws Exception{
        Integer functionId = executeTestRequest.getId();
        RuleEngineFunction2 engineFunction = this.ruleEngineFunction2Manager.getById(functionId);

        if (engineFunction == null) {
            throw new ApiException(ErrorCodeEnum.RULE9999404.getCode(),"不存在函数:{}", functionId);
        }

        //获取设置对应的方法名
        String className = engineFunction.getClassName();
        String functionName = engineFunction.getFunctionName();

        if (this.applicationContext.containsBean(className)) {

            AviatorFunction abstractFunction = (AviatorFunction)this.applicationContext.getBean(className);

            QueryWrapper<RuleEngineFunctionParam2> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("function_id", engineFunction.getId());

            //拿到对应的参数集合,参数集合
            List<RuleEngineFunctionParam2> list = ruleEngineFunctionParam2Manager.list(queryWrapper);

            // 入参参数集合
            List<ParamValue> paramValues = executeTestRequest.getParamValues();

            HashMap hashMap = composeParams(list, paramValues);

            AviatorEvaluator.addFunction(abstractFunction);

            String params = "";

            for (RuleEngineFunctionParam2 ruleEngineFunctionParam2 : list) {
                params = params +"arg1,";
            }

            params = params.substring(0, params.length() - 1);

            String expression = functionName+"("+params+")";

            Object execute = AviatorEvaluator.execute(expression, hashMap);

            log.error(execute.toString());

            return execute;
        } else {
            throw new ApiException("容器中找不到{}函数", className+functionName);
        }
    }

    public HashMap composeParams(List<RuleEngineFunctionParam2> list,List<ParamValue> paramValues){

        HashMap params = new HashMap();
        for (int i = 0; i < list.size(); i++) {
            RuleEngineFunctionParam2 ruleEngineFunctionParam2 = list.get(i);
            String paramCode = ruleEngineFunctionParam2.getParamCode();

            for (int j = 0; j < paramValues.size(); j++) {
                ParamValue paramValue = paramValues.get(j);
                String code = paramValue.getCode();
                if (paramCode.equals(code)) {
                    if(ruleEngineFunctionParam2.getValueType().equals("STRING")){
                        params.put(paramCode, paramValue.getValue());
                    }else if(ruleEngineFunctionParam2.getValueType().equals("COLLECTION")){
                        String arr = paramValue.getValue();
                        List<String> items = Arrays.asList(arr.split(","));
                        params.put(paramCode, items);
                    }else if(ruleEngineFunctionParam2.getValueType().equals("NUMBER")){
                        int number = Integer.valueOf(paramValue.getValue());
                        params.put(paramCode, number);
                    }
                }
            }
        }
        return params;
    }

这一块代码是我写的函数执行的底层改造,唯一的问题就是在于传参,不过在当时看来是没有问题的

@Function
public class LetterToUpperCaseFunction extends AbstractFunction {

    @Executor
    public String executor(@Param(value = "letter",required = false) String letter) {
        if (letter == null) {
            return null;
        }
        return letter.toUpperCase();
    }

    @Override
    public AviatorObject call(Map<String, Object> env,AviatorObject arg1) {
        String letter = env.get("letter").toString();
        if (letter == null) {
            return null;
        }

        return new AviatorString(letter.toUpperCase());
    }

    @Override
    public String getName() {
        return "letterToUpperCaseFunction";
    }
}

在执行以上函数代码的时候一点问题都没有,那么问题出在了哪里呢,
String letter = env.get("letter").toString();这个取值,因为我这边取了一个巧,我在发现入参的类型我不好判断之后,我放弃了使用顺序确认入参这个形势,我直接使用的key-value的形势,这样可以在传参的时候一点问题都不会,如果前端传过来的入参的顺序出现问题的情况下,也会如我计划的一样执行,但是确实面临了一个问题,因为后面需要实现一个公式规则的功能
在这里插入图片描述
这个的具体研发可以放在下一篇进行讲述,然后就发现了,因为这个牵扯到给函数传值以及给代码块传值,所以陷入了一个死局,需要进行函数入参的调整,很麻烦,也不是不能做。
后面就转换了实现思路,不在使用String letter = env.get("letter").toString();方式去获取参数中的入参,尊重他人命运,前端传错了前端改吧,不过事实证明也没有出现问题,有点杞人忧天的意思了。

    @Override
    public Object runFunction(ExecuteFunctionRequest executeTestRequest) throws Exception{
        Integer functionId = executeTestRequest.getId();
        RuleEngineFunction2 engineFunction = this.ruleEngineFunction2Manager.getById(functionId);

        if (engineFunction == null) {
            throw new ApiException(ErrorCodeEnum.RULE9999404.getCode(),"不存在函数:{}", functionId);
        }

        //获取设置对应的方法名
        String className = engineFunction.getClassName();
        String functionName = engineFunction.getFunctionName();

        if (this.applicationContext.containsBean(className)) {

            AviatorFunction abstractFunction = (AviatorFunction)this.applicationContext.getBean(className);

            QueryWrapper<RuleEngineFunctionParam2> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("function_id", engineFunction.getId());

            // 入参参数集合
            List<ParamValue> paramValues = executeTestRequest.getParamValues();

            AviatorEvaluator.addFunction(abstractFunction);

            String params = "";

            for (int i = 0; i < paramValues.size(); i++) {
                ParamValue paramValue = paramValues.get(i);
                String value = paramValue.getValue();
                if (paramValue.getValueType().equals("STRING"))
                {
                    params = params + "'" + value +"'" + ",";
                }else if (paramValue.getValueType().equals("NUMBER")){
                    params = params + value + ",";
                }else if (paramValue.getValueType().equals("COLLECTION")){
                    params = params + "'" + value +"'" + ",";
                }
            }

            params = params.substring(0, params.length() - 1);

            String expression = functionName+"("+params+")";

            Object execute = AviatorEvaluator.execute(expression);

            log.error(execute.toString());

            return execute;
        } else {
            throw new ApiException("容器中找不到{}函数", className+functionName);
        }
    }

修改函数显示底层,使用直接参数的方式,后端直接处理参数,方便后面代码块执行,大概是组成add(1, 2)格式。

@Function
public class LetterToUpperCaseFunction extends AbstractFunction {

    @Executor
    public String executor(@Param(value = "letter",required = false) String letter) {
        if (letter == null) {
            return null;
        }
        return letter.toUpperCase();
    }

    @Override
    public AviatorObject call(Map<String, Object> env,AviatorObject arg1) {
        String letter = FunctionUtils.getStringValue(arg1, env);
        if (letter == null) {
            return null;
        }

        return new AviatorString(letter.toUpperCase());
    }

    @Override
    public String getName() {
        return "letterToUpperCaseFunction";
    }
}

函数获取参数底层也进行响应的修改。

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

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

相关文章

5G如何助力物流智能化转型

导语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;你的老朋友&#xff0c;老K。行业群 新书《智能物流系统构成与技术实践》人俱乐部 整版PPT和更多学习资料&#xff0c;请球友到知识星球 【智能仓储物流技术研习社】自行下载 智能制造-话题精读 1、西门子…

移植内核linux-2.6.32.24遇见的问题和解决方法

目录 概述 1 配置编译环境 2 编译内核 2.1 配置内核 2.2 编译存在的问题 2.3 验证zImage 3 移植 yaffs2 3.1 下载yaffs2 3.2 为内核打上 yaffs2 补丁 3.3 配置和编译带 YAFFS2 支持的内核 3.3.1 配置 YAFFS2内核 3.3.2 编译带YAFFS2 支持的内核 3.4 验证带YAFFS2 支…

Mudbus协议CRC校验码C#

Mudbus协议CRC校验码C# 什么是modbus协议特点协议格式modbus-crc16校验原理方法帧校验CRC计算方法&#xff1a;例子 C#代码Demo源码下载 什么是modbus Modbus是一种串行通信协议&#xff0c;最初由Modicon&#xff08;目前属于施耐德电气公司&#xff09;于1979年开发 Modbus协…

机器学习知识点

1鸢尾花分类 鸢尾花分类问题是一个经典的机器学习问题&#xff0c;旨在根据鸢尾花的花萼长度、花萼宽度、花瓣长度和花瓣宽度等特征&#xff0c;将鸢尾花分成三个品种&#xff1a;山鸢尾&#xff08;setosa&#xff09;、变色鸢尾&#xff08;versicolor&#xff09;和维吉尼亚…

使用 proxySQL 来代理 Mysql

我有若干台云主机&#xff0c; 但是只有1个台vm 具有外部ip 而在另1台vm上我安装了1个mysql instance, 正常来讲&#xff0c; 我在家里的电脑是无法连接上这个mysql 尝试过用nginx 代理&#xff0c; 但是nginx只能代理http协议的&#xff0c; mysql 3306 并不是http协议 解决…

Leetcode面试经典150_Q14最长公共前缀

题目&#xff1a; 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀&#xff0c;返回空字符串 ""。 思路A&#xff1a;横向/纵向扫描 Python&#xff1a; class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:s "…

Mac 每次重启终端都要重新配置mysql环境变量解决办法

1、问题 Mac 每次关闭终端后&#xff0c;mysql环境配置就失效了&#xff0c;需要重新配置mysql环境变量 2、解决方法 在 " ~/.zshrc "文件添加" source ~/.bash_profile "即可 vim ~/.zshrc source ~/.bash_profile 3、验证 退出终端后重新打开终端 mys…

PDF锐化

PDF Shaper Ultimate(pdf转图片) 编辑->添加文件->选中一个要处理的pdf 操作->转换->PDF转为图片 ComicEnhancerPro设置(把图片锐化) PDF Shaper Ultimate(图片转pdf) 编辑-添加图片->选中所有锐化处理后的图片 转换->图片转为pdf&#xff08;会把所有图…

3. Django 初探路由

3. 初探路由 一个完整的路由包含: 路由地址, 视图函数(或者视图类), 可选变量和路由命名. 本章讲述Django的路由编写规则与使用方法, 内容分为: 路由定义规则, 命名空间与路由命名, 路由的使用方式.3.1 路由定义规则 路由称为URL (Uniform Resource Locator, 统一资源定位符)…

Springboot使用教程

二、配置文件 SpringBoot使用一个全局的配置文件&#xff0c;配置文件名是固定的&#xff1b; •application.properties •application.yml 1.配置文件的作用&#xff1a; 修改SpringBoot自动配置的默认值&#xff1b;SpringBoot在底层都给我们自动配置好&#xff1b; Y…

HiveSQL之lateral view

lateral view是hiveQL中的一个高级功能&#xff0c;用于和表生成函数一起&#xff0c;来处理嵌套数组和结构的数据&#xff0c;特别是在处理复杂的数据结构如JSON或数组内嵌套数组时特别有用。它允许用户在每一行上应用TGF&#xff08;表生成函数&#xff09;&#xff0c;将生成…

再探Java为面试赋能(二)Java基础知识(二)反射机制、Lambda表达式、多态

文章目录 前言1.4 反射机制1.4.1 Class对象的获取1.4.2 Class类的方法1.4.3 通过反射机制修改只读类的属性 1.5 Lambda表达式1.5.1 函数式接口1.5.2 Lambda表达式的使用 1.6 多态1.6.1 多态的概念1.6.2 多态的实现条件1.6.3 重载&#xff08;Overload&#xff09;和重写&#x…

odoo16 安装

1、安装 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 2、安装git brew install git 3、安装python3 brew install python3 brew install python3.10 -- odoo16 如果用python3.12 - 会报错 brew unlink python3.1…

Python数学建模学习-莱斯利(Leslie)种群模型

Leslie模型是一种用于离散时间的生物种群增长模型&#xff0c;经常用于描述年龄结构对种群增长的影响。在1945年&#xff0c;人口生态学家Patrick H. Leslie&#xff08;莱斯利&#xff09;为了研究具有离散年龄结构的种群&#xff0c;特别是对于有不同年龄阶段的生物&#xff…

nginx This request has been blocked; the content must be served over HTTPS问题处理

This request has been blocked; the content must be served over HTTPS问题处理 1.问题现象2.解决问题3.解决后的现象4.proxy_set_header x-forwarded-proto 作用 1.问题现象 Mixed Content: The page at https://www.ssjxx.cn/ssjy/viy-edu/index.html?systemCodeTW0010#/…

电脑与多台罗克韦尔AB PLC无线通讯的搭建方法分为几步?

在实际系统中&#xff0c;同一个车间里分布多台PLC&#xff0c;通过上位机集中控制。通常所有设备距离在几十米到上百米不等。在有通讯需求的时候&#xff0c;如果布线的话&#xff0c;工程量较大耽误工期&#xff0c;这种情况下比较适合采用无线通信方式。本方案以组态王和2台…

OpenCV单通道图像按像素成倍比例放大(无高斯平滑处理)

OpenCV中的resize函数可以对图像做任意比例的放大(/缩小)处理&#xff0c;该处理过程会对图像做高斯模糊化以保证图像在进行放大&#xff08;/缩小&#xff09;后尽可能保留源图像所展现的具体内容&#xff08;消除固定频率插值/采样带来的香农采样信息损失&#xff09;&#x…

QML学习记录:并排页面切换效果的实现

定义一个ApplicationWindow窗口&#xff0c;通过添加SwipeView和PageIndicator来实现页面切换效果和显示当前页面位置的指示器。 ApplicationWindow {id:rootvisible: truewidth: 340height: 480title: qsTr("SwipeView") // 定义一个SwipeView用于页面切换效果 Swip…

支持向量机(SVM)白话之个人理解(学习记录)

本文仅有文字理解部分&#xff0c;没有相应的数学公式推导过程&#xff0c;便于新手理解。 一、什么是支持向量机 首先我们看下面这张图&#xff0c;在图中圆形和三角形分别代表不同的数据类型&#xff0c;如何画出一条直线使两者能够显著地区分开来呢&#xff1f; 答案可以多…

SSL数字证书基本概念

CA机构 CA机构&#xff0c;即证书授权中心&#xff08;Certificate Authority&#xff09;或称证书授权机构。CA认证中心作为电子商务交易中受信任的第三方&#xff0c;承担公钥体系中公钥合法性检验的责任。 SSL证书和SSL协议 安全套接层SSL&#xff08;Secure Sockets Lay…