RuleEngine规则引擎底层改造AviatorScript 之公式规则

前情提要,看上一个文章,具体要实现的效果就是

当然上来的问题就是前端的问题,这个框首先他们用的是富文本,富文本传到后台的结果是前端脚本,带着h5的标签,后面改成了这个,当时这个东西其实和后端关系不大,就是如何处理换行符而已,使用这个之后换行符变成了/n,

其实我们也是比着普通规则新建的一个功能,不过有很多的自己的设计

他们的实现是这样的

java 复制代码
     */
    @Override
    public Object run(RunTestRequest runTestRequest) {
        log.info("模拟运行规则:{}", runTestRequest.getCode());
        RuleEngineGeneralRulePublish rulePublish = this.ruleEngineGeneralRulePublishManager.lambdaQuery()
                .eq(RuleEngineGeneralRulePublish::getStatus, runTestRequest.getStatus())
                .eq(RuleEngineGeneralRulePublish::getGeneralRuleCode, runTestRequest.getCode())
                .eq(RuleEngineGeneralRulePublish::getWorkspaceCode, runTestRequest.getWorkspaceCode())
                .one();
        if (rulePublish == null) {
            // 如果测试找不到,用线上  此场景出现在只有一个线上的时候
            rulePublish = this.ruleEngineGeneralRulePublishManager.lambdaQuery()
                    .eq(RuleEngineGeneralRulePublish::getStatus, DataStatus.PRD.getStatus())
                    .eq(RuleEngineGeneralRulePublish::getGeneralRuleCode, runTestRequest.getCode())
                    .eq(RuleEngineGeneralRulePublish::getWorkspaceCode, runTestRequest.getWorkspaceCode())
                    .one();
            if (rulePublish == null) {
                throw new ValidException("找不到可运行的规则数据:{},{},{}", runTestRequest.getWorkspaceCode(), runTestRequest.getCode(), runTestRequest.getStatus());
            }
        }
        Input input = new DefaultInput(runTestRequest.getParam());
        log.info("初始化规则引擎");
        RuleEngineConfiguration ruleEngineConfiguration = new RuleEngineConfiguration();
        Container.Body<GeneralRule> generalRuleContainer = ruleEngineConfiguration.getGeneralRuleContainer();
        GeneralRule rule = GeneralRule.buildRule(rulePublish.getData());
        generalRuleContainer.add(rule);
        GeneralRuleEngine engine = new GeneralRuleEngine(ruleEngineConfiguration);
        // 加载变量
        engine.getConfiguration().setEngineVariable(this.ruleEngineConfiguration.getEngineVariable());
        return engine.execute(input, runTestRequest.getWorkspaceCode(), runTestRequest.getCode());
    }

然后我们改成了这个样子

java 复制代码
    @Override
    public Object formularun(RunTestRequest runTestRequest) {
        QueryWrapper<RuleEngineFunction2> wrapper = new QueryWrapper<>();
        List<RuleEngineFunction2> list = ruleEngineFunction2Manager.list(wrapper);
        for (int i = 0; i < list.size(); i++) {
            RuleEngineFunction2 ruleEngineFunction2 = list.get(i);
            //获取设置对应的方法名
            String className = ruleEngineFunction2.getClassName();
            String functionName = ruleEngineFunction2.getFunctionName();
            if (applicationContext.containsBean(className)) {
                AviatorFunction abstractFunction = (AviatorFunction)applicationContext.getBean(className);
                AviatorEvaluator.addFunction(abstractFunction);
            }
        }

        String funcation = runTestRequest.getFuncation();
        funcation = removeHtmlTags(funcation);
        System.out.println(funcation);
        Expression compiledExp = AviatorEvaluator.compile(funcation);

        Map<String, Object> param = runTestRequest.getParam();

        String res = String.valueOf(compiledExp.execute(param));
        System.out.println(res);
        return null;
    }

    public  String removeHtmlTags(String input) {
        return input.replaceAll("<[^>]*>", "");
    }
}

实现方式,但是这个时候出现了问题,就是函数底层实现的时候出现了问题,然后我们将函数的实现修改了,这个代码就几乎没有什么变动了,这个时候有一个另外的需求。就是需要有一个函数nvlFunction,这个函数是用来干啥的呢,就是说处理入参的,出现了这个函数就是表示有入参,这个函数一共两个参数,第一个参数,是取自函数这个功能的字段,要求是函数功能的函数code值,用来表示入参,另一个参数就是当这个入参不输入的时候,将这个参数赋值给对应的函数。

听着不难,实现的话我也是觉得挺简单的

java 复制代码
@Function
public class NvlFunction extends AbstractFunction {
    @Override
    public String getName() {
        return "nvlFunction";
    }

    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
        String letter1 = FunctionUtils.getStringValue(arg1, env);
        String letter2 = FunctionUtils.getStringValue(arg2, env);
        System.out.println("letter1"+letter1);
        System.out.println("letter2"+letter2);
        return new AviatorString(letter2);
    }
}

初版,发现不大行,如果参数没有穿进去不大对,

java 复制代码
@Function
public class NvlFunction extends AbstractFunction {
    @Override
    public String getName() {
        return "nvlFunction";
    }

    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
        if (arg1 != null && !"".equals(arg1)) {
            return arg1;
        }
        return arg2;
    }
}

然后换成了这个,发现也是不大行,即使为空的话这个对象AviatorObject 也不会为null

java 复制代码
@Function
public class NvlFunction extends AbstractFunction {
    @Override
    public String getName() {
        return "nvlFunction";
    }

    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
        Object param1 = arg1.getValue(env);
        if (param1 == null || param1.toString().isEmpty()) {
            return arg2;
        } else {
            return arg1;
        }
    }
}

发现了只有这个value是null,当这个入参是空的时候,至此改造全部完成了,剩下的就是他原本框架的小bug的修改以及小功能的新增了。

相关推荐
AI你一生一世3 小时前
不止于时序存储:DolphinDB 如何成为 AI 时代的工业智能底座
java·人工智能·struts·时序数据库·工业智能·dolphindb·ai基础设施
云-缩影3 小时前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端
瑞克-桑切斯4 小时前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
海的透彻8 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
code2cat8 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
后台模板学习9 小时前
大模型 Prompt 工程在电商订单系统中的踩坑记录
java·python·prompt
w_zero_one9 小时前
算法--构造
java·数据结构·算法
SL_staff9 小时前
制造业订单交付崩盘?用四层协同框架重建交付可信度(技术实践)
java·产品·全栈
SL_staff10 小时前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈
Mikko711 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端