提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、模板引擎的选择?
- 二、什么是JEXL规则引擎?
- 优点
- 缺点
- 三、其他规则引擎
- 四、示例
- 1.引入依赖
- 2.方法示例
- 3、代码解释
- 4、效果
- ![import java.util.*;](https://img-blog.csdnimg.cn/direct/560fb9361ba14b6ab72d42d2f49922ae.png)
- 总结
前言
最近产品提了一个需求,通过前端页面点击生成表达式。来,请看大屏幕。。。错了,请看需求原型
通过前端按钮点击生成在公式展示栏的表达式,这里先不计较公式正确与否,就默认生成的公式一定是正确的,而生成的公式会作为传参传递到后端接口。
一、模板引擎的选择?
这里的公式仅用于匹配通过接口传入的类或者参数是否匹配,所以,这里不需要引入过重的表达式引擎,最终选择了Apache Jexl规则引擎
二、什么是JEXL规则引擎?
Apache Jexl(以下简称Jexl)是一种基于Java的表达式语言,用于在Java应用程序中计算和操作值。它可以用作规则引擎的一部分,但不是专门为此而设计的。与其他专为规则引擎而设计的引擎相比,Jexl具有以下优点和缺点。
优点
- 易于学习和使用:Jexl的语法简单直观,易于理解和使用。它的API也很容易上手,对于新手来说非常友好。
- 灵活性高:Jexl具有很高的灵活性,允许用户自定义函数、变量和操作符等,以满足各种需求。
- 与Java集成良好:Jexl是基于Java的,因此可以非常方便地与Java应用程序集成。它可以轻松地与Java对象交互,并使用Java的反射机制来访问类和方法。
缺点
- 不是专为规则引擎设计:尽管可以将Jexl用作规则引擎的一部分,但它并不是专为此而设计的。因此,在处理复杂的业务规则时,可能会存在一些限制和不足。
- 缺少规则管理功能:Jexl本身只提供了表达式解析和计算功能,如果需要更复杂的规则管理功能,例如规则编辑、版本控制和审批流程等,需要自行实现或使用其他规则引擎。
- 性能较差:由于Jexl是解释型语言,因此它的性能相对较低。如果需要处理大量数据或高并发场景,则可能需要考虑使用其他规则引擎。
三、其他规则引擎
市面上除了Jexl之外,还有许多其他的规则引擎可供选择,这里简单介绍一些在市面上比较常见的规则引擎:
-
Drools:Drools 是一个开源规则引擎,它允许开发人员将业务逻辑与应用程序代码分离。它使用基于规则的语言(DRL)来表示和执行规则,并提供从多个数据源中自动推断输出结果的能力。
-
Jess:Jess 是另一个基于规则的编程语言,它被设计为与 Java 集成。它可以用于构建专家系统、商业决策支持系统等。Jess 还包括一些高级特性,例如模式匹配和对象操作。
-
Easy Rules:Easy Rules 是一个轻量级的规则引擎框架,它允许开发人员在应用程序中定义和执行简单的规则。它支持注解和 Lambda 表达式,并提供了与 Spring 和 CDI 的集成。
-
Apache Spark MLlib:Apache Spark MLlib 是一个大规模机器学习库,它包含了许多算法和工具用于分类、回归、聚类和协同过滤等任务。它还提供了一组规则引擎,用于处理流数据和批数据。
-
NRules:NRules 是一个 .NET 规则引擎,它允许开发人员定义和执行规则。它使用 C# 语言编写,并提供了与 LINQ 的集成,使得开发人员可以使用类似 SQL 的查询来过滤数据
四、示例
1.引入依赖
在 pom.xml 文件中添加以下依赖项:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl3</artifactId>
<version>3.2</version>
</dependency>
2.方法示例
代码如下(示例):
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.MapContext;
import java.util.*;
public static void main(String[] args) {
// 中文表达式
String expStr = "(长<=120 且 宽<=60 且 高<=60 且 围长<=300 且 容积>150 且 重量<=31.5)" +
" 或 (长>=121 且 长<=175 且 宽<=60 且 高<=60 且 围长<=300 且 容积<=150 且 重量<=31.5)" +
" 或 (长<=120 且 宽>70 且 高<=60 且 围长<=300 且 容积<=150 且 重量<=31.5)";
// Step 1:将中文且、或替换成java中的&&、||
String replaceAfterStr = expStr.replaceAll("且", "&&")
.replaceAll("或", "||")
.replaceAll("围长", "perimeter")
.replaceAll("容积", "volume")
.replaceAll("重量", "weight")
.replaceAll("长", "length")
.replaceAll("宽", "width")
.replaceAll("高", "height");
System.out.println("将中文且、或替换后的表达式:\n" + replaceAfterStr);
// Step 2: 按照特定格式切割替换后表达式:"||"
String[] split = replaceAfterStr.split("\\|\\|");
List<String> splitExpStr = Arrays.asList(split);
System.out.println("切割后的表达式:\n" + String.join("\n", splitExpStr));
// Step 3:校验表达式是否符合
JexlEngine engine = new JexlEngine();
JexlContext context = new MapContext();
context.set("length", 119);
context.set("width", 59);
context.set("height", 59);
context.set("perimeter", 299);
context.set("volume", 151);
context.set("weight", 31.5);
for (String s : splitExpStr) {
Object evaluate = engine.getEngine().createExpression(s).evaluate(context);
if (Boolean.FALSE.equals(evaluate)) {
System.out.println("context不符合当前表达式:" + s);
} else {
System.out.println("context符合当前表达式:" + s);
}
}
}
3、代码解释
这个方法的功能是通过解析和校验一个给定的中文表达式,来判断某些商品是否符合特定条件。具体步骤如下:
- 将中文的“且”和“或”替换为Java中的“&&”和“||”,并将其他中文关键词替换为对应的英文关键词。
- 将替换后的表达式按照“||”进行分割,得到多个子表达式。
- 创建一个JexlEngine对象用于解析表达式,并创建一个JexlContext对象用于设置待校验的上下文信息(长度、宽度、高度、围长、容积、重量)。
- 遍历分割后的子表达式,使用JexlEngine对每个子表达式进行求值,并根据求值结果判断上下文是否符合该子表达式。
- 最终输出符合或不符合子表达式的上下文信息。
4、效果
这个是运行结果
总结
这里说个问题,JEXL对于单表达式(例如:长<=120)组成的组合表达式是可以解析的,但是,如果你的单表达式写成(例:121<=长<=175)组成的组合表达式,Jexl是没办法解析的,所以,这种单表达式(例:121<=长<=175)你需要转换成(长>=121 且 长<=175),这样Jexl就会解析没问题
表达式:21<=长<=175解析报错信息
将中文且、或替换后的表达式:
(length<=120 && width<=60 && height<=60 && perimeter<=300 && volume>150 && weight<=31.5) || (121<=length<=175 && width<=60 && height<=60 && perimeter<=300 && volume<=150 && weight<=31.5) || (length<=120 && width>70 && height<=60 && perimeter<=300 && volume<=150 && weight<=31.5)
切割后的表达式:
(length<=120 && width<=60 && height<=60 && perimeter<=300 && volume>150 && weight<=31.5)
(121<=length<=175 && width<=60 && height<=60 && perimeter<=300 && volume<=150 && weight<=31.5)
(length<=120 && width>70 && height<=60 && perimeter<=300 && volume<=150 && weight<=31.5)
context符合当前表达式:(length<=120 && width<=60 && height<=60 && perimeter<=300 && volume>150 && weight<=31.5)
Exception in thread "main" org.apache.commons.jexl3.JexlException$Parsing: com.smallrig.logistics.service.impl.LogisticsFreightOverrunRuleServiceImpl.main:257@1:13 parsing error in '<='
at org.apache.commons.jexl3.JexlEngine.createExpression(JexlEngine.java:335)
at com.smallrig.logistics.service.impl.LogisticsFreightOverrunRuleServiceImpl.main(LogisticsFreightOverrunRuleServiceImpl.java:257)
原创不易,望一键三连 (^ _ ^)