基于规则引擎的多维度配置化适配系统
作者:五陵散人
- 2024-02-21 北京
本文字数:3461 字
阅读完需:约 11 分钟

在工作中常遇到通过某几个可选维度组合匹配出主体的场景,在这里提供一套通用实现,生产在用的灵活适配抽象
设计思想为:
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);
}
/** * 子项匹配 */@Servicepublic 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
五陵散人
关注
学以解惑 2017-12-31 加入
还未添加个人简介







评论