基于规则引擎的多维度配置化适配系统
作者:五陵散人
- 2024-02-21 北京
本文字数:3461 字
阅读完需:约 11 分钟
![基于规则引擎的多维度配置化适配系统](https://static001.geekbang.org/infoq/40/40a2a08db1454d4aff4660c4dc2897d4.png)
在工作中常遇到通过某几个可选维度组合匹配出主体的场景,在这里提供一套通用实现,生产在用的灵活适配抽象
设计思想为:
1、定义决策原子项- 如:部门、标签等, 针对原子项提供 scope 可选决策语法
2、由 1 可选配置出多个决策子项 item,并组合成逻辑表达式 rule_formula
3、借用规则引擎逻辑表达式执行能力执行 rule_formula,获取决策结果
核心代码如下
数据库:
CREATE TABLE `adapter_rule` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`meta_code` varchar(64) NOT NULL DEFAULT '' COMMENT '业务类别编码',
`meta_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '业务类型',
`subject_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '适用对象id',
`subject_type` varchar(32) NOT NULL DEFAULT '' COMMENT '配置元类型:标示 配置、模版或其他',
`rule_formula` varchar(256) NOT NULL DEFAULT '' COMMENT '逻辑公式',
`valid_time` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '生效时间',
`expiry_time` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '过期时间',
`del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
`creator` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updator` varchar(32) NOT NULL DEFAULT '' COMMENT '更新人',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=154 DEFAULT CHARSET=utf8mb4 COMMENT='适配-规则';
CREATE TABLE `adapter_rule_item` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`rule_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '适用对象id',
`item_seq` varchar(32) NOT NULL DEFAULT '' COMMENT '顺序标示',
`adapter_item_type` varchar(32) NOT NULL DEFAULT '' COMMENT '元类型',
`adapter_item_value` text COMMENT '元值',
`scope_type` varchar(32) NOT NULL DEFAULT '' COMMENT '适配类型',
`valid_time` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '生效时间',
`expiry_time` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '过期时间',
`del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
`creator` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updator` varchar(32) NOT NULL DEFAULT '' COMMENT '更新人',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=338 DEFAULT CHARSET=utf8mb4 COMMENT='适配规则-子项';
复制代码
/**
* 决策匹配方法
*/
public class AdapterApiService {
@Resource
AdapterRuleMapper adapterRuleMapper;
@Resource
AdapterRuleItemMapper adapterRuleItemMapper;
@Resource
AdapterItemServiceFactory adapterItemServiceFactory;
@Resource
BaseConfigMapper baseConfigMapper;
@Resource
QlExpressRunner runner;
/**
* 匹配主体方法,返回主体Id集合
*
* @param req
* @param subjectType
* @return
*/
public List<Long> matchSubjects(AdapterReq req, AdapterSubjectType subjectType) {
AdapterRuleCriteria criteria = new AdapterRuleCriteria();
AdapterRuleCriteria.Criteria criteria1 =
criteria.createCriteria().andSubjectTypeEqualTo(subjectType.getCode()).andDelEqualTo(Boolean.FALSE);
if (StringUtils.isNotBlank(req.getMetaCode())) {
criteria1.andMetaCodeEqualTo(req.getMetaCode());
}
List<AdapterRule> rules = adapterRuleMapper.selectByExample(criteria);
if (CollectionUtils.isEmpty(rules)) {
return Collections.emptyList();
}
return rules.stream().filter(adapterRule -> isCompileRule(adapterRule.getId(), req))
.map(AdapterRule::getSubjectId).collect(Collectors.toList());
}
private String getAdapterValue(AdapterReq req, String itemType) {
AdapterItemType adapterItemType = AdapterItemType.valueOfCode(itemType);
if (Objects.isNull(adapterItemType)) {
return null;
}
switch (adapterItemType) {
case BACK_FIELD1:
return req.getBackField1();
case BACK_FIELD2:
return req.getBackField2();
default: return null;
}
}
private boolean isCompileRule(Long ruleId, AdapterReq req) {
AdapterRule rule = adapterRuleMapper.selectByPrimaryKey(ruleId);
if(StringUtils.isBlank(rule.getRuleFormula())){
return true;
}
List<AdapterRuleItem> items = listItem(rule.getId());
Map<String,
Object> params = items.stream()
.collect(Collectors.toMap(AdapterRuleItem::getItemSeq,
ruleItem -> adapterItemServiceFactory
.checkAdapterItem(getAdapterValue(req, ruleItem.getAdapterItemType()), ruleItem),
(o1, o2) -> o1));
return runner.boolExecute(rule.getRuleFormula(), params);
}
private List<AdapterRuleItem> listItem(Long ruleId) {
AdapterRuleItemCriteria criteria = new AdapterRuleItemCriteria();
criteria.createCriteria().andRuleIdEqualTo(ruleId);
return adapterRuleItemMapper.selectByExampleWithBLOBs(criteria);
}
}
/**
* 抽象决策子项
*/
public abstract class AbstractAdapterItemService {
boolean checkAdapter(String value, List<String> adapterValues, AdapterScopeType scopeType) {
switch (scopeType) {
case EQ:
return isEq(value, adapterValues);
case NOT_EQ:
return isNotEq(value, adapterValues);
case EXIST_IN:
return isExistIn(value, adapterValues);
case NOT_EXIST_IN:
return isNotExistIn(value, adapterValues);
default: return false;
}
}
abstract boolean isEq(String value, List<String> adapterValues);
abstract boolean isNotEq(String value, List<String> adapterValues);
abstract boolean isExistIn(String value, List<String> adapterValues);
abstract boolean isNotExistIn(String value, List<String> adapterValues);
}
/**
* 子项匹配
*/
@Service
public class AdapterItemServiceFactory {
@Resource
Map<String, AbstractAdapterItemService> abstractAdapterItemServiceMap;
public boolean checkAdapterItem(String value, AdapterRuleItem ruleItem) {
AdapterItemType itemType = AdapterItemType.valueOfCode(ruleItem.getAdapterItemType());
if (Objects.isNull(itemType)) {
return false;
}
AdapterScopeType scopeType = AdapterScopeType.valueOfCode(ruleItem.getScopeType());
if (Objects.isNull(scopeType)) {
return false;
}
List<String> adapterValues = JSON.parseArray(ruleItem.getAdapterItemValue(), String.class);
return abstractAdapterItemServiceMap.get(itemType.getAdapterService()).checkAdapter(value, adapterValues,
scopeType);
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 5
![用户头像](http://static001.geekbang.org/account/avatar/00/0f/e6/a4/791d0f5e.jpg?x-oss-process=image/resize,w_200,h_200)
五陵散人
关注
学以解惑 2017-12-31 加入
还未添加个人简介
评论