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. [python 学习]正则表达式

    re 模块函数re 模块函数和正则表达式对象的方法match(pattern,string,flags=0) 尝试使用带有可选的标记的正则表达式的模式来匹配字符串.如果匹配成功,就返回匹配对象:如果失 ...

  2. 关于KindEditor编辑器,word文档中的图文全选粘贴,在编辑器中不显示图片的问题

    图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码 目前限chrome浏览器使用,但是项目要求需要支持所有的浏览器,包括Windows和macOS系统.没有办 ...

  3. 如何添加筛选器 (Reporting Services)

    如果您希望在计算或显示时包含或排除特定值,可向数据集.数据区域或组添加筛选器.在运行时应用筛选器的顺序为:先对数据集,再对数据区域,最后对组,并按照组层次结构自上而下的顺序.在表.矩阵或列表中,对行组 ...

  4. Netty学习笔记(一)

    学习圣思园Netty笔记,个人理解 2.netty宏观理解-本节内容: 1.阶段性事件驱动,一个请求分为若干阶段处理,每个阶段根据情况合理分配线程去处理,各阶段间通信采用异步事件驱动方式. 2.net ...

  5. Log4d:Error:Could not instantiate class[com.mapgis.util.tools.JDBCExtAppender]

    https://blog.csdn.net/gikieng/article/details/47150567  https://blog.alswl.com/2018/03/sql-server-mi ...

  6. ICMP(Internet Control Message Protocol)网际控制报文协议初识

    ICMP是(Internet Control Message Protocol)Internet控制报文协议.它是TCP/IP协议族的一个子协议,用于在IP主机.路由器之间传递控制消息.控制消息是指网 ...

  7. 导入maven项目pom.xml首行报错missing artifact。。。

    解决方法: 在maven地址(如一般默认的地址C:\Users\Administrator\.m2\repository\)找到对应包名 加后缀名为.lastUpdated文件(如:ojdbc14.l ...

  8. 测开之路七十八:shell之函数和参数

    函数 function function_name(){    statement1    Statement2    ....    statementn} function_name $var1  ...

  9. openstack介绍及共享组件——消息队列rabbitmq

    一.云计算的前世今生 所有的新事物都不是突然冒出来的,都有前世和今生.云计算也是IT技术不断发展的产物. 要理解云计算,需要对IT系统架构的发展过程有所认识. 请看下 IT系统架构的发展到目前为止大致 ...

  10. Vagrant 入门 - box

    原文地址 Vagrant 使用基础镜像来快速克隆虚拟机,而不是从头开始构建虚拟机.这些基础镜像在 Vagrant 中被称为"box",并且指定用于 Vagrant 环境的 box ...