【Drools】(一)基于业务需求动态生成 DRT 规则模板:事实与动作定义详解

(一)基于业务需求动态生成 DRT 规则模板:事实与动作定义详解

背景

在业务规则管理中,DRT 文件(Drools Rule Template)用于定义和重用规则模板,这些模板可以动态地根据实际业务需求进行填充和生成。通过动态生成 DRT 文件,我们可以根据不同的业务场景创建定制化的规则,从而提高业务规则配置的灵活性和效率。本文将介绍如何根据事实和动作定义动态生成 DRT 规则模板文件,并提供详细的代码注释,以帮助理解其生成过程。
接下来,我将进一步完善以下两个部分,以形成完整的规则引擎闭环:
(二) 基于DRT 规则模板动态配置,生成DRL规则文件
(三) 基于业务需求动态调用DRL规则文件

drools介绍,请参考: 探索Drools:Java世界的规则引擎

在这里插入图片描述

在这里插入图片描述

DRT 文件介绍

在这里插入图片描述

DRT 文件格式主要用于定义可重用的规则模板。一个标准的 DRT 文件通常包括以下部分:

  1. 模板头部:定义规则模板的基本信息。
  2. 包声明:指定规则模板所在的包。
  3. 导入语句:导入规则模板中需要使用的类或库。
  4. 事实声明:定义规则模板中涉及的事实类型及其属性。
  5. 动作声明:定义规则模板中触发的动作及其方法。
  6. 规则定义:具体的规则内容,包括 whenthen 部分。
  7. 模板结束标识:标记规则模板的结束。

示例 DRT 文件

以下是一个 DRT 文件的示例,展示了其基本结构和实际应用:

/*** 规则模板头部*/
template "exampleRuleTemplate"/*** 包声明*/
package com.example.rules/*** 导入语句*/
import com.example.models.Person;
import com.example.utils.DateUtils;/*** 事实声明*/
declare Personname: Stringage: intbirthDate: java.util.Date
end/*** 动作声明*/
declare ActionsetName(name: String);setAge(age: int);setBirthDate(birthDate: java.util.Date);
end/*** 规则定义*/
rule "exampleRule"when$person: Person(age > 18, birthDate >= DateUtils.getStartOfYear())thenAction action = new Action();action.setName($person.getName());action.setAge($person.getAge());action.setBirthDate($person.getBirthDate());// 其他业务逻辑
end

说明

  • 模板头部

    • template "exampleRuleTemplate": 这是规则模板的标识符,用于引用和填充模板内容。
  • 包声明

    • package com.example.rules: 指定规则模板所在的包,以便在项目中组织和管理规则模板。
  • 导入语句

    • import com.example.models.Person;: 导入用于事实声明的 Person 类。
    • import com.example.utils.DateUtils;: 导入用于日期处理的工具类 DateUtils
  • 事实声明

    • declare Person: 声明事实类型 Person,包括其属性 nameagebirthDate
    • end: 结束事实声明部分。
  • 动作声明

    • declare Action: 声明动作类型 Action,包括其方法 setNamesetAgesetBirthDate
    • end: 结束动作声明部分。
  • 规则定义

    • rule "exampleRule": 定义规则 exampleRule,包括规则名称和描述。
    • when: 规则的条件部分,用于匹配满足特定条件的事实。
      • $person: Person(age > 18, birthDate >= DateUtils.getStartOfYear()): 匹配年龄大于 18 岁且出生日期在当前年份开始之后的 Person 对象。
    • then: 规则的动作部分,用于触发匹配规则后的操作。
      • 创建 Action 对象并设置其属性。
      • 执行其他业务逻辑。

动态生成 DRT 文件

DrtTemplateUtil

DrtTemplateUtil 类提供了动态生成 DRT 规则模板文件的方法。以下是该类的详细实现和功能说明:

