基于业务数据动态调用 DRL 规则文件:详解与实战
在业务规则管理中,DRL 文件(Drools Rule Language 文件)用于定义和执行业务规则。通过动态调用 DRL 文件,我们可以根据不同的业务场景灵活配置和执行定制化的规则,从而提高业务规则配置的灵活性和效率。本文将详细介绍如何基于业务数据动态调用 DRL 规则文件,并提供详细的代码注释和实现步骤,以帮助理解其执行过程。我们还将展示一个测试功能,用于模拟真实场景并验证规则执行的成功与否。
drools介绍,请参考:
探索Drools:Java世界的规则引擎
1. DRT 文件介绍
DRL(Drools Rule Language)文件是用来编写规则的文件格式,基于 DRT 规则模板动态配置生成 DRL 规则文件(更多请看:
(一)基于业务需求动态生成 DRT 规则模板:事实与动作定义详解),我们可以根据不同的业务场景创建定制化的规则,提高业务规则配置的灵活性和效率。
下面是: (二)基于业务需求动态生成 DRL 规则文件:事实与动作定义详解
package org.droolsimport com.xinyuan.re.utils.DateUtilsdeclare SuppliersNumberFactPVOpurchaseMethod: StringprojectStage: StringsuppliersNumber: Integer
enddeclare SubmitTaskVerifyMessagestate: inttext: String
endrule "re_openbid_supplier_count_0"when $suppliers_number_fact_p_v_o : SuppliersNumberFactPVO(("00380002,00380024,00380020,00380003" == "null" || purchaseMethod memberOf "00380002,00380024,00380020,00380003") &&("1" == "null" || projectStage == 1) &&("3" == "null" || suppliersNumber < 3));$submit_task_verify_message : SubmitTaskVerifyMessage();then $submit_task_verify_message.setState(2);$submit_task_verify_message.setText("招标的项目,投标人数量少于3个不得开标");
endrule "re_openbid_supplier_count_1"when $suppliers_number_fact_p_v_o : SuppliersNumberFactPVO(("00380002,00380003,00380020,00380024" == "null" || purchaseMethod memberOf "00380002,00380003,00380020,00380024") &&("2" == "null" || projectStage == 2) &&("3" == "null" || suppliersNumber < 3));$submit_task_verify_message : SubmitTaskVerifyMessage();then $submit_task_verify_message.setState(2);$submit_task_verify_message.setText("资审阶段的项目,申请人数量少于3个不得开启");
end
2. 规则测试功能
我们为此专门开发了一个测试功能,可以模拟真实的业务场景,并调用规则执行,返回规则执行结果。通过此功能,可以快速验证规则的正确性和业务适用性。
测试功能界面如图所示:
在测试功能中,事实定义的数据会自动加载出来,用户可以根据实际需求输入相关参数,点击测试按钮后系统会自动调用规则引擎,返回测试结果。
3. 代码实现详解
下面是完整的代码实现,并附上详细注释,帮助理解其生成过程:
/*** 执行规则** @param ruleEngineContext 规则引擎上下文* @return 执行结果*/
@Override
public ReturnValue<Map<String, Object>> execRule(RuleEngineContext ruleEngineContext) {log.info("---------------执行规则开始---------------");// 获取规则定义GetReDefine getReDefine = reEngineService.getReDefine(ruleEngineContext.getRuleCode());Map<String, Object> actionMap = new HashMap<>();// 检查规则文件是否存在if (StringUtils.isNotBlank(getReDefine.getDrl_rule_file())) {// 获取事实定义GetReFactDefine getReFactDefine = reEngineService.getReFactDefine(getReDefine.getId());// 获取动作定义GetReActionDefine getReActionDefine = reEngineService.getReActionDefine(getReDefine.getId());// 使用 KieHelper 构建规则引擎KieHelper helper = new KieHelper();GetBigColumnRVO getBigColumnRVO = bigColumnFacade.getBigColumn(getReDefine.getDrl_rule_file());helper.addContent(getBigColumnRVO.getZdz(), ResourceType.DRL);log.info("执行规则,drl文件:{}", getBigColumnRVO.getZdz());// 构建 KieBaseKieBase kieBase = helper.build();// 获取事实类型和动作类型FactType factType = kieBase.getFactType(Constants_public.ORG_DRT_PACKAGE_NAME, getReFactDefine.getClass_name());FactType actionType = kieBase.getFactType(Constants_public.ORG_DRT_PACKAGE_NAME, getReActionDefine.getClass_name());log.info("执行规则,事实定义,所属服务:{}", getReFactDefine.getOwn_service());Map<String, Object> bizData;// 如果业务数据为空,则根据业务编号获取业务数据if (ruleEngineContext.getBizData().isEmpty()) {ReturnValue<Map<String, Object>> returnValue = reBizFacade.getBizData(getReFactDefine.getOwn_service(),RuleEngineContext.builder().bizId(ruleEngineContext.getBizId()).implClass(getReFactDefine.getFact_loader()).build());bizData = returnValue.getData();} else {// 使用上下文中的业务数据bizData = ruleEngineContext.getBizData();// 将数值类型的字符串转换为相应的数值类型List<ConditionDefine> conditionDefineList = getReFactDefine.getConditionDefineList();Map<String, Integer> conditionMap = conditionDefineList.stream().collect(Collectors.toMap(ConditionDefine::getFieldCode, ConditionDefine::getFieldType));bizData.forEach((key, val) -> {if (val != null && Objects.equals(conditionMap.get(key), Constants_re.FACT_PROP_TYPE_NUMBER)) {if (ConvertUtil.createString(val).length() >= 8) {bizData.put(key, ConvertUtil.createLong(val));} else {bizData.put(key, ConvertUtil.createInteger(val));}}});}log.info("执行规则,业务数据:{}", bizData);Object factInstance;Object actionInstance;try {// 创建事实实例factInstance = factType.newInstance();factType.setFromMap(factInstance, bizData);// 创建动作实例actionInstance = actionType.newInstance();} catch (InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}// 创建 KieSessionKieSession kieSession = kieBase.newKieSession();kieSession.insert(factInstance);kieSession.insert(actionInstance);// 执行所有规则kieSession.fireAllRules();// 释放 KieSessionkieSession.dispose();// 获取动作执行后的结果actionMap = actionType.getAsMap(actionInstance);log.info("执行规则,返回数据:{}", actionMap);}log.info("---------------执行规则结束---------------");ReturnValue<Map<String, Object>> returnValue = ReturnValue.newSuccessInstance();returnValue.setData(actionMap);return returnValue;
}
4. 测试功能说明
为了验证规则文件的正确性,我们实现了一个专门的测试功能。用户可以通过界面输入相关参数,模拟真实业务场景,测试规则的执行情况。
测试功能的使用步骤如下:
- 选择步骤:从下拉列表中选择需要测试的业务步骤。
- 选择时间类型:从下拉列表中选择时间类型。
- 输入当前时间和投标截止时间。
- 点击“测试”按钮,系统将调用规则引擎执行规则,并在“测试结果”中显示执行结果。
通过此测试功能,可以快速验证不同业务场景下规则的执行效果,确保规则的正确性和适用性。
总结
本文详细介绍了如何基于业务数据动态调用 DRL 规则文件,并通过实际代码示例和详细注释,阐述了整个执行过程。我们还展示了一个专门的测试功能,帮助模拟和验证规则执行的效果。通过这种方式,可以实现业务规则的灵活配置和高效执行,提升业务系统的自动化和智能化水平。