# aviator-extend **Repository Path**: grapegun/aviator-extend ## Basic Information - **Project Name**: aviator-extend - **Description**: Aviator是一个开源的Java表达式求值器,不仅支持四则运算、三元运算、逻辑运算,而且其强大的接口支持自定义扩展函数。鉴于此,我原先的研发团队结合公司业务场景,选择了这个google的计算引擎,为了扩展我们业务需求,定义了一系列自定义函数,以支撑我们业务场景。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 21 - **Created**: 2021-10-26 - **Last Updated**: 2021-10-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [toc] # 概述 >Aviator是一个开源的Java表达式求值器,不仅支持四则运算、三元运算、逻辑运算,而且其强大的接口支持自定义扩展函数。鉴于此,我原先的研发团队结合公司业务场景,选择了这个google的计算引擎,为了扩展我们业务需求,定义了一系列自定义函数,以支撑我们业务场景。 [源代码](https://gitee.com/suze/aviator-extend) # 特性 ## 数据类型 - `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。 ## 操作类型 ### 算术运算符 Aviator支持常见的算术运算符,包括+ - * / % 五个二元运算符,和一元运算符"-"。其中 - * / %和一元的"-"仅能作用于Number类型。 "+"不仅能用于Number类型,还可以用于String的相加,或者字符串与其他对象的相加。Aviator规定,任何类型与String相加,结果为String。 ### 逻辑运算符 Avaitor的支持的逻辑运算符包括,一元否定运算符"!",以及逻辑与的"&&",逻辑或的"||"。逻辑运算符的操作数只能为Boolean。 关系运算符 Aviator支持的关系运算符包括"<" “<=” “>” “>=” 以及"==“和”!=" 。 &&和||都执行短路规则。 关系运算符可以作用于Number之间、String之间、Pattern之间、Boolean之间、变量之间以及其他类型与nil之间的关系比较,不同类型除了nil之 外不能相互比较。 Aviator规定任何对象都比nil大除了nil之外。 ### 位运算符 Aviator支持所有的Java位运算符,包括"&" “|” “^” “~” “>>” “<<” “>>>”。 ### 匹配运算符 匹配运算符"=~"用于String和Pattern的匹配,它的左操作数必须为String,右操作数必须为Pattern。匹配成功后,Pattern的分组将存于变量 $num,num为分组索引。 ### 三元运算符 Aviator没有提供if else语句,但是提供了三元运算符 “?:”,形式为 bool ? exp1: exp2。 其中bool必须为结果为Boolean类型的表达式,而exp1和 exp2可以为任何合法的Aviator表达式,并且不要求exp1和exp2返回的结果类型一致。 # 扩展特性 ## 数字扩展 ### 1、多个数字求和:sum >对多个数字进行求和,忽略空值,作为0处理,提供兼容。 示例代码: ```java /** * @description: 多个数字求和计算(其中任何一个数字为空则作为0处理) * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class SumTest { @Test public void test(){ Map evn = new HashMap(){{ put("x",2); put("y",4); put("z",8); }}; System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("sum(x,y,z,h)").env(evn).build())); } } ``` 输出: ```shell 14 ``` ### 2、多个数字获取最大值:max >对多个数字获取最大值,忽略空值,作为0处理,提供兼容。 示例代码: ```java /** * @description: 多个数字求最大值(其中任何一个数字为空则作为0处理) * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class MaxTest { @Test public void test(){ Map evn = new HashMap(){{ put("x",2); put("y",4); put("z",8); }}; System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("max(x,y,z,h)").env(evn).build())); } } ``` 输出: ```shell 8 ``` ### 3、多个数字获取最大值:min >对多个数字获取最小值,忽略空值,作为0处理,提供兼容。 示例代码: ```java /** * @description: 多个数字求最小值(其中任何一个数字为空则作为0处理) * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class MinTest { @Test public void test(){ Map evn = new HashMap(){{ put("x",2); put("y",4); put("z",8); }}; System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("min(x,y,z,h)").env(evn).build())); } } ``` 输出: ```shell 2 ``` ### 4、向上取整:ceil >向上取整 示例代码: ```java /** * @description: 向上取整 * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class CeilTest { @Test public void test(){ System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(1.2)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(1.6)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(201)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(196)").env(Collections.emptyMap()).build())); } } ``` 输出: ```shell 2.0 2.0 201.0 196.0 ``` ### 5、向下取整:ceil >向上取整 示例代码: ```java /** * @description: 向下取整 * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class FloorTest { @Test public void test(){ System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(1.2)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(1.6)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(201)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(196)").env(Collections.emptyMap()).build())); } } ``` 输出: ```shell 1.0 1.0 201.0 196.0 ``` ### 6、四舍五入:round >四舍五入 示例代码: ```java /** * @description: 四舍五入 * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class RoundTest { @Test public void test(){ System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(1.2)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(1.6)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(201)").env(Collections.emptyMap()).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(196)").env(Collections.emptyMap()).build())); } } ``` 输出: ```shell 1 2 201 196 ``` ### 7、精度处理:scale >精度处理,具体参数说明查看 org.suze.aviator.function.number.Scale 示例代码: ```java /** * @description: 对数字取整方式 和 精度进位 处理 * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class ScaleTest { @Test public void test(){ Map evn = new HashMap(){{ put("x",15.344); }}; System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,0,0)").env(evn).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,0,1)").env(evn).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,0,2)").env(evn).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,-2,1)").env(evn).build())); System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("scale(x,-2,2)").env(evn).build())); } } ``` 输出: ```shell 15 16 15 100 0 ``` ## 集合扩展 ### 1、判断一个字符串是否在一个字符串区间集合中:in(finder,delimiter,values) >判断一个字符串是否在一个字符串区间集合中,finder代表查找项,delimiter字符串分隔符,values以delimiter分割的字符串。 示例代码: ```java /** * @description: 判断一个字符串是否在一个字符串区间集合中 * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class InTest { @Test public void test(){ Map evn = new HashMap(){{ put("x",15); }}; String expression = "in(x, ',' , '15,34,22')"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println(AviatorExecutor.executeBoolean(ctx)); } } ``` 输出: ```shell true ``` ### 2、判断一个字符串是否不在一个字符串区间集合中:notin(finder,delimiter,values) >判断一个字符串是否不在一个字符串区间集合中,finder代表查找项,delimiter字符串分隔符,values以delimiter分割的字符串。 示例代码: ```java /** * @description: 判断一个字符串是否在一个字符串区间集合中 * @Date : 2021/4/11 9:43 AM * @Author : 石冬冬-Seig Heil */ public class InTest { @Test public void test(){ Map evn = new HashMap(){{ put("x",15); }}; String expression = "notin(x, ',' , '15,34,22')"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println(AviatorExecutor.executeBoolean(ctx)); } } ``` 输出: ```shell false ``` ## 通用函数 >基于日常业务场景需求,扩展的相关自定义函数。 ### 1、两日期相差天数,参数类型为date:days.diff(current,destination) >两日期相差天数,参数类型为date 示例代码: ```java /** * @description: 两日期相差天数,参数类型为date * @Date : 2021/4/11 10:19 AM * @Author : 石冬冬-Seig Heil */ public class DiffDaysTest { @SneakyThrows @Test public void test(){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Map evn = new HashMap(){{ put("current",simpleDateFormat.parse("2021-04-11")); put("destination",simpleDateFormat.parse("2020-04-11")); }}; String expression = "days.diff(current,destination)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println( AviatorExecutor.executeBigDecimal(ctx)); } } ``` 输出: ```shell 365 ``` ### 2、获取生日年龄:age(date) >根据出生年月日计算年龄,出生年月日类型为字符串 示例代码: ```java /** * @description: 根据出生年月日计算年龄,出生年月日类型为字符串 * @Date : 2021/4/11 10:19 AM * @Author : 石冬冬-Seig Heil */ public class AgeTest { @SneakyThrows @Test public void test(){ Map evn = new HashMap(){{ put("birth","19880808"); }}; String expression = "age(birth)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println("age:" + AviatorExecutor.execute(ctx)); } } ``` 输出: ```shell 32 ``` ### 3、截取字符串中的数字求和:string.numbers.sum >截取字符串中的数字求和 示例代码: ```java /** * @description: 截取字符串中的数字求和 * @Date : 2021/4/11 10:19 AM * @Author : 石冬冬-Seig Heil */ public class StringNumbersSumTest { @SneakyThrows @Test public void test(){ String str = "保费借款金额:人民币(第一年:5600.00元;第二年:1110.00元;第三年:1000.00元)"; Map evn = new HashMap(){{ put("str",str); }}; String expression = "string.numbers.sum(str, '-', ':', '元')"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).cached(false).build(); System.out.println(AviatorExecutor.execute(ctx)); } } ``` 输出: ```shell 7710.00 ``` ### 4、数字转大写金额:chinese.number.upper(num) >截取字符串中的数字求和 示例代码: ```java /** * @description: 数字转大写金额 * @Date : 2021/4/11 10:19 AM * @Author : 石冬冬-Seig Heil */ public class ChineseNumberUpperTest { @SneakyThrows @Test public void test(){ BigDecimal num = new BigDecimal("11111.01"); Map evn = new HashMap(){{ put("num",num); }}; String expression = "chinese.number.upper(num)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println(AviatorExecutor.execute(ctx)); } } ``` 输出: ```shell 壹万壹仟壹佰壹拾壹元零壹分 ``` ## 对象函数 >为空时,设置一个默认值 ### 1、为空时,设置一个默认值:nvl(value,defaultValue) >两日期相差天数,参数类型为date 示例代码: ```java /** * @description: 根据出生年月日计算年龄,出生年月日类型为字符串 * @Date : 2021/4/11 10:19 AM * @Author : 石冬冬-Seig Heil */ public class NvlTest { @SneakyThrows @Test public void test(){ String expression = "nvl(a,0)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build(); System.out.println(AviatorExecutor.executeBigDecimal(ctx)); } } ``` 输出: ```shell 0 ``` ### 2、字符串转数字:objects.toNumber(value,defaultValue) >字符串转数字,如果字符串为空,则使用默认值作为返回值,objects.toNumber(value,defaultValue) 示例代码: ```java /** * @description: objects.toNumber(x,y) * @Date : 2021/4/11 10:19 AM * @Author : 石冬冬-Seig Heil */ public class ToNumberTest { @SneakyThrows @Test public void test(){ String expression = "objects.toNumber('1',0)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build(); System.out.println(AviatorExecutor.executeBigDecimal(ctx)); } } ``` 输出: ```shell 1 ``` ### 3、数字转字符串:objects.toString(value,defaultValue) >数字转字符串,如果数字为空,则使用默认值作为返回值,objects.toString(value,defaultValue) 示例代码: ```java /** * @description: 数字转字符串,如果数字为空,则使用默认值作为返回值,objects.toString(value,defaultValue) * @Date : 2021/4/11 10:19 AM * @Author : 石冬冬-Seig Heil */ public class ToStringTest { @SneakyThrows @Test public void test(){ String expression = "objects.toString(1,'0')"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build(); System.out.println(AviatorExecutor.executeBigDecimal(ctx)); } } ``` 输出: ```shell 1 ``` # 高级特性 示例代码: ```java /** * @description: 基于Aviator测试类 * @Date : 2018/9/7 下午6:00 * @Author : 石冬冬-Seig Heil(shiyongxin2010@163.com) */ @Slf4j public class AviatorObjectTest { @Test public void object_instance(){ Teacher teacher = new Teacher(){{ setName("im"); setScore(20); }}; Student student = new Student(){{ setName("Jack"); setScore(22); }}; Map env = new HashMap(){{ put("teacher",teacher); put("student",student); }}; Object value = AviatorExecutor.execute(AviatorContext.builder().env(env).expression("student.name").build()); System.out.println(value); } @Data @NoArgsConstructor @AllArgsConstructor public class Colleague { private String name; private double score; } @Data @NoArgsConstructor public class Student extends Colleague { public Student(String name, double score) { super(name, score); } } @Data @NoArgsConstructor public class Teacher extends Colleague { } } ``` 输出: ```shell Jack ``` # 扩展阅读 [CSDN 介绍](https://blog.csdn.net/shichen2010/article/details/82630334) [掘金 介绍](https://juejin.cn/post/6949737576139849741/) [Aviator 源码地址](https://github.com/killme2008/aviator) [Aviator api 相关文档](https://www.yuque.com/boyan-avfmj/aviatorscript)