easy-rules规则引擎最佳落地实践
创始人
2024-04-13 03:47:36
0

写作目的

这是一个头部互联网公司中的一个问题。因为有很多业务产品线,作为一个新人或者团队外的人员是很难区分不同的产品线之间的区别的,因此需要给某个产品线一个描述。但是随着业务的发展,产品线下可能又根据某个字段进一步划分,那么子产品线就是父产品线 + 字段 去区分。后面根据两个字段划分…。人都麻了。因为不同的组合有不同的链路。因此针对一个产品,我们要提供针对这个产品的具体规则描述,从而减少答疑。

接下来以 餐厅、套餐、菜品进行举例。
在这里插入图片描述

比如你想加盟XX火锅店,你需要像区域经理申请开店。
经理说 你开一个 牛肉火锅(prouductId = 1) 自营店(type =1)。
经理让李四 开一个 羊肉火锅(prouductId = 2) 自营店(type =1)。
经理让王五 开一个 羊肉火锅(prouductId = 2) 旗舰店(type =2)。
。。。。。

那么针对不同的场景(product && type),需要走的审批流程不一样。

  • 牛肉火锅(prouductId = 1) 自营店(type =1)
    开店规则:需要审批菜品,审批通过后套餐自动审批通过,套餐都审批通过后 餐厅自动审批通过,审批通过后即可运营。
    在这里插入图片描述

  • 羊肉火锅(prouductId = 2) 自营店(type =1)
    开店规则:只审批餐厅,审批通过后即可运营。
    在这里插入图片描述

  • 羊肉火锅(prouductId = 2) 旗舰店(type =2)
    开店规则:
    只审批餐厅,审批通过后即可运营。
    但是菜品也可以申请,审批通过后套餐自动审批通过,审批通过的套餐可以每天赠送100份。
    在这里插入图片描述

那么问题来了,如果你作为审批流程客服工作人员,当一个开店的审批工单来了以后,总有人问你为什么他的工单还在审批中,你怎么办呢?最好的方式就是你告诉他你的工单是菜品、套餐、餐厅没审批通过,请找相关同学咨询。

源码下载Gitee (亲测可用,真实有效)

gitee代码下载地址
启动方法和工程目录如下
在这里插入图片描述

java规则引擎easy-rules简单使用

以上面的牛肉火锅(prouductId = 1) 自营店(type =1) 为例

正常情况下可以写代码判断

      int productId = 1;int type = 1;if(productId == 1 && type ==1){System.out.println("牛肉火锅自营店。请从【餐品】开始进行向上申请");}

如果这样的规则能通过配置的方式进行实现,那简直无敌。

下面先写一个demo版本

    Canteen canteen = new Canteen().setProductId(1).setType(1);// define rules 定义规则Rule canteenRule =new RuleBuilder().name("牛肉火锅自营店") // 规则名称.description("productId = 1 && type =1 。文案:牛肉火锅自营店。请从【餐品】开始进行向上申请") // 规则描述.when(facts -> facts.get("productId").equals(1) && facts.get("type").equals(1)) // 规则条件.then(facts -> System.out.println("牛肉火锅自营店。请从【餐品】开始进行向上申请")) // 命中规则后的操作.build();// 定义规则集合Rules rules = new Rules();rules.register(canteenRule);// fire rules on known facts  创建执行引擎RulesEngine rulesEngine = new DefaultRulesEngine();// define facts 定义需要验证的参数Facts facts = new Facts();facts.put("productId", canteen.getProductId());facts.put("type", canteen.getType());// 进行规则校验rulesEngine.fire(rules, facts);

看打印结果
在这里插入图片描述

上面还存在以下问题

  • 规则还是手动通过代码定义的,如果通过配置文件定义那就最好了
  • 命中的规则后结果只能打印,我想获取规则的一些信息比如规则描述description应该怎么办

最佳落地实践

注意:部分代码没有展示,可以去仓库查看全部源码

通过配置文件定义规则 canteenRule.yml

---
name: "牛肉火锅自营店"
description: "prouductId = 1 && type = 1 "
condition: "canteen.productId==1&&canteen.type==1"
priority: 1
actions:- "System.out.println(1);"
---
name: "牛肉火锅旗舰店"
description: "prouductId = 1 && type = 2"
condition: "canteen.productId == 2 && canteen.type == 1"
priority: 2
actions:- "System.out.println(2);"

创建规则引擎工厂类RulesEngineFactory

目的:上述例子中,规则引擎不可能只为 餐厅 服务,还需要为 套餐、菜品服务。因此肯定是有不同的规则和规则引擎的。因此这里需要一个工厂。

