在之前的文章中,我们的业务规则都是写在了drl文件中,这对开发人员来说是没有什么问题,如果是业务人员则不怎么友好,这篇文章我们简单学习一下drools中决策表的使用,规则是写在excel文件中。

在上面这个图中ResultSet和ResultTable是必须的,而且同一个包中,我们最好只上传一个决策表。

| Label | Value | Usage |
|---|---|---|
RuleSet | The package name for the generated DRL file. Optional, the default is rule_table. | Must be the first entry. |
Sequential | true or false. If true, then salience is used to ensure that rules fire from the top down. | Optional, at most once. If omitted, no firing order is imposed. |
SequentialMaxPriority | Integer numeric value | Optional, at most once. In sequential mode, this option is used to set the start value of the salience. If omitted, the default value is 65535. |
SequentialMinPriority | Integer numeric value | Optional, at most once. In sequential mode, this option is used to check if this minimum salience value is not violated. If omitted, the default value is 0. |
EscapeQuotes | true or false. If true, then quotation marks are escaped so that they appear literally in the DRL. | Optional, at most once. If omitted, quotation marks are escaped. |
IgnoreNumericFormat | true or false. If true, then the format for numeric values is ignored, for example, percent and currency. | Optional, at most once. If omitted, DRL takes formatted values. |
Import | A comma-separated list of Java classes to import from another package. | Optional, may be used repeatedly. |
Variables | Declarations of DRL globals (a type followed by a variable name). Multiple global definitions must be separated by commas. | Optional, may be used repeatedly. |
Functions | One or more function definitions, according to DRL syntax. | Optional, may be used repeatedly. |
Queries | One or more query definitions, according to DRL syntax. | Optional, may be used repeatedly. |
Declare | One or more declarative types, according to DRL syntax. | Optional, may be used repeatedly. |
Unit | The rule units that the rules generated from this decision table belong to. | Optional, at most once. If omitted, the rules do not belong to any unit. |
Dialect | java or mvel. The dialect used in the actions of the decision table. | Optional, at most once. If omitted, java is imposed. |
ResultSet:区域只可有一个。
| Label | Or custom label that begins with | Value | Usage |
|---|---|---|---|
NAME | N | Provides the name for the rule generated from that row. The default is constructed from the text following the RuleTable tag and the row number. | At most one column. |
DESCRIPTION | I | Results in a comment within the generated rule. | At most one column. |
CONDITION | C | Code snippet and interpolated values for constructing a constraint within a pattern in a condition. | At least one per rule table. |
ACTION | A | Code snippet and interpolated values for constructing an action for the consequence of the rule. | At least one per rule table. |
METADATA | @ | Code snippet and interpolated values for constructing a metadata entry for the rule. | Optional, any number of columns. |
具体的使用可以见上方的图
在ResultSet和ResultTable这个地方都可以编写规则属性。ResultSet地方的规则属性将影响同一个包下所有的规则,而ResultTable这个地方的规则属性,只影响这个规则。ResultTable的优先级更高。
支持的规则属性有:PRIORITY、DATE-EFFECTIVE、DATE-EXPIRES、NO-LOOP、AGENDA-GROUP、ACTIVATION-GROUP、DURATION、TIMER、CALENDAR、AUTO-FOCUS、LOCK-ON-ACTIVE、RULEFLOW-GROUP。
具体的用法:见上图中ACTIVATION-GROUP的使用。
我们需要根据学生的成绩分数,给出相应的结果。规则如下:
特殊处理的规则:
规则一:只要名字是张三的,直接判定为 优
规则二:只要名字是李四的,如果分数在0,60之间,直接认为是一般
普通规则:
规则三:分数在0,60之间认为是不及格
规则四:分数在60,70之间认为是一般
规则五:分数在70,90之间认为是良好
规则六:分数在90,100之间认为是优
从上方的规则中,我们可以看到姓名为张三和李四的学生特殊处理了。

