业务自定义逻辑适配能力设计

在工作中常遇到通过某几个可选维度组合匹配出主体的场景,在这里提供一套通用实现,生产在用的灵活适配抽象

设计思想为:

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);

    }

通过二级决策达到自定义维度适配能力,目前已支撑多业务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值