基于google aviator计算引擎的场景应用

Aviator是一个开源的Java表达式求值器,不仅支持四则运算、三元运算、逻辑运算,而且其强大的接口支持自定义扩展函数。鉴于此,金融产品重构优化团队在金融产品平台中,选择了这个google的计算引擎,为了扩展我们业务需求,我们自定义了一系列自定义函数,以支撑我们业务场景。

1、简单地API调用示例

  • 第一步:我们的maven工程需要引入依赖
<!-- 表达式解析引擎 -->
<dependency>
   <groupId>com.googlecode.aviator</groupId>
   <artifactId>aviator</artifactId>
   <version>3.0.0</version>
</dependency>
  • 第二步:通过调用AviatorEvaluator.execute的静态方法,类型返回Object类型,示例如下
import com.googlecode.aviator.AviatorEvaluator;
public class SimpleExample {
    public static void main(String[] args) {
        Long result = (Long) AviatorEvaluator.execute("1+2+3");
        System.out.println(result);
    }
}

2、如何自定义一个函数

第一步:我们可以继承AbstractVariadicFunction,实现相应地接口。这里我们自定义一个多个数字求和的函数。

import com.googlecode.aviator.runtime.function.AbstractVariadicFunction;
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.util.Map;

/**
 * @description: 多个数字求和计算(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class SumFunction extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        BigDecimal sum = new BigDecimal(0);
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            sum = sum.add(new BigDecimal(value.toString()));
        }
        return new AviatorDecimal(new BigDecimal(sum.toString()));
    }

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

第二步:把函数注册,并调用

AviatorEvaluator.addFunction(new SumFunction());
System.out.println(AviatorEvaluator.execute("sum(1,2)"));

3、各种表达式类型

3.1、三元表达式、逻辑运算

Map<String,Object> evn = new HashMap<String,Object>(){{
  put("a",3);
  put("b",2);
  put("c",5);
  put("d",-2);
}};
String expression = " (a > b) && (c > 0 || d > 0) ? a : b";
System.out.println(AviatorEvaluator.execute(expression,evn));

3.2、各种内置函数string和math

AviatorEvaluator.execute("string.length('hello')");    // 求字符串长度
AviatorEvaluator.execute("string.contains('hello','h')");  //判断字符串是否包含字符串
AviatorEvaluator.execute("string.startsWith('hello','h')");  //是否以子串开头
AviatorEvaluator.execute("string.endsWith('hello','llo')");  是否以子串结尾

AviatorEvaluator.execute("math.pow(-3,2)");   // 求n次方
AviatorEvaluator.execute("math.sqrt(14.0)");   //开平方根
AviatorEvaluator.execute("math.sin(20)");    //正弦函数

4、支持的数据类型

  • Number类型:数字类型,支持两种类型,分别对应Java的Long和Double,也就是说任何整数都将被转换为Long,而任何浮点数都将被转换 为Double,包括用户传入的数值也是如此转换。不支持科学计数法,仅支持十进制。如-1、100、2.3等。
  • String类型:字符串类型,单引号或者双引号括起来的文本串,如’helloworld’,变量如果传入的是String或者Character也将转为String类型。
  • Bool类型:常量true和false,表示真值和假值,与java的Boolean.TRUE和Boolean.False对应。
  • Pattern类型: 类似Ruby、perl的正则表达式,以//括起来的字符串,如/\d+/,内部实现为java.util.Pattern。
  • 变量类型:与Java的变量命名规则相同,变量的值由用户传入,如"a"、"b"等
  • nil类型:常量nil,类似java中的null,但是nil比较特殊,nil不仅可以参与==、!=的比较,也可以参与>、>=、<、<=的比较,Aviator规定任何类型 都n大于nil除了nil本身,nil==nil返回true。用户传入的变量值如果为null,那么也将作为nil处理,nil打印为null。

5、支持操作符

5.1 算术运算符

Aviator支持常见的算术运算符,包括+ - * / % 五个二元运算符,和一元运算符"-"。其中 - * / %和一元的"-"仅能作用于Number类型。 "+"不仅能用于Number类型,还可以用于String的相加,或者字符串与其他对象的相加。Aviator规定,任何类型与String相加,结果为String。

5.2 逻辑运算符

Avaitor的支持的逻辑运算符包括,一元否定运算符"!",以及逻辑与的"&&",逻辑或的"||"。逻辑运算符的操作数只能为Boolean。 关系运算符
Aviator支持的关系运算符包括"<" “<=” “>” “>=” 以及"==“和”!=" 。 &&和||都执行短路规则。
关系运算符可以作用于Number之间、String之间、Pattern之间、Boolean之间、变量之间以及其他类型与nil之间的关系比较,不同类型除了nil之 外不能相互比较。
Aviator规定任何对象都比nil大除了nil之外。

5.3 位运算符

Aviator支持所有的Java位运算符,包括"&" “|” “^” “~” “>>” “<<” “>>>”。

5.4 匹配运算符

匹配运算符"=~"用于String和Pattern的匹配,它的左操作数必须为String,右操作数必须为Pattern。匹配成功后,Pattern的分组将存于变量 $num,num为分组索引。

5.5 三元运算符

Aviator没有提供if else语句,但是提供了三元运算符 “?:”,形式为 bool ? exp1: exp2。 其中bool必须为结果为Boolean类型的表达式,而exp1和 exp2可以为任何合法的Aviator表达式,并且不要求exp1和exp2返回的结果类型一致。

6、支持自定义

nvl:如果为空,设置默认值

/**
 * @description: 为空时,设置一个默认值
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Nvl extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number originValue = FunctionUtils.getNumberValue(args[0], env);
        Number defaultValue = FunctionUtils.getNumberValue(args[1], env);
        return new AviatorDecimal(new BigDecimal(Optional.ofNullable(originValue).orElse(defaultValue).toString()));
    }

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

sum:多个数字求和

/**
 * @description: 多个数字求和计算(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Sum extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        BigDecimal sum = new BigDecimal(0);
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            sum = sum.add(new BigDecimal(value.toString()));
        }
        return new AviatorDecimal(new BigDecimal(sum.toString()));
    }

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

min:多个数字求最小值

/**
 * @description: 多个数字求最小值(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Min extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        List<BigDecimal> list = new ArrayList<>();
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            list.add(new BigDecimal(value.toString()));
        }
        list.sort(Comparator.comparing(BigDecimal::doubleValue));
        return new AviatorDecimal(new BigDecimal(list.get(0).toString()));
    }

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

max:多个数字求最大值

/**
 * @description: 多个数字求最大值(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Max extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        List<BigDecimal> list = new ArrayList<>();
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            list.add(new BigDecimal(value.toString()));
        }
        list.sort(Comparator.comparing(BigDecimal::doubleValue).reversed());
        return new AviatorDecimal(new BigDecimal(list.get(0).toString()));
    }

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

round:四舍五入

/**
 * @description: 四舍五入
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Round extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number value = FunctionUtils.getNumberValue(args[0], env);
        return new AviatorDecimal(Math.round(value.doubleValue()));
    }

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

ceil:向上取整

/**
 * @description: 向上取整
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Ceil extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number value = FunctionUtils.getNumberValue(args[0], env);
        return new AviatorDecimal(Math.ceil(value.doubleValue()));
    }

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

floor:向下取整

/**
 * @description: 向下取整
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Floor extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number value = FunctionUtils.getNumberValue(args[0], env);
        return new AviatorDecimal(Math.floor(value.doubleValue()));
    }

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

7、扩展阅读

源码地址:https://github.com/killme2008/aviator
相关文档:https://www.yuque.com/boyan-avfmj/aviatorscript


下面的是我的公众号二维码图片,欢迎关注。
秋夜无霜

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值