(一)基于业务需求动态生成 DRT 规则模板:事实与动作定义详解
背景
在业务规则管理中,DRT 文件(Drools Rule Template)用于定义和重用规则模板,这些模板可以动态地根据实际业务需求进行填充和生成。通过动态生成 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 Person
name: String
age: int
birthDate: java.util.Date
end
/**
* 动作声明
*/
declare Action
setName(name: String);
setAge(age: int);
setBirthDate(birthDate: java.util.Date);
end
/**
* 规则定义
*/
rule "exampleRule"
when
$person: Person(age > 18, birthDate >= DateUtils.getStartOfYear())
then
Action 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 文件的结构及其生成方法。
如果有进一步的问题或需要更多帮助,请随时告诉我!