package com.example.demo.rulesEngine.listener;import com.example.demo.rulesEngine.common.RuleCommonInterface;
import lombok.Data;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.support.YamlRuleDefinitionReader;import java.io.FileReader;/*** @author chaird* @create 2022-11-26 13:02*/
public class RulesEngineFactory {/*** 构建食堂规则。特殊** @return*/public static BizRuleEngine buildRuleEngine4Canteen() {String entityType = "canteen";String reulePath ="D:\\work\\IntelliJ IDEA 2018.2.4Workspace\\Demooo\\springboot-easu-rules-demo\\src\\main\\resources\\canteenRule.yml";return buildRuleEngine(entityType, reulePath);}// 可以有N个public static BizRuleEngine buildRuleEngine4MealGroup() {String entityType = "mealGroup";String reulePath = "xxxxx";// return buildRuleEngine(entityType, reulePath);return null;}private static BizRuleEngine buildRuleEngine(String entityType, String rulePath) {BizRuleEngine bizRuleEngine = new BizRuleEngine(entityType, rulePath);return bizRuleEngine;}@Datapublic static class BizRuleEngine {private String entityType;private MVELRuleFactory ruleFactory;private DefaultRulesEngine rulesEngine;private Rules rules;public BizRuleEngine(String entityType, String rulePath) {try {this.entityType = entityType;ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());rules = ruleFactory.createRules(new FileReader(rulePath));rulesEngine = new DefaultRulesEngine();rulesEngine.registerRuleListener(new YmlRulesListener(entityType));} catch (Exception e) {e.printStackTrace();}}public void fire(RuleCommonInterface input) {Facts facts = new Facts();facts.put(entityType, input);rulesEngine.fire(rules, facts);}}
}

这样我就可以针对餐厅这样一个特殊的实例创建自己独有的规则引擎

RulesEngineFactory.BizRuleEngine canteenRuleEngine = RulesEngineFactory.buildRuleEngine4Canteen();Canteen canteen = new Canteen().setName("西餐厅").setProductId(1).setType(1);
//todo

创建监听器YmlRulesListener

目的:其实有有的时候命中规则后我们要做一些事情,比如取到规则的一些描述等信息好组织文案

package com.example.demo.rulesEngine.listener;import com.example.demo.rulesEngine.common.RuleCommonInterface;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.RuleListener;/*** @author chaird* @create 2022-11-26 1:54*/
public class YmlRulesListener implements RuleListener {private String entityType ;@Overridepublic boolean beforeEvaluate(Rule rule, Facts facts) {return true;}@Overridepublic void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) {}@Overridepublic void beforeExecute(Rule rule, Facts facts) {}@Overridepublic void onSuccess(Rule rule, Facts facts) {//获取需要验证的对象,比如 【餐厅、套餐、菜品 implement RuleCommonInterface】RuleCommonInterface ruleCommon = facts.get(entityType);//把规则信息进行一个赋值ruleCommon.setDescription(rule.getDescription());}@Overridepublic void onFailure(Rule rule, Facts facts, Exception exception) {}public YmlRulesListener(){}public YmlRulesListener(String entityType) {this.entityType = entityType;}
}

可以直接通过规则action进行赋值

有的时候会有转换操作,针对本文提出的案例。我想让productId =2的时候和productId = 9527的后续流程一样,可以在actions中使用下面的命令

name: "牛肉火锅旗舰店"
description: "prouductId = 1 && type = 2"
condition: "canteen.productId == 2 && canteen.type == 1"
priority: 2
actions:- "canteen.productId = 9527;"

总结

  • 这样的一个工具案例其实写文章还挺难组织思路的,代码贴的多显示不出核心思路。代码贴的少大家又看不太懂。
  • 百度了一些文章,其实有些都没有跑通,所以自己写一篇文章。
  • 其实单场景下对一个实体类进行规则校验那很简单,本文通过工厂模式设计的是对多实体类进行规则校验。总体还是有难度的。

参考

https://www.cnblogs.com/rongfengliang/p/12686702.html
https://www.jianshu.com/p/3bc5773a1545

相关内容

热门资讯

窃取个人信息,卖给境外犯罪组织... 2025年12月31日,南都N视频记者从云南公安机关网安部门获悉,该部门近期成功斩断一条利用黑客技术...
原创 少... 近些年来,一些司法工作者表现得很没担当,总是把西方的司法思想看得像是不可更改的圣经,尤其是在未成年犯...
杭州靠谱公司律师推荐:程明律师... 在商业活动与个人生活中,法律问题无处不在。无论是企业面临商业诋毁、合同违约纠纷,还是个人在婚姻家事、...
靠谱公司律师推荐:浙江同济律师... 在商业活动日益频繁、法律关系愈发复杂的今天,公司面临的法律风险也越来越多,拥有一位靠谱的公司律师成为...
徐工取得法规眼点定位及视野测量... 国家知识产权局信息显示,江苏徐工工程机械研究院有限公司取得一项名为“一种法规眼点定位及视野测量装置及...
靠谱税务律师哪家好?程晓凤律师 在企业经营和个人财富管理过程中,税务问题一直是备受关注的核心。税务法规复杂多变,税务案件处理不当可能...
税务律师服务推荐:靠谱口碑之选... 在企业经营和个人财富管理的过程中,税务问题一直是核心痛点。税务法规复杂多变,税务风险如影随形,因此,...
擅长强制执行律师哪家口碑好?周... 在法律纠纷中,胜诉只是第一步,真正实现权益落地才是关键。而强制执行环节往往困难重重,让许多当事人头疼...
赣锋锂业被移送审查起诉 子公司... 来源:中国经济网 赣锋锂业(002460.SZ)近日发布关于收到宜春市公安局移送起诉告知书的公告。赣...