1.java里可以使用Spring的 Spel或者Google的Aviator

如果使用 Aviator 则添加以下依赖

      <dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>4.1.</version>
</dependency>

不过,推荐使用Spel

一般的规则匹配最终都会采用如下表达式来计算

如   ( {status} in "2,3" && ({level} in "p1,p2" || {times} in "1,9"))

但是存储在DB中一般采用 List<Model>的方式来存储,这样方便管理界面的前端的渲染 (当然也不排除直接存储表达式的,不过前端的渲染就有些难度了)

整个解析过程实现过程有以下几步

1.存储的List中的规则转换为表达式

1.1 增加括号

1.2 替换变量

1.3 构造spel表达式

1.4 连接下一个规则

2.计算表达式

代码如下:

import com.google.common.collect.ImmutableMap;

import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
static class RuleItem {
/**
* 左变量
*/
private String left; /**
* 比较表达式
*/
private ComparelOpration comparelOpration; /**
* 右变量或者常量
*/
private String right; /**
* 连接下一个表达式的逻辑运算符
*/
private LogicalOpration logicalOpra;
} @NoArgsConstructor
@AllArgsConstructor
@Data
static class RuleModel {
/**
* 规则列表
*/
private List<RuleItem> ruleItems; /**
* 左括号放在第几个Item之前
*/
private List<Integer> leftParenthesesIndex; /**
* 右括号放在第几个Item之后
*/
private List<Integer> rightParenthesesIndex;
} @Data
@AllArgsConstructor
@NoArgsConstructor
static class SpelResult {
private String express;
private StandardEvaluationContext context;
}

使用的两个连接器(比较连接和逻辑连接)

enum ComparelOpration {
In,
NotIn,
GreaterThan,
LessThan,
GreaterEqualThan,
LessEqualThan,
Equal,
NotEqual; public static boolean isDecimalCompareLogicalOpration(ComparelOpration opration) {
return opration.ordinal() == ComparelOpration.GreaterThan.ordinal()
|| opration.ordinal() == ComparelOpration.GreaterEqualThan.ordinal()
|| opration.ordinal() == ComparelOpration.LessEqualThan.ordinal()
|| opration.ordinal() == ComparelOpration.LessThan.ordinal();
} public static boolean isEqualLogicalOpration(ComparelOpration opration) {
return opration.ordinal() == ComparelOpration.Equal.ordinal()
|| opration.ordinal() == ComparelOpration.NotEqual.ordinal()
;
}
} enum LogicalOpration {
None,
And,
Or; static String toStr(LogicalOpration logicalOpration) {
return logicalOpration.ordinal() == LogicalOpration.None.ordinal()
? ""
: (logicalOpration.ordinal() == LogicalOpration.And.ordinal() ? "&&" : "||");
}
}

匹配工厂如下

 static class SpelMatchFactory {
private static final ExpressionParser parser = new SpelExpressionParser(); static SpelResult toSpelExpress(RuleModel model, Map<String, String> userFeature) {
List<RuleItem> ruleItemList = model.getRuleItems();
StringBuilder sb = new StringBuilder();
StandardEvaluationContext ctx = new StandardEvaluationContext();
for (int i = ; i < ruleItemList.size(); i++) {
RuleItem item = ruleItemList.get(i);
if (model.leftParenthesesIndex.contains(i)) {
sb.append("(");
} String listKey = "list" + i;
String valueKey = "item" + i; String subExpress = compute(item, listKey, valueKey);
sb.append(subExpress); String leftValue = item.getLeft();
if (leftValue.startsWith("{") && leftValue.endsWith("}")) {
leftValue = userFeature.get(leftValue.substring(, leftValue.length() - ));
} String rightValue = item.getRight();
if (rightValue.startsWith("{") && rightValue.endsWith("}")) {
rightValue = userFeature.get(rightValue.substring(, rightValue.length() - ));
} if (ComparelOpration.isDecimalCompareLogicalOpration(item.comparelOpration)) {
ctx.setVariable(listKey, Integer.parseInt(rightValue));
ctx.setVariable(valueKey, Integer.parseInt(leftValue));
} else if (ComparelOpration.isEqualLogicalOpration(item.comparelOpration)) {
ctx.setVariable(listKey, rightValue);
ctx.setVariable(valueKey, leftValue);
} else {
ctx.setVariable(listKey, Arrays.asList(rightValue.split(",")));
ctx.setVariable(valueKey, leftValue);
} if (model.rightParenthesesIndex.contains(i)) {
sb.append(")");
} if (item.logicalOpra.ordinal() != LogicalOpration.None.ordinal()) {
sb.append(LogicalOpration.toStr(item.getLogicalOpra()));
}
} return new SpelResult(sb.toString(), ctx);
} public static boolean compute(RuleModel model, Map<String, String> userFeature) {
SpelResult spelExpressResult = SpelMatchFactory.toSpelExpress(model, userFeature); Boolean execResult = parser.parseExpression(spelExpressResult.getExpress()).getValue(
spelExpressResult.getContext(),
Boolean.class);
return execResult;
} private static String compute(RuleItem matchItem, String listKey, String valueKey) {
if (matchItem.getComparelOpration().ordinal() == ComparelOpration.Equal.ordinal()) {
return "#" + listKey + ".equals(#" + valueKey + ")";
} if (matchItem.getComparelOpration().ordinal() == ComparelOpration.NotEqual.ordinal()) {
return "!#" + listKey + ".equals(#" + valueKey + ")";
} if (matchItem.getComparelOpration().ordinal() == ComparelOpration.In.ordinal()) {
return "#" + listKey + ".contains(#" + valueKey + ")";
}
if (matchItem.getComparelOpration().ordinal() == ComparelOpration.NotIn.ordinal()) {
return "!#" + listKey + ".contains(#" + valueKey + ")";
}
if (matchItem.getComparelOpration().ordinal() == ComparelOpration.GreaterEqualThan.ordinal()) {
return "#" + valueKey + ">=" + "#" + listKey;
} if (matchItem.getComparelOpration().ordinal() == ComparelOpration.LessEqualThan.ordinal()) {
return "#" + valueKey + "<=" + "#" + listKey;
} if (matchItem.getComparelOpration().ordinal() == ComparelOpration.GreaterThan.ordinal()) {
return "#" + valueKey + ">" + "#" + listKey;
} if (matchItem.getComparelOpration().ordinal() == ComparelOpration.LessThan.ordinal()) {
return "#" + valueKey + "<" + "#" + listKey;
} throw new IllegalArgumentException("不支持的逻辑运算类型");
}
}

