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

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

背景

在业务规则管理中,DRT 文件(Drools Rule Template)用于定义和重用规则模板,这些模板可以动态地根据实际业务需求进行填充和生成。通过动态生成 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 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,包括其属性 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 文件的结构及其生成方法。


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

  • 21
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jack_hrx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值