写点什么

基于规则引擎的多维度配置化适配系统

作者:五陵散人
  • 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);
}
复制代码


用户头像

五陵散人

关注

学以解惑 2017-12-31 加入

还未添加个人简介

评论

发布
暂无评论
基于规则引擎的多维度配置化适配系统_五陵散人_InfoQ写作社区