最后 ,测试代码如下:

public static void main(String[] args) {
List<RuleItem> ruleItems = new ArrayList<>();
ruleItems.add(new RuleItem("{status}", ComparelOpration.In, "2,3", LogicalOpration.Or));
ruleItems.add(new RuleItem("{level}", ComparelOpration.In, "1,2", LogicalOpration.And));
ruleItems.add(new RuleItem("{hours}", ComparelOpration.GreaterEqualThan, "", LogicalOpration.And));
ruleItems.add(new RuleItem("{phone1}", ComparelOpration.Equal, "{phone2}", LogicalOpration.None));
RuleModel model = new RuleModel();
model.setRuleItems(ruleItems); //左括号在0的位置之前
model.setLeftParenthesesIndex(Arrays.asList());
//右括号在1的位置之后
model.setRightParenthesesIndex(Arrays.asList());
//以上表达式相当于 ({status} in '2,3' or {level} in '1,2') && {hours}>=48 && {phone1}=={phone2} //1. {phone1} != {phone2} ,结果为false
Map<String, String> userFeature1 = ImmutableMap.of("status", "", "level", "", "phone1",
"", "phone2", "", "hours", "");
boolean computeResult = SpelMatchFactory.compute(model, userFeature1);
System.out.println("userFeature1的匹配结果:" + computeResult); //2.{hours} < 48 ,结果为false
Map<String, String> userFeature2 = ImmutableMap.of("status", "", "level", "", "phone1",
"", "phone2", "", "hours", "");
computeResult = SpelMatchFactory.compute(model, userFeature2);
System.out.println("userFeature2的匹配结果:" + computeResult); //3. {status} 不在 2,3 中,但是 level 在 1,2中,结果为true
Map<String, String> userFeature3 = ImmutableMap.of("status", "", "level", "", "phone1",
"", "phone2", "", "hours", "");
computeResult = SpelMatchFactory.compute(model, userFeature3);
System.out.println("userFeature3的匹配结果:" + computeResult); //4. {status} 不在 2,3 中,且 level 不在 1,2中,结果为false
Map<String, String> userFeature4 = ImmutableMap.of("status", "", "level", "", "phone1",
"", "phone2", "", "hours", "");
computeResult = SpelMatchFactory.compute(model, userFeature4);
System.out.println("userFeature4的匹配结果:" + computeResult); //4.一切都匹配,返回true
Map<String, String> userFeature5 = ImmutableMap.of("status", "", "level", "", "phone1",
"", "phone2", "", "hours", "");
computeResult = SpelMatchFactory.compute(model, userFeature5);
System.out.println("userFeature5的匹配结果:" + computeResult);
}

输出结果为:

