# rule_engine **Repository Path**: ahaow/rule_engine ## Basic Information - **Project Name**: rule_engine - **Description**: Drule业务规则可视化平台。基于Drools 封装的业务规则可视化平台,用于简化规则开发,将规则表达式、规则条件和规则动作等进行可视化展示,并降低学习和开发成本,帮助用户快速创建业务规则。并在其基础之上,拓展更多功能,如规则文件的变更差异、规则对象的热加载、KieBase管理与监控、规则执行信息监控等。 - **Primary Language**: Java - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 19 - **Forks**: 8 - **Created**: 2024-08-27 - **Last Updated**: 2025-09-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: Java, drools, 规则引擎, 可视化编辑, DRULE ## README # Drule > 本文档持续更新。 ## 📚 介绍 Drule业务规则可视化平台。基于Drools 封装的业务规则可视化平台,用于简化规则开发,将规则表达式、规则条件和规则动作等进行可视化展示,并降低学习和开发成本,帮助用户快速创建业务规则。并在其基础之上,拓展更多功能,如规则文件的变更差异、规则对象的热加载、KieBase管理与监控、规则执行信息监控等。 ## 🌈 体验地址 链接:[http://ahaoweb.cn/drule/visual](http://ahaoweb.cn/drule/visual),账号:test,密码:123456 使用文档链接:[https://blog.csdn.net/qq_51513626/category_12897737.html](https://blog.csdn.net/qq_51513626/category_12897737.html) ## 🪙 技术栈 Java8,Drools 7.60.0.Final ## 🛠️ 模块关系 ```xml drule-core ``` `drule-core`:drule核心包。当前版本包含 `drule-models` , `drule-compile` 和`drule-execute` 共3个模块。 - `drule-models`:对象配置模块。用于辅助配置规则对象的信息,能够自动扫描对象结构,有利于后续相关处理。 - `drule-compile`:内容编译模块。借助于 `drule-models` 生成的规则对象结构以及某些可视化结构,生成最终的DRL文件。 - `drule-execute`:执行模块。对规则内容进行编译,生成可执行的规则服务`RuleService`,还可通过规则服务调度器统一管理规则服务,通过标识符执行规则。 ## 📖 使用说明 ### 1.drule-models #### 1.1.TreeNode `TreeNode`类是一个用于构建类型(`Class`)结构树的类,提供了构建树节点、获取节点信息、判断节点类型以及根据路径查找节点等功能。主要方法`cn.ahaoweb.drule.core.model.TreeNode#treeNode`,用于自动扫描对象结构,注意所扫描的Class必须`@ClassAnn` 注释。见如下测试代码`enums.cn.ahaoweb.drule.core.model.NodeTypeTest#scan`: ```java public void scan(){ // 设置默认的配置信息 RuleModelConfiguration.setChildDepth(2); // 扫描规则对象,转换为树形结构 TreeNode treeNode = TreeNode.treeNode(TestObj.class); System.out.println(treeNode); // 通过路径获取对于节点。(匹配cn.ahaoweb.drule.core.model.info.BaseInfo#path) System.out.println(treeNode.find("testObj.treeNodes.cesu")); } ``` ### 2.drule-compile #### 2.1.DefaultDruleCompile `DefaultDruleCompile`类是默认规则编译器,用于将结构化规则对象编译为DRL文件。它提供了添加函数、引入包/类、添加全局变量、编译规则、校验规则结构等功能。主要方法如下: 1. **addFunction(DruleFunction function)**: - **功能**: 添加函数到函数集合中 - **参数**: `DruleFunction function` - **返回值**: `boolean`,表示是否添加成功 2. **addImport(String im)**: - **功能**: 添加包/类到引入列表中 - **参数**: `String im`,表示包/类名 3. **addGlobal(String identify, String type)**: - **功能**: 添加全局变量 - **参数:** - `String identify`: 标识符(变量名) - `String type`: 变量类型 4. **compile()**: - **功能**: 编译规则,生成`DruleCompileStructure`对象 - **返回值**: `DruleCompileStructure` 5. **compileRule(DruleBlock druleBlock)**: - **功能**: 编译单个规则块 - **参数**: `DruleBlock druleBlock` - **返回值**: 编译后的规则字符串 6. **validateRules()**: - **功能**: 校验规则结构 - **返回值**: `ValidateResult` 使用方法如下,参考`cn.ahaoweb.drule.core.compile.DefaultDruleCompileTest#compileRule`: ```java // 配置好规则块集合 List rules = ...; // 入参对象的树形结构 TreeNode inNode = ...; // 出参对象的树形结构 TreeNode outNode = ...; // 构建默认编译器 DefaultDruleCompile defaultDruleCompile = new DefaultDruleCompile(rules, inNode, outNode); // 效验规则结构 ValidateResult validate = defaultDruleCompile.validateRules(); System.out.println(validate.isSuccess()); // 执行编译方法 DruleCompileStructure compile = defaultDruleCompile.compile(); // 输出最终编译的DRL内容 System.out.println(compile.toDrl()); ``` #### 2.2.DruleChineseTranslation `DruleChineseTranslation`中文转译器,用于将规则块转译为中文文本,以便业务人员理解。它提供了构建、转译规则(目前仅支持将规则内容进行转译为中文。)、生成字符串列表和生成文本内容等功能。使用方法如下 ```java // 构建中文转移器 ChineseTranslation chineseTranslation = DruleChineseTranslation.buildTranslation(rules, treeNode, treeNode); // 方式一:转译规则内容结构体集合 List translatedRuleTexts = chineseTranslation.translateRules(); // 方式二:转译后的规则文本内容 String translatedRuleTexts = chineseTranslation.generateText(); ``` 规则内容差异对比工具。 ```java // 需要对比的内容 List old_content = ... List new_content = ... // 执行对比方法 List list = DiffHandleUtils.diffList(old_content, new_content, "原内容","新内容"); // 如需,将差异内容可视化显示,可使用该方法生成一个Html文件 DiffHandleUtils.generateDiffHtml(list,"生成文件的地址"); ``` #### 2.3.FieldUsedLocator `FieldUsedLocator`字段定位器,用于定位出入参字段被使用在那些规则块(`DruleBlock`)中,提供了两种定位方法,如下所示。 其定位逻辑通过委托`cn.ahaoweb.drule.core.compile.provide.hepler.FieldMatcher`接口实现,该接口定义了字段匹配的具体逻辑。默认情况下,使用`SimpleFieldMatcher`作为字段匹配接口的实现。若需自定义匹配逻辑,可实现`FieldMatcher`接口,并在调用`locate`方法时传入自定义的匹配器实例。 ```java public static List simpleLocate(List druleBlockList, List nodes) { // 使用默认的字段匹配器 SimpleFieldMatcher return locate(druleBlockList, nodes, new SimpleFieldMatcher()); } /** * 根据给定的规则块列表和字段节点列表,关联字段出现过的规则块列表 * * @param druleBlockList 规则块列表 * @param nodes 字段节点列表 * @param fieldMatcher 字段匹配器 * @return 匹配结果列表,每个元素包含字段及其对应的规则块列表 */ public static List locate(List druleBlockList, List nodes, FieldMatcher fieldMatcher); ``` 测试方法见 `cn.ahaoweb.drule.core.compile.provide.hepler.FieldUsedLocatorTest#testSimpleLocate` 。 ### 3.drule-execute #### 3.1.RuleServiceImpl `RuleServiceImpl`类是规则服务的实现类,提供了规则内容的添加、规则服务的初始化、会话的创建、配置的管理等功能。有两种实现方式,第一种通过构造器方法`com.ahaoweb.drule.core.RuleServiceImpl`。 ```java // 构造器方法 RuleService ruleService1 = new RuleServiceImpl("id01"); RuleService ruleService2 = new RuleServiceImpl("id01","1.0.0"); RuleService ruleService3 = new RuleServiceImpl("id01","1.0.0","cn.ahaoweb"); RuleService ruleService4 = new RuleServiceImpl("id01","1.0.0","cn.ahaoweb",null); // 构造后需要添加规则内容然后初始化 String drl = DruleUtil.getFileContentByClassPath("test.drl"); ruleService4 = ruleService4 // 需要指定类型(必要) .addContent(RuleType.RULE_BLOCK,drl) // 修改配置(非必要) .addConfig(RuleServiceConfiguration.RULE_CONTENT_CACHE.PROPERTY_NAME ,RuleServiceConfiguration.RULE_CONTENT_CACHE.OPEN.value()) // 事实对象类型选择器(非必要) .factClassSelector(new FactClassSelector() { @Override public Class inType() { return TestIn.class; } @Override public Class outType() { return TestOut.class; } }) // 初始化(必要) .init(); ``` 第二种通过`cn.ahaoweb.drule.core.DruleServiceHelper` 构造(Builder模式)。 ```java RuleService test_rule = new DruleServiceHelper() // 唯一标识 .identifier("test_rule") // 添加规则内容 .addContent(RuleType.RULE_BLOCK, DruleUtil.getFileContentByClassPath("test.drl")) // 修改配置 .addConfig(RuleServiceConfiguration.RULE_CONTENT_CACHE.CLOSE) .addConfig(RuleServiceConfiguration.EXECUTE_MODE.DEBUG) // 获取构建好的规则服务 .getRuleService(); ``` #### 3.2.RuleSessionImpl 首先需要通过 `cn.ahaoweb.drule.core.RuleService#createSession` 获取 RuleSession,配置好RuleSession之后可通过`cn.ahaoweb.drule.core.RuleSession#execute(cn.ahaoweb.drule.core.FactInfo)`方法执行规则。 ```java // 获取规则内容 String drl = DruleUtil.getFileContentByClassPath("test.drl"); // 构建规则服务 RuleService ruleService = new DruleServiceHelper() // 唯一标识 .identifier("test_rule") // 添加规则内容 .addContent(RuleType.RULE_BLOCK,drl) // 修改配置 .addConfig(RuleServiceConfiguration.RULE_CONTENT_CACHE.CLOSE) .addConfig(RuleServiceConfiguration.EXECUTE_MODE.DEBUG) // 获取构建好的规则服务 .getRuleService(); // 通过 RuleService 创建规则会话 RuleSession ruleSession = ruleService.createSession() // 添加前置处理器 .addPreExecuteHandler(new PreExecuteHandler() { @Override public void preHandler(FactInfo factInfo) { TestIn input = factInfo.getInput(); input.setAge(10); System.out.println("前置处理器:"+input); } }) // 添加后置处理器 .addPostExecuteHandler(new PostExecuteHandler() { @Override public void postHandler(FactInfo factInfo) { TestOut output = (TestOut) factInfo.getOutput(); System.out.println("后置处理器:"+output); } }); // ---------------- 执行方式1: execute(FactInfo factInfo)--------------------- // 构建事实信息 FactInfo factInfo = FactInfo.FactInfoBuilder.builder() .input(new TestIn()) .inputClass(TestIn.class) .inputName("testIn") .outputClass(TestOut.class) .build(); // 通过规则会话执行事实信息 ruleSession.execute(factInfo); // 输出事实信息 System.out.println(factInfo); // ---------------- 执行方式2:execute(Object in, Object out) --------------------- TestIn input = new TestIn(); input.setName("1"); // 通过入参和出参对象,调用执行方法 FactInfo execute2 = ruleSession.execute(input,new TestOut()); // 输出事实信息 System.out.println(execute2); ``` 实际执行方法为`cn.ahaoweb.drule.core.RuleSessionImpl#doExecute`,其大致流程如下: 1. cn.ahaoweb.drule.core.RuleSessionImpl#enter(可执行拓展) 2. 执行前置处理器 cn.ahaoweb.drule.core.RuleSessionImpl#preExecuteHandlers 3. cn.ahaoweb.drule.core.RuleSessionImpl#afterPreHandlers(可执行拓展) 4. 添加规则执行监听器 cn.ahaoweb.drule.core.RuleSessionImpl#listeners,并真正执行规则 5. cn.ahaoweb.drule.core.RuleSessionImpl#afterExecuted(可执行拓展) 6. 执行前置处理器 cn.ahaoweb.drule.core.RuleSessionImpl#postExecuteHandlers 7. cn.ahaoweb.drule.core.RuleSessionImpl#afterPostHandlers(可执行拓展) 8. 销毁会话 cn.ahaoweb.drule.core.KieSessionWrapper#destroy 9. cn.ahaoweb.drule.core.RuleSessionImpl#exit(可执行拓展) #### 3.3.RuleServiceScheduler `RuleServiceScheduler`类是一个规则服务调度器,扩展了`RuleServiceFactory`类,提供了统一管理规则服务的功能。该类可通过规则服务构造器`RuleServiceConstructor`动态获取规则服务实例,并维护了一个规则服务会话的缓存,以提高规则执行的效率。同时,该类提供了多种重载的`execute`方法,方便用户以不同的方式执行规则。 有两种使用方式,如下所示: ```java /** * 通用流程 * 1.构建好规则服务RuleService; * 2.添加至调度器RuleServiceScheduler中; * 3.通过identifier获取RuleSession,可配置规则执行监听器、前置/后置处理器等操作; * 4.通过调度器执行规则。 */ @Test public void generalProcessing(){ // 构建调度器 RuleServiceScheduler ruleServiceScheduler = new RuleServiceScheduler(); // 服务1 RuleService test1 = getTest1(); // 添加至调度器中 ruleServiceScheduler.addService(test1); // 服务2 RuleService test2 = getTest2(); // 添加至调度器中 ruleServiceScheduler.addService("test2", test2); // 通过identifier获取RuleSession,可配置规则执行监听器、前置/后置处理器 RuleSession ruleSession = ruleServiceScheduler.getRuleSession("test1"); ruleSession.addPreExecuteHandler(new PreExecuteHandler() { @Override public void preHandler(FactInfo factInfo) { TestIn input = factInfo.getInput(); System.out.println("入参对象的名称:"+input.getName()); } }); // 开始通过调度器执行 // 方式1:通过唯一标识符进行调用 ruleServiceScheduler.execute("test1", new TestIn()); ruleServiceScheduler.execute("test2", new Person()); // 方式2:直接通过入参对象进行调用(注意⚠️:此方式需要确保唯一标识符和入参对象类型是一一对应的) TestIn in = new TestIn(); in.setName("test"); ruleServiceScheduler.execute(in); Person person = new Person(); person.setAge(18); ruleServiceScheduler.execute("test2", person); } /** * 动态流程 *
     *     1.构建规则服务调度器,并配置好RuleServiceConstructor;
     *     2.通过调度器执行规则。
     * 
