规则引擎aviatorEvaluator注意点

规则引擎aviatorEvaluator注意点

官方文档:AviatorScript 编程指南(5.0) · 语雀

1、依赖

XML 复制代码
        <!--规则引擎-->
        <dependency>
            <groupId>com.googlecode.aviator</groupId>
            <artifactId>aviator</artifactId>
            <version>5.4.3</version>
        </dependency>

2、自定义函数

java 复制代码
package com.jayce.boot.route.common.aviatorEvaluator;

import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorDecimal;
import com.googlecode.aviator.runtime.type.AviatorObject;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;

public class RoundFunction extends AbstractFunction {
    private static final long serialVersionUID = 1;


    @Override
    public AviatorObject call(final Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
        Number number = FunctionUtils.getNumberValue(arg1, env);
        Number number2 = FunctionUtils.getNumberValue(arg2, env);
        
        BigDecimal numberData = new BigDecimal(number.toString());
        // 四舍五入
        BigDecimal roundedHalfUp = numberData.setScale(number2.intValue(), RoundingMode.HALF_UP);
        return AviatorDecimal.valueOf(roundedHalfUp);
    }


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

使用时:

String expression = "ROUND((task_a + task_b) - (task_c/task_d) + task_a*task_c,2)";

Expression compiledExp = AviatorEvaluator.getInstance().compile(expression);

Expression compiledExp = instance.compile(expression);

Map<String, Object> paramMap = new HashMap<>();

paramMap.put("task_a", 3.666666666666666);

paramMap.put("task_b", 7);

paramMap.put("task_c", 1);

paramMap.put("task_d", 2);

Object result = compiledExp.execute(paramMap);

3、关于计算精度问题

// -- 1. 解析浮点数为 Decimal 类型

AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();

instance.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true);

// -- 2. 解析整数为 Decimal 类型

instance.setOption(Options.ALWAYS_PARSE_INTEGRAL_NUMBER_INTO_DECIMAL, true);

4、除法变量替换表达式存在bug

如:String expression = "1/2"; result = 0.5;

a=1,b=2;

String expression = "a/b"; result = 0;

得出结果不一样,底层处理可能存在计算漏洞。

临时解决办法,先自行定义规则进行替换,再直接数字直接运算

替换方法:

java 复制代码
/**
     * 替换字符串表达式中的变量为map中对应的值。
     *
     * @param expression 包含变量的数学表达式
     * @param values     存储变量及其值的映射
     * @return 替换后的数学表达式
     */
    public static String replaceVariables(String expression, Map<String, Object> values) {
        // 正则表达式用于匹配变量名
        //正则表达式:\\b[a-zA-Z_][a-zA-Z0-9_]*\\b 用于匹配变量名。这里的 \b 是单词边界,确保我们只匹配完整的变量名,而不是部分字符串
        Pattern pattern = Pattern.compile("\\b[a-zA-Z_][a-zA-Z0-9_]*\\b");
        Matcher matcher = pattern.matcher(expression);

        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String variable = matcher.group(); // 获取匹配到的变量名
            if (values.containsKey(variable)) {
                String replacement = String.valueOf(values.get(variable));
                // 使用找到的值替换变量
                matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
            } else {
                // 如果变量不在map中,保留原样
                matcher.appendReplacement(sb, Matcher.quoteReplacement(variable));
            }
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

使用示例:

String expression = "ROUND((task_a + task_b) - (task_c/task_d) + task_a*task_c,2)";

Map<String, Object> paramMap = new HashMap<>();

变量赋值............

//计算逻辑手动替换,自动替换有bug,除法丢精度

expression = replaceVariables(expression, paramMap);

//参数无需传入

Object result = xxx.execute();

相关推荐
7哥♡ۣۖᝰꫛꫀꪝۣℋ4 小时前
Spring-cloud\Eureka
java·spring·微服务·eureka
老毛肚4 小时前
手写mybatis
java·数据库·mybatis
两点王爷4 小时前
Java基础面试题——【Java语言特性】
java·开发语言
choke2334 小时前
[特殊字符] Python 文件与路径操作
java·前端·javascript
choke2334 小时前
Python 基础语法精讲:数据类型、运算符与输入输出
java·linux·服务器
岁岁种桃花儿4 小时前
CentOS7 彻底卸载所有JDK/JRE + 重新安装JDK8(实操完整版,解决kafka/jps报错)
java·开发语言·kafka
roman_日积跬步-终至千里5 小时前
【Java并发】Java 线程池实战:警惕使用CompletableFuture.supplyAsync
java·开发语言·网络
毕设源码-钟学长5 小时前
【开题答辩全过程】以 基于Springboot的扶贫众筹平台为例,包含答辩的问题和答案
java·spring boot·后端
CodeSheep程序羊5 小时前
拼多多春节加班工资曝光,没几个敢给这个数的。
java·c语言·开发语言·c++·python·程序人生·职场和发展
我是咸鱼不闲呀6 小时前
力扣Hot100系列19(Java)——[动态规划]总结(上)(爬楼梯,杨辉三角,打家劫舍,完全平方数,零钱兑换)
java·leetcode·动态规划