一个轻量级的规则引擎、搜索引擎,让条件匹配简单、优雅。
https://gitcode.cosmoplat.com/15011240224/rule-engine-starter
Rule-Engine-Starter 是一个轻量级规则引擎,V1.0.0主要解决条件匹配问题。比如飞书文档,每个文档都可以设置访问权限,可以限制哪些人、哪些部门可以访问、是否对互联网用户公开等等,这些条件可以看成每个文档设置的访问规则,一个文档可以设置多个规则。
校验一个用户是否能访问目标文档,只需要校验规则中的条件,可以使用SPEL等表达式来实现;但是如果想获取一个用户有访问权限的所有文档,如果再用SPEL实现岂不是需要遍历所有文档的所有规则,这种方案无疑是低效的。因此自研 Rule-Engine-Starter 解决这个问题,只需要将用户的属性作为条件输入给规则引擎,规则引擎会快速返回所有匹配的规则:
Rule-Engine-Starter 通过拉平条件和MySQL的B+Tree索引实现快速匹配。
访问地址:https://gitcode.cosmoplat.com/15011240224/rule-engine-demo
修改数据库配置后,可本地执行com.cosmoplat.rule.RuleTest。
MySQL初始化,执行src/main/sql/init.sql
POM引入依赖和卡奥斯仓库
<dependency>
<groupId>com.cosmoplat.rule</groupId>
<artifactId>rule-engine-starter</artifactId>
<version>1.0.0</version>
</dependency>
<repository>
<id>maven-public</id>
<name>maven-public</name>
<url>http://nexus.cosmoplat.com/repository/maven-public/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
修改配置文件
spring:
datasource:
url: jdbc:mysql://xxx.xxx.xxx.xxx:xxxxx/库名
username: 用户名
password: 密码
driver-class-name: com.mysql.cj.jdbc.Driver
# 启用规则引擎
rule:
engine:
enabled: true
创建维度
Dimension dimension = Dimension.builder().namespaceId(NAMESPACE_ID)
.code(dimensionEnum.getCode())
.description(dimensionEnum.getName()).build();
ruleEngineService.createDimensions(Collections.singletonList(dimension));
创建分类
List<String> dimension = Lists.newArrayList(DimensionEnum.WORK_NO.getCode(),
DimensionEnum.DEPT_NO.getCode());
Type ruleType = Type.builder().code(DOC_READ_RULE_TYPE_CODE).description("文档阅读规则")
.namespaceId(NAMESPACE_ID).dimensionCodes(dimension).build();
ruleEngineService.createTypes(Lists.newArrayList(ruleType));
添加规则
String docId1= "11111";
String docId2= "22222";
String docId3= "33333";
// 允许体验云和海云智造的员工阅读文档1
createDocReadRule(docId1, Lists.newArrayList(ALL), Lists.newArrayList("tiYanYun", "haiyunzhizao"));
// 只允许工号22038425阅读文档2
createDocReadRule(docId2, Lists.newArrayList("22038425"), Lists.newArrayList(ALL));
// 只允许工号77889998阅读文档3
createDocReadRule(docId3, Lists.newArrayList("77889998"), Lists.newArrayList(ALL));
private void createDocReadRule(String docId, List<String> workNos, List<String> deptNos) throws RuleConflictException {
Package rule = new Package();
rule.setNamespaceId(NAMESPACE_ID);
rule.setTypeCode(DOC_READ_RULE_TYPE_CODE);
rule.setName("文档阅读规则");
rule.setCreateInfo();
// 匹配结果
rule.setConfigInfo(docId);
// 规则条件
Map<String, List<String>> searchKeyMap = Maps.newHashMap();
searchKeyMap.put(DimensionEnum.WORK_NO.getCode(), workNos);
searchKeyMap.put(DimensionEnum.DEPT_NO.getCode(), deptNos);
ruleEngineService.createRule(rule, searchKeyMap);
}
规则匹配
// 规则匹配,返回体验云员工22038425能访问的文档
Map<String, List<String>> searchAndSortKeyMap = Maps.newHashMap();
searchAndSortKeyMap.put(DimensionEnum.WORK_NO.getCode(), Lists.newArrayList( "22038425", ALL));
searchAndSortKeyMap.put(DimensionEnum.DEPT_NO.getCode(), Lists.newArrayList("tiYanYun", ALL));
List<MatchRuleResult<String>> ret = ruleEngineService.matchRule(NAMESPACE_ID,
DOC_READ_RULE_TYPE_CODE, searchAndSortKeyMap, null);
List<String> docIds = ret.stream().map(MatchRuleResult::getResult).collect(toList());
Assert.isTrue(docIds.contains(docId1), "文档1不能阅读");
Assert.isTrue(docIds.contains(docId2), "文档2不能阅读");
Assert.isTrue(!docIds.contains(docId3), "文档3能阅读");
如果您觉得有用,麻烦您按照链接支持下:链接