/*** DrtTemplateUtil - 动态生成 DRT 规则模板的工具类*/
public class DrtTemplateUtil {/*** 生成 DRT 规则模板** @param factDefine 事实定义对象,包含事实类型及其属性* @param actionDefine 动作定义对象,包含动作类型及其方法* @param ruleCode 规则代码,用于标识生成的规则模板* @return 生成的 DRT 规则模板字符串*/public static String generateDrtTemplate(GetReFactDefineRVO factDefine, GetReActionDefineRVO actionDefine, String ruleCode) {StringBuilder sb = new StringBuilder();// 添加模板头部sb.append(Constants_public.ORG_DRT_TEMPLATE_HEADER).append("\n");// 添加事实和动作定义列sb.append(getCustomParams(factDefine.getClass_params()));sb.append(getCustomParams(actionDefine.getClass_params()));sb.append("\n");// 添加包声明sb.append(Constants_public.ORG_DRT_PACKAGE).append(" ").append(Constants_public.ORG_DRT_PACKAGE_NAME).append("\n");sb.append("\n");// 添加导入语句getImport(sb);// 添加事实和动作声明getDeclare(factDefine, sb);getDeclare(actionDefine, sb);sb.append("\n");// 添加规则定义sb.append(Constants_public.ORG_DRT_TEMPLATE).append(" ").append("\"").append(ruleCode).append("\"").append("\n");getRule(factDefine, actionDefine, ruleCode, sb);// 添加模板结束标识sb.append(Constants_public.ORG_DRT_END_TEMPLATE);return sb.toString();}/*** 生成规则定义部分** @param factDefine 事实定义对象* @param actionDefine 动作定义对象* @param ruleCode 规则代码* @param sb StringBuilder 对象,用于构建规则模板字符串*/private static void getRule(GetReFactDefineRVO factDefine, GetReActionDefineRVO actionDefine, String ruleCode, StringBuilder sb) {// 添加规则标识sb.append(Constants_public.ORG_DRT_RULE).append(" \"").append(ruleCode).append(Constants_public.ORG_DRT_ROW_NUMBER).append("\"\n").append(DroolsUtil.tabNum(1)).append(Constants_public.ORG_DRT_WHEN).append(" \n");// 添加事实定义sb.append(DroolsUtil.tabNum(2)).append("$").append(DroolsUtil.getClassAlias(factDefine.getClass_name())).append(" : ").append(factDefine.getClass_name()).append("(").append(getConditions(factDefine)).append(")").append(";\n");// 添加日期处理逻辑List<ConditionDefineRVO> dateConditions = factDefine.getConditionDefineRVOList().stream().filter(e -> StringUtils.isNotBlank(e.getExpression()) && e.getExpression().contains(Constants_public.ORG_DRT_TEMPLATE_DATA_SIGN)).collect(Collectors.toList());List<String> verifyDates = getVerifyDates(factDefine, dateConditions, sb);// 添加动作定义sb.append(DroolsUtil.tabNum(2)).append("$").append(DroolsUtil.getClassAlias(actionDefine.getClass_name())).append(" : ").append(actionDefine.getClass_name()).append("()").append(";\n").append(DroolsUtil.tabNum(1)).append(Constants_public.ORG_DRT_THEN).append(" \n").append(getActions(actionDefine, dateConditions, verifyDates)).append("\n").append(Constants_public.ORG_DRT_END).append("\n");}/*** 获取条件表达式** @param factDefine 事实定义对象* @return 条件表达式字符串*/private static String getConditions(GetReFactDefineRVO factDefine) {return factDefine.getConditionDefineRVOList().stream().filter(e -> StringUtils.isNotBlank(e.getExpression()) && !e.getExpression().contains(Constants_public.ORG_DRT_TEMPLATE_DATA_SIGN)).map(e -> e.getExpression().contains("@{") ? "(" + getNullStrOfRegex(e.getExpression()) + e.getExpression() + ")" : e.getExpression()).collect(Collectors.joining(Constants_public.ORG_DRT_DEFAULT_RELATION));}/*** 获取日期验证列表** @param factDefine 事实定义对象* @param dateConditions 日期条件列表* @param sb StringBuilder 对象* @return 日期验证列表*/private static List<String> getVerifyDates(GetReFactDefineRVO factDefine, List<ConditionDefineRVO> dateConditions, StringBuilder sb) {List<String> verifyDates = new ArrayList<>();for (int i = 0; i < dateConditions.size(); i++) {StringBuilder dateCondition = new StringBuilder();dateCondition.append("$").append(DroolsUtil.getClassAlias(factDefine.getClass_name())).append(".get").append(StringUtils.capitalize(Constants_public.ORG_DRT_TEMPLATE_START_DATE)).append("(), ").append("$").append(DroolsUtil.getClassAlias(factDefine.getClass_name())).append(".get").append(StringUtils.capitalize(Constants_public.ORG_DRT_TEMPLATE_END_DATE)).append("()");String expression = dateConditions.get(i).getExpression();sb.append(DroolsUtil.tabNum(2)).append("$verifyDate").append(i).append(" : ").append(MessageFormat.format(Constants_public.ORG_DRT_TEMPLATE_WHEN_DATE_CALL, getNullStrOfRegex(expression), dateCondition)).append(expression.substring(expression.indexOf(")") + 1)).append("\n");verifyDates.add("$verifyDate" + i);}return verifyDates;}/*** 获取动作表达式** @param actionDefine 动作定义对象* @param dateConditions 日期条件列表* @param verifyDates 日期验证列表* @return 动作表达式字符串*/private static String getActions(GetReActionDefineRVO actionDefine, List<ConditionDefineRVO> dateConditions, List<String> verifyDates) {StringBuilder sb = new StringBuilder();String[] actionParams = getCustomParams(actionDefine.getClass_params()).split("\n");for (String action : actionParams) {sb.append(DroolsUtil.tabNum(dateConditions.isEmpty() ? 2 : 3)).append("$").append(DroolsUtil.getClassAlias(actionDefine.getClass_name())).append(".set").append(StringUtils.capitalize(action)).append("(@{").append(action).append("});").append("\n");}if (!dateConditions.isEmpty()) {sb.insert(0, DroolsUtil.tabNum(2) + MessageFormat.format("if ({0}) '{", String.join(Constants_public.ORG_DRT_DEFAULT_RELATION, verifyDates)) + "\n");sb.append(DroolsUtil.tabNum(2)).append("}");}return sb.toString();}/*** 生成正则表达式匹配的空字符串,用于数据校验** @param expression 原始表达式* @return 生成的空字符串*/private static String getNullStrOfRegex(String expression) {Pattern pattern = Pattern.compile(Constants_public.GLOBAL_PARAMS_PATTERN);Matcher matcher = pattern.matcher(expression);StringBuilder nullStr = new StringBuilder();while (matcher.find()) {nullStr.append("\"").append(matcher.group()).append("\" == \"null\" ").append(Constants_public.ORG_DRT_OR_RELATION).append(" ");}return nullStr.toString();}/*** 添加导入语句到 StringBuilder 对象中** @param sb StringBuilder 对象*/private static void getImport(StringBuilder sb) {sb.append(Constants_public.ORG_DRT_IMPORT).append(" com.xinyuan.re.utils.DateUtils").append("\n\n");}/*** 添加声明部分到 StringBuilder 对象中** @param classParamsAndName 事实或动作定义对象* @param sb StringBuilder 对象*/private static void getDeclare(GetClassParamsAndNameRVO classParamsAndName, StringBuilder sb) {sb.append(Constants_public.ORG_DRT_DECLARE).append(" ").append(classParamsAndName.getClass_name()).append("\n").append(classParamsAndName.getClass_params()).append(Constants_public.ORG_DRT_END).append("\n");}/*** 格式化自定义参数,去除多余的空格和制表符** @param classParams 自定义参数字符串* @return 格式化后的参数字符串*/public static String getCustomParams(String classParams) {return classParams.replaceAll(":\\s\\w+\\n", "\n").replaceAll("\\t", "");}
}

方法功能