*/ @Test public void automationProcessing(){ // 构建规则服务调度器 RuleServiceScheduler scheduler = new RuleServiceScheduler(new RuleServiceConstructor() { /** * 此处如何生产规则服务的方式可自由实现,例如从数据库中获取。 * @param identifier * @return */ @Override public RuleService getRuleService(String identifier) { if ("test1".equals(identifier)){ return getTest1(); } if ("test2".equals(identifier)){ return getTest2(); } return null; } }); // 不需要添加规则服务,直接执行即可 scheduler.execute("test1",new TestIn()); /** * 以下方式调度需要配置 {@link cn.ahaoweb.drule.core.RuleServiceConstructor#getIdentifier} */ // scheduler.execute(new TestIn()); } ``` #### 3.4.AfterCreateSessionCallback `AfterCreateSessionCallback` 接口作用是在规则会话创建后提供一个扩展点,允许开发者在会话创建后执行自定义的逻辑。例如,可以在这里添加日志记录、会话参数设置、会话监听器等。 使用方式如下: ```java RuleService test2 = new DruleServiceHelper() // 唯一标识 .identifier("test2") // 省略其他不相关内容... // 设置 规则会话创建后回调函数 .afterCreateSessionCallback(ruleSession -> { log.info("执行 afterCreateSessionCallback"); ruleSession.addPreExecuteHandler(new PreExecuteHandler() { @Override public void preHandler(FactInfo factInfo) { log.info("afterCreateSessionCallback 添加的 执行前处理器:{}",factInfo); } }); return ruleSession; }); ``` ## 📝 配置说明 ### 1.规则条件运算符 ```java public enum ConditionOperate{ eq("==","等于", new Operator.Eq()), neq("!=","不等于", new Operator.Neq()), lt("<","小于", new Operator.Lt()), lte("<=","小于等于", new Operator.Lte()), gt(">","大于", new Operator.Gt()), gte(">=","大于等于", new Operator.Gte()), left_contains("contains","包含(左)", new Operator.LeftContains()), right_contains("contains","包含(右)", new Operator.RightContains()), not_left_contains("not contains","不包含(左)", new Operator.LeftNotContains()), not_right_contains("not contains","不包含(右)", new Operator.RightNotContains()), in("in","存在于", new Operator.In()), not_in("not in","不存在于", new Operator.NotIn()), matches("matches","正则匹配", new Operator.Matches()), not_matches("not matches","正则不匹配", new Operator.NotMatches()), // 其他条件判断符待扩充 ; } ``` #### 1.1.eq、neq 等价于java中的`equals()`和`!equals()`。 #### 1.2.lt、lte、gt、gte 关系运算`<`、`<=`、 `>`、 `>=`。 #### 1.3.left_contains、right_contains 包含(左)表示参数字段在左侧,比如 `name contains "jack"`。而包含(右)则表示参数字段在右侧,即 `"jack" contains name`。 当前条件支持List和字符串。字符串等价于`java.lang.String#contains`,List表示是否包含指定元素。 #### 1.4.not_left_contains、not_right_contains 与`left_contains`、`right_contains`判断逻辑相反。 #### 1.5.in、not_in 相当于`sql`中的`in`操作符,用于检查某个值是否包含在给定的多个可能值。例如`name in ("jack","mary")` #### 1.6.matches、not_matches 与指定的Java正则表达式匹配或不匹配。例如`name matches "ja.*"` ## 🎋 分支说明 | 分支 | 说明 | | ----------- | ------------------------------------------------------------ | | release-1.6 | 1.新增字段定位器`FieldUsedLocator`:用于定位出入参字段被使用在那些规则块(`DruleBlock`)中。
2.新增规则会话执行异常处理器`RuleExecuteExceptionHandler`,用于规则执行异常时进行处理,例如异常兜底输出。
3.新增规则会话创建后回调函数`AfterCreateSessionCallback`。用于解决调度器在某些场景需要加工规则会话时的不便。 | | release-1.5 | 1.新增8种条件运算符:包含(左),包含(右),不包含(左),不包含(右),存在于,不存在于,正则匹配,正则不匹配。
2.规则服务调度器支持直接通过入参对象执行规则 | | release-1.4 | 1.新增规则服务调度器,提供了统一管理规则服务的功能。
2.`RuleService`新增事实对象类型选择器`factClassSelector`,用于获取规则出入参对象类型。 | | release-1.3 | 1.新增中文转译器`ChineseTranslation`,支持将规则块转译为中文。
2.新增文本差异对比工具`DiffHandleUtils`,将转译后的规则内容进行差异对比,支持转`html`可视化显示。
3.修复问题:节点类型中新增布尔类型 | | release-1.2 | 1.新增效验可视化规则块的方法:`DefaultDruleCompile.validateRules`
2.根据类型的选择不同的值处理逻辑:`Operator.Eq.doCompile` | | release-1.1 | 新增`drule-execute`模块。基于KieBase构建可执行的规则服务`RuleService`,统一执行框架,并对部分过程开放接口,允许自定义实现。 | | release-1.0 | 完成初版的规则对象配置和规则编译功能。
1.支持根据注解描述规则对象,转换为`TreeNode`结构;
2.支持简单的规则编译功能,不支持函数;
3.支持6种简单条件运算符:等于、不等于、小于、小于等于、大于、大于等于; | ## 📦 合作与支持 感谢大家对此项目的支持,如有其他需要,可直接联系本人。 QQ:1298894906 邮箱:1298894906@qq.com