JEXL表达式引擎
源码地址:https://github.com/TomFrost/Jexl
官方文档:https://commons.apache.org/proper/commons-jexl/reference/syntax.html
简介
JEXL(Java Expression Language)是一种基于Java的表达式语言,可以在Java程序中使用它来计算表达式的值。它支持常见的算数运算、逻辑运算、比较运算、条件运算变量和函数、数组与集合、正则表达式等。可以帮助开发人员在Java程序中使用表达式来计算值并实现更灵活和复杂的操作。
常用的表达式语法
一元运算符
Operation | Symbol |
---|---|
Negate | ! |
二元运算符
Operation | Symbol |
---|---|
Add, Concat | + |
Subtract | - |
Multiply | * |
Divide | / |
Divide and floor | // |
Modulus | % |
Power of | ^ |
Logical AND | && |
Logical OR | || |
比较
Comparison | Symbol |
---|---|
Equal | == |
Not equal | != |
Greater than | > |
Greater than or equal | >= |
Less than | < |
Less than or equal | <= |
Element in array or string | in |
关于in
的注释
in
运算符可用于检查子字符串: "Cad" in "Ron Cadillac"
,也可用于检查数组元素: "coarse" in ['fine', 'medium', 'coarse']
。但是,该==
运算符在幕后用于搜索数组,因此不应将其与对象数组一起使用。以下表达式返回 false:{a: 'b'} in [{a: 'b'}]
。
三元运算符
条件表达式检查第一个段的计算结果是否为真值。如果是,则评估随后的段。否则,替代方案是。如果后续部分丢失,则将使用测试结果本身。
Expression | Result |
---|---|
“” ? “Full” : “Empty” | Empty |
“foo” in “foobar” ? “Yes” : “No” | Yes |
{agent: “Archer”}.agent ?: “Kane” | Archer |
原生类型
Type | Examples |
---|---|
Booleans | true , false |
Strings | “Hello “user””, ‘Hey there!’ |
Numerics | 6, -7.2, 5, -3.14159 |
Objects | {hello: “world!”} |
Arrays | [‘hello’, ‘world!’] |
括号
括号的作用正如我们所期望的那样:
表达 | 结果 |
---|---|
(83 + 1) / 2 | 42 |
1 < 3 && (4 > 2 || 2 > 4) | 真的 |
其他
JEXL还支持类似Java语言的语法,比如在字符串前面加上$
变量引用
- Hello,${name}
可以使用.
来调用对象的方法和属性
- object.property
可以支持数组和集合,可以使用[]
访问元素
- list[index]。
另外,JEXL还支持正则表达式,可以使用~=
和~!
进行匹配和不匹配的操作
- string~=/pattern/
- string!=/pattern/
在代码中集成JEXL
pom依赖
<!-- Jexl表达式引擎依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl3</artifactId>
<version>3.2.1</version>
</dependency>
自定义工具类
package com.hand.hap.core.util;
import org.apache.commons.jexl3.*;
import java.math.BigDecimal;
import java.util.Map;
/**
* JexlExpression util
*
* @author linwy
*/
public class JexlExpressionUtil {
private static final JexlContext INSTANCE;
static {
// Initialize the INSTANCE JexlContext with the BigDecimal variable
MapContext mapContext = new MapContext();
// BigDecimal类方法支持 如果需要其他类方法的支持 引入方式同下
mapContext.set("BigDecimal", BigDecimal.class);
INSTANCE = mapContext;
}
public static synchronized JexlContext getInstance() {
return INSTANCE;
}
private JexlExpressionUtil(){
}
/**
* 将字符串公式转换成可执行代码
*
* @param formula 计算公式
* @param param 参数Map<参数名, 参数值>
* @return 计算结果
*/
public static BigDecimal convertToCode(String formula, Map<String, BigDecimal> param) {
JexlExpression expression = new JexlBuilder().create().createExpression(formula);
JexlContext jc = JexlExpressionUtil.getInstance();
// 转换参数
param.forEach((k, v) -> jc.set(k, v != null ? v : BigDecimal.ZERO));
// 执行计算
Object obj = expression.evaluate(jc);
BigDecimal result = obj == null ? BigDecimal.ZERO : new BigDecimal(obj.toString());
return result.setScale(2, RoundingMode.HALF_UP);
}
}
测试demo
public static void main(String[] args){
String calculateRule = "amount-(amount/(1+taxRate)*taxRate).setScale(2, BigDecimal.ROUND_HALF_UP)";
Map<String, BigDecimal> param = new HashMap<>();
param.put("amount", new BigDecimal("1230"));
param.put("taxRate", new BigDecimal("0.06"));
System.out.println(JexlExpressionUtil.convertToCode(calculateRule,param));
}
输出结果
1160.38
Process finished with exit code 0