(一)基于业务需求动态生成 DRT 规则模板:事实与动作定义详解
背景
在业务规则管理中,DRT 文件(Drools Rule Template)用于定义和重用规则模板,这些模板可以动态地根据实际业务需求进行填充和生成。通过动态生成 DRT 文件,我们可以根据不同的业务场景创建定制化的规则,从而提高业务规则配置的灵活性和效率。本文将介绍如何根据事实和动作定义动态生成 DRT 规则模板文件,并提供详细的代码注释,以帮助理解其生成过程。
接下来,我将进一步完善以下两个部分,以形成完整的规则引擎闭环:
(二) 基于DRT 规则模板动态配置,生成DRL规则文件
(三) 基于业务需求动态调用DRL规则文件
drools介绍,请参考:
探索Drools:Java世界的规则引擎
DRT 文件介绍
DRT 文件格式主要用于定义可重用的规则模板。一个标准的 DRT 文件通常包括以下部分:
- 模板头部:定义规则模板的基本信息。
- 包声明:指定规则模板所在的包。
- 导入语句:导入规则模板中需要使用的类或库。
- 事实声明:定义规则模板中涉及的事实类型及其属性。
- 动作声明:定义规则模板中触发的动作及其方法。
- 规则定义:具体的规则内容,包括
when
和then
部分。 - 模板结束标识:标记规则模板的结束。
示例 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
,包括其属性name
、age
和birthDate
。end
: 结束事实声明部分。
-
动作声明:
declare Action
: 声明动作类型Action
,包括其方法setName
、setAge
和setBirthDate
。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
:构建规则的when
和then
部分,处理事实条件、动作执行及日期验证。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 文件的结构及其生成方法。
如果有进一步的问题或需要更多帮助,请随时告诉我!