<dependencyManagement> <dependencies> <dependency> <groupId>org.drools</groupId> <artifactId>drools-bom</artifactId> <type>pom</type> <version>7.69.0.Final</version> <scope>import</scope> </dependency> </dependencies></dependencyManagement><dependencies> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-mvel</artifactId> </dependency> <!-- 决策表 --> <dependency> <groupId>org.drools</groupId> <artifactId>drools-decisiontables</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.11</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> </dependency></dependencies><kmodule xmlns="http://www.drools.org/xsd/kmodule"> <kbase name="kabse" packages="rules.decision.tables" default="false"> <ksession name="ksession" default="false" type="stateful"/> </kbase></kmodule>@Getter@Setter@ToStringpublic class Student { private String name; // 分数只能在 0-100 之间 private Integer score; public Student(String name, Integer score) { this.name = name; if (null == score || score < 0 || score > 100) { throw new RuntimeException("分数只能在0-100之间"); } this.score = score; }}
这步主要是为了查看我们的决策表编写的是否正确,看看最终生成的drl文件是什么样的。
/*** 决策表转换成 drl 文件*/public static void decisionTable2Drl() throws IOException { Resource resource = ResourceFactory.newClassPathResource("rules/decision/tables/student-score.xlsx", "UTF-8"); InputStream inputStream = resource.getInputStream(); SpreadsheetCompiler compiler = new SpreadsheetCompiler(); String drl = compiler.compile(inputStream, InputType.XLS); log.info("决策表转换的drl内容为:\r{}", drl); // 验证一下 drl 文件是否有问题 KieHelper kieHelper = new KieHelper(); Results results = kieHelper.addContent(drl, ResourceType.DRL).verify(); List<Message> messages = results.getMessages(Message.Level.ERROR); if (null != messages && !messages.isEmpty()) { for (Message message : messages) { log.error(message.getText()); } }}package rules.decision.tables;//generated from Decision Tableimport java.lang.StringBuilder;import com.huan.drools.Student;global java.lang.StringBuilder resultsInfo;// rule values at B15, header at B10rule "student-score-name-1"/* 1、姓名为张三的特殊处理2、自定义规则的名字 */ salience 65535 activation-group "score" when $stu: Student(name == "张三") then resultsInfo.append("张三特殊处理:");System.out.println("规则:" + drools.getRule().getName() + " 执行了."); resultsInfo.append("优");System.out.println("规则:" + drools.getRule().getName() + " 执行了.");end// rule values at B16, header at B10rule "student-score_16" salience 65534 activation-group "score" when $stu: Student(name == "李四", score > 0 && score < 60) then resultsInfo.append("李四部分特殊处理:");System.out.println("规则:" + drools.getRule().getName() + " 执行了."); resultsInfo.append("一般");System.out.println("规则:" + drools.getRule().getName() + " 执行了.");end// rule values at B17, header at B10rule "student-score_17" salience 65533 activation-group "score" when $stu: Student(score > 0 && score < 60) then resultsInfo.append("不及格");System.out.println("规则:" + drools.getRule().getName() + " 执行了.");end// rule values at B18, header at B10rule "student-score_18" salience 65532 activation-group "score" when $stu: Student(score > 60 && score < 70) then resultsInfo.append("一般");System.out.println("规则:" + drools.getRule().getName() + " 执行了.");end// rule values at B19, header at B10rule "student-score_19" salience 65531 activation-group "score" when $stu: Student(score > 70 && score < 90) then resultsInfo.append("良好");System.out.println("规则:" + drools.getRule().getName() + " 执行了.");end// rule values at B20, header at B10rule "student-score_20" salience 65530 activation-group "score" when $stu: Student(score > 90 && score < 100) then resultsInfo.append("优");System.out.println("规则:" + drools.getRule().getName() + " 执行了.");end从上方可以看出第一个规则的规则名称是不一样的,而且存在一些描述信息,这个是在决策表中特殊处理了。
package com.huan.drools;import lombok.extern.slf4j.Slf4j;import org.drools.decisiontable.InputType;import org.drools.decisiontable.SpreadsheetCompiler;import org.kie.api.KieServices;import org.kie.api.builder.Message;import org.kie.api.builder.Results;import org.kie.api.io.Resource;import org.kie.api.io.ResourceType;import org.kie.api.runtime.KieContainer;import org.kie.api.runtime.KieSession;import org.kie.internal.io.ResourceFactory;import org.kie.internal.utils.KieHelper;import java.io.IOException;import java.io.InputStream;import java.util.List;/** * drools 决策表的使用 */@Slf4jpublic class DroolsDecisionTableApplication { public static void main(String[] args) throws IOException { decisionTable2Drl(); KieServices kieServices = KieServices.get(); KieContainer kieContainer = kieServices.newKieClasspathContainer(); // 张三虽然只得20分,但是根据规则判断,结果应该是 优 invokedDecisionTable(kieContainer, new Student("张三", 20)); // 李四虽然只得20分,但是根据规则判断,结果应该是 一般 invokedDecisionTable(kieContainer, new Student("李四", 20)); // 李四得75分,但是根据规则判断,结果应该是 良好 invokedDecisionTable(kieContainer, new Student("李四", 75)); // 王五得59分,但是根据规则判断,结果应该是 不及格 invokedDecisionTable(kieContainer, new Student("王五", 59)); // 赵六得20分,但是根据规则判断,结果应该是 一般 invokedDecisionTable(kieContainer, new Student("赵六", 65)); // 钱七得20分,但是根据规则判断,结果应该是 良好 invokedDecisionTable(kieContainer, new Student("钱七", 75)); // 李八得20分,但是根据规则判断,结果应该是 优 invokedDecisionTable(kieContainer, new Student("李八", 95)); } public static void invokedDecisionTable(KieContainer kieContainer, Student student) { System.out.println("\r"); KieSession kieSession = kieContainer.newKieSession("ksession"); StringBuilder result = new StringBuilder(); kieSession.setGlobal("resultsInfo", result); kieSession.insert(student); kieSession.fireAllRules(); kieSession.dispose(); System.out.println("规则执行结果:" + result); } /** * 决策表转换成 drl 文件 */ public static void decisionTable2Drl() throws IOException { Resource resource = ResourceFactory.newClassPathResource("rules/decision/tables/student-score.xlsx", "UTF-8"); InputStream inputStream = resource.getInputStream(); SpreadsheetCompiler compiler = new SpreadsheetCompiler(); String drl = compiler.compile(inputStream, InputType.XLS); log.info("决策表转换的drl内容为:\r{}", drl); // 验证一下 drl 文件是否有问题 KieHelper kieHelper = new KieHelper(); Results results = kieHelper.addContent(drl, ResourceType.DRL).verify(); List<Message> messages = results.getMessages(Message.Level.ERROR); if (null != messages && !messages.isEmpty()) { for (Message message : messages) { log.error(message.getText()); } } }}
从上图中可知,我们的规则都正常执行了。
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-decision-table
1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#decision-tables-con_decision-tables