表达式:(#list0.contains(#item0)||#list1.contains(#item1))&&#item2>=#list2&&#list3.equals(#item3)
userFeature1的匹配结果:false
表达式:(#list0.contains(#item0)||#list1.contains(#item1))&&#item2>=#list2&&#list3.equals(#item3)
userFeature2的匹配结果:false
表达式:(#list0.contains(#item0)||#list1.contains(#item1))&&#item2>=#list2&&#list3.equals(#item3)
userFeature3的匹配结果:true
表达式:(#list0.contains(#item0)||#list1.contains(#item1))&&#item2>=#list2&&#list3.equals(#item3)
userFeature4的匹配结果:false
表达式:(#list0.contains(#item0)||#list1.contains(#item1))&&#item2>=#list2&&#list3.equals(#item3)
userFeature5的匹配结果:true

c#.net的代码如下

c#.net使用 ExpressionEvaluator.2.0.4.0 来做表达式的计算

通用的规则匹配算法(原创)(java+.net)的更多相关文章

  1. [原创]Java静态代码检查工具介绍

    [原创]Java静态代码检查工具介绍 一  什么是静态代码检查? 静态代码分析是指无需运行被测代码,仅通过分析或检查源程序的语法.结构.过程.接口等来检查程序的正确性,找出代码隐藏的错误和缺陷,如参数 ...

  2. 规则引擎集成接口(七)规则引擎调用Java类

    规则引擎调用Java类 通过myEclipse编写一个简单工程,其中方法是两数相加等到结果,既结果1=输入值1+输入值2.实现规则调用外部接口的方法有三种. 1:接口实例:在myEclipse中制作一 ...

  3. [原创]java WEB学习笔记95:Hibernate 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. [原创]Java性能优化权威指南读书思维导图

    [原创]Java性能优化权威指南读书思维导图 书名:Java性能优化权威指南 原书名:Java performance 作者: (美)Charlie Hunt    Binu John 译者: 柳飞 ...

  5. [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  6. [原创]java WEB学习笔记66:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  7. Fortify规则与CERT JAVA 安全编程规范的对照表

    Fortify规则与CERT JAVA 安全编程规范的对照表http://www.automationqa.com/forum.php?mod=viewthread&tid=4353& ...

  8. [原创]Java性能优化权威指南读书思维导图4

    [原创]Java性能优化权威指南读书思维导图4

  9. [原创]Java性能优化权威指南读书思维导图3

    [原创]Java性能优化权威指南读书思维导图3

随机推荐

  1. CSS3 Transform实例

    移动translate <!doctype html> <html> <head> <meta charset="utf-8"> & ...

  2. rocketmq架构设计

    # 架构设计 1 技术架构 RocketMQ架构上主要分为四部分,如上图所示: Producer:消息发布的角色,支持分布式集群方式部署.Producer通过MQ的负载均衡模块选择相应的Broker集 ...

  3. darknet-yolov3使用opencv3.4.8时,undefined reference 'imshow()'、'waitKey()'、'nameWindows()'

    解决办法:暴力卸载 卸载办法:进入到opencv3.4.8的安装目录下:make uninstall 然后重新安装了其他版本的,立马编译通过了.

  4. 数据库的特性与隔离级别和spring事务的传播机制和隔离级别

    首先数据库的特性就是 ACID: Atomicity 原子性:所有事务是一个整体,要么全部成功,要么失败 Consistency 一致性:在事务开始和结束前,要保持一致性状态 Isolation 隔离 ...

  5. 提示”The following modules are missing or built with a different engine version”

    一台机器使用自行编译版本引擎修改了工程后,另一台机器也使用自行编译版本引擎编辑该工程,有时会出现标题的提示 解决办法: 打开\Engine\Binaries\Win64\UE4Editor.modul ...

  6. QT | 第二章 基本语法

    ''' @Modify Time @Author ------------ ------- python基本语法 2019/10/26 8:16 laoalo ''' import functools ...

  7. Python 测评工具

    开源--Python测评工具 Github仓库 本次实验作业的测评工具仅使用Python语言编写. 程序思路是基于文本的快速匹配. 编译test.py运行 1.GUI界面 GUI界面使用了PyQt5完 ...

  8. Centos7开机自动启动服务和联网

    虚拟机设置选择NAT模式,默认情况下,Centos不是自动连接上网的,需要点击右上角,手动连接上网. 可以修改开机启动配置修改: 1. cd 到/etc/sysconfig/network-scrip ...

  9. scrapy--meta参数传递问题

    scrapy使用大坑---meta参数传递出现之重复问题 问题描述: 爬虫目标: 实现哔哩哔哩网站的视频信息爬取,只要的信息结构爬去顺序为**关键词的搜索结果,拿到第一页上某个视频的标题,url,和时 ...

  10. 测开之路六十三:UI测试平台之视图层

    实现效果,在页面时配置 后台执行 蓝图结构 视图代码 from flask import jsonifyfrom flask import requestfrom flask import Bluep ...