  • generateDrtTemplate:生成 DRT 文件模板的核心方法,接受事实定义、动作定义和规则代码作为输入,返回格式化的 DRT 文件模板字符串。
  • getRule:构建规则的 whenthen 部分,处理事实条件、动作执行及日期验证。
  • getNullStrOfRegex:生成正则表达式匹配的空字符串,用于数据校验。
  • getImport:添加必要的导入语句到 StringBuilder 对象中。
  • getDeclare:添加类声明部分到 StringBuilder 对象中,包括类名和参数定义。
  • getCustomParams:格式化自定义参数,去除多余的空格和制表符。

示例

以下是如何使用 DrtTemplateUtil 类生成 DRT 文件模板的示例:

GetReFactDefineRVO factDefine = new GetReFactDefineRVO();
// 设置 factDefine 的属性
// ...GetReActionDefineRVO actionDefine = new GetReActionDefineRVO();
// 设置 actionDefine 的属性
// ...String ruleCode = "exampleRuleCode";// 生成 DRT 文件模板
String drtTemplate = DrtTemplateUtil.generateDrtTemplate(factDefine, actionDefine, ruleCode);// 输出模板
System.out.println(drtTemplate);

结论

通过使用 DrtTemplateUtil 类,我们能够根据不同的业务需求动态生成符合规范的 DRT 文件模板。这种方法不仅提高了规则配置的灵活性,还简化了规则模板的生成过程,使得规则管理更加高效。希望本文的示例和详细注释能帮助您理解 DRT 文件的结构及其生成方法。


如果有进一步的问题或需要更多帮助,请随时告诉我!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/50311.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 10.0 Launcher 启动流程

在前面SystemUI启动流程中说到&#xff0c;在SystemServer中会去启动各种系统服务&#xff0c;这里的launcher也是启动的其中一个服务ActivityManagerService去启动的。在android10之前&#xff0c;系统四大组件的启动都是在ActivityManagerService中&#xff0c;在android10中…

C语言实现多线程下载

本文介绍c语言实现多线程下载&#xff0c;使用 curl库 需求分析 对于一个文件的下载&#xff0c;我们有多种情况需要考虑&#xff1a; 1.单线程下载还是多线程下载 2.如果是多线程下载&#xff0c;如何保证下载结果正确 3.能否实现断点续传 4.能否实现多文件下载 设计 …

前端创建仓库的详细步骤

第一步点击号新建仓库 第二步输入完仓库名称路径会自己出来然后点击创建 第三步在自己创建的文件夹右键点击GIt Bash Here 第四步把我框的这些一个一个的输在Git Bash Here中每输入一个回车一个 第五步全部输入完以后CtrlF5自动刷新下就好了 然后文件夹就会有.git了

机器视觉12-相机

相机 作用: 工业相机 是 机器视觉系统 的重要组成部分 最本质的功能就是通过CCD或CMOS成 像传感器将镜头产生的光信号转变为 有序的电信号&#xff0c;并将这些信息通过相 应接口传送到计算机主机 工业相机分类 目前业内没有对相机进行明确的分类定义&#xff0c; 以下分类是…

Python 学习中的 API,如何调用API ?

1.1 API的定义 API&#xff0c;全称是Application Programming Interface&#xff08;应用程序编程接口&#xff09;。它是一组定义好的协议和工具&#xff0c;用于在软件应用程序之间进行通信。API可以简化软件开发&#xff0c;使不同的应用程序能够相互协作。它是软件开发中…

数字车间与智能工厂:区别、联系与制造业的未来转型

数字车间和智能工厂在制造业中扮演着重要角色&#xff0c;它们之间存在明显的区别和紧密的联系。以下是对两者区别和联系的详细阐述&#xff1a; 一、区别 定义与范围 数字车间&#xff1a;数字车间是指通过信息化技术、智能化装备和数据化管理等手段&#xff0c;实现生产过程全…

【Python系列】Python 程序的优雅退出:使用`sys.exit()`控制程序终止

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

笔记本电脑怎么录屏?5个小技巧(2024最全)

在今天&#xff0c;录屏功能已经不再是专业人士的专属&#xff0c;而是融入了普通人的日常生活与工作之中。想要记录游戏的精彩瞬间、分享软件的操作教程&#xff0c;或是保存屏幕上的重要信息&#xff0c;录屏都能帮你一键搞定。那么&#xff0c;对于我们这些日常使用笔记本电…

初始K8s

K8S 基本概念: K8S 的全称为 Kubernetes (K12345678S)&#xff0c;PS&#xff1a;“嘛&#xff0c;写全称也太累了吧&#xff0c;不如整个缩写”。 作用&#xff1a; 用于自动部署、扩展和管理“容器化&#xff08;containerized&#xff09;应用程序”的开源系统。 可以理解成…

火狐浏览器怎么切换ip:详细步骤与注意事项

随着互联网的飞速发展&#xff0c;网络环境的复杂性和安全性问题日益凸显。对于需要保护个人隐私、突破地域限制或进行网络测试的用户来说&#xff0c;切换IP地址成为了一项重要的技能。火狐浏览器&#xff0c;作为一款备受欢迎的开源浏览器&#xff0c;凭借其强大的自定义功能…

Kafka 消费者启动后与服务器的交互流程

Kafka 消费者启动后与服务器的交互流程涉及多个关键步骤&#xff0c;主要包括初始化、查找组协调器、加入消费者组、分区分配、心跳维持、拉取数据和提交偏移量等。以下是详细的流程说明&#xff1a; 1. 初始化消费者 创建消费者实例&#xff1a;应用程序通过调用KafkaConsum…

PHP表单必需字段

在PHP中处理表单时&#xff0c;确保必填字段被正确填写是非常重要的。这通常涉及到在客户端&#xff08;使用HTML5&#xff09;和服务器端&#xff08;使用PHP&#xff09;进行验证。以下是一个关于PHP表单必需字段的详细教程&#xff0c;包括如何在客户端和服务器端进行验证。…

【计算机网络】TCP和UDP的封装以及案例

TCP和UDP的封装以及案例 背景知识TCP实现UDP实现封装Network用NetWork再次实现TCP和UDP小知识点 背景知识 TCP&#xff1a;传输控制协议&#xff08;Transmission Control Protocol&#xff09; UDP&#xff1a;用户数据报协议 &#xff08;User Datagram Protocol&#xff09…

Spring Bean的初始化过程

在Spring框架中&#xff0c;Bean是应用程序的基本构建块。每个Bean都是由Spring IoC容器管理的对象实例&#xff0c;用于封装业务逻辑或资源。理解Spring Bean的初始化过程对于有效地使用和配置Spring框架至关重要。本文将详细解释Spring Bean的生命周期&#xff0c;包括其创建…

AI的欺骗游戏:揭示多模态大型语言模型的易受骗性

人工智能咨询培训老师叶梓 转载标明出处 多模态大型语言模型&#xff08;MLLMs&#xff09;在处理包含欺骗性信息的提示时容易生成幻觉式响应。尤其是在生成长响应时&#xff0c;仍然是一个未被充分研究的问题。来自 Apple 公司的研究团队提出了MAD-Bench&#xff0c;一个包含8…

Spring的优缺点?

Spring的优缺点 直接回答相关的Spring的特点&#xff1a; IOC AOP 事务 简化开发&#xff1a; 容易集成JDBCTemplateRestTemplate&#xff08;接口远程调用&#xff09;邮件发送相关异步消息请求支持 更加深入就讲源码了 优点&#xff1a; 方便解耦&#xff0c;简化开发…

网站打不开怎么办,收藏以备不时之需

DNS设置示范教程 部分地区有使用移动网络的小伙伴们吐槽无法访问部分网站的情况&#xff0c;同样的网站&#xff0c;使用电信和联通的用户就能正常访问。 这其实有很大几率是由于运营商的网络问题导致的&#xff0c;容易出现网站打不开的结果。 要解决移动网络无法访问的情况…

docker 部署mysql nginx redis

设置镜像 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://tddq0ov6.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload 重启 sudo systemctl restart docker mysql mkdir /docker/my…

[React]如何提高大数据量场景下的Table性能?

[React]如何提高大数据量场景下的Table性能&#xff1f; 两个方向&#xff1a;虚拟列表&#xff0c;发布订阅 虚拟列表 虚拟列表实际上只对可视区域的数据项进行渲染 可视区域&#xff08;visibleHeight&#xff09;: 根据屏幕可视区域动态计算或自定义固定高度数据渲染项&…

python_合并同一个文件夹下的excel文件

python_合并同一个文件夹下的excel文件 import os import glob import pandas as pddef merge_excel_sheets(input_folder, output_file):# 创建一个空的 DataFrame 用于存储所有数据combined_data pd.DataFrame()# 获取指定文件夹内所有的 Excel 文件excel_files glob.glob…