1. Background
In the previous articles, our business rules were written in the drl
file. This is no problem for developers. If it is a business person, it is not very friendly. In this article, we are simple Learn about the use of decision tables in drools
3b9f6640035898cf4a82ca223d40037f---. The rules are written in the excel
file.
2. A simple decision table
In the above picture ResultSet
and ResultTable
are required, and in the same package, we'd better upload only one decision table.
1. Process multiple Sheet pages in the same decision table
2. What properties can be found under RuleSet
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
: There can be only one area.
3. What properties can be found under RuleTable
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. |
具体的使用可以见上方的图
4. Writing rule attributes
Rule attributes can be written in both ResultSet
and ResultTable
. ResultSet
The rule attribute of this place will affect all rules under the same package, and ResultTable
The rule attribute of this place will only affect this rule. ResultTable
has higher priority.
支持的规则属性有: PRIORITY
、 DATE-EFFECTIVE
、 DATE-EXPIRES
、 NO-LOOP
、 AGENDA-GROUP
、 ACTIVATION-GROUP
、 DURATION
、 TIMER
、 CALENDAR
、 AUTO-FOCUS
、 LOCK-ON-ACTIVE
、 RULEFLOW-GROUP
.
Specific usage: see the usage of ACTIVATION-GROUP
in the picture above.
3. Demand
We need to give corresponding results based on the students' grades. The rules are as follows:
特殊处理的规则:
Rule 1: As long as the name is 张三
, 直接判定为 优
Rule 2: As long as the name is 李四
, if it is between 分数在0,60
, it is directly regarded as 一般
普通规则:
Rule 3: A score between 0,60
is considered to be 不及格
Rule 4: A score between 60,70
is considered to be 一般
Rule 5: A score between 70,90
is considered to be 良好
Rule 6: A score between 90,100
is considered to be 优
From the rules above, we can see that students with the names 张三
and 李四
are treated specially.
4. Realization
1. Project realization structure diagram
2. Import jar package
<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>
3. Write the kmodule.xml file
<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>
4. Write the student entity class
@Getter
@Setter
@ToString
public 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;
}
}
5. Write a decision table
6. Convert decision table to drl file
这步主要是为了查看我们的决策表编写的是否正确,看看最终生成的drl文件是什么样的
.
1. Convert decision table to drl file code
/**
* 决策表转换成 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());
}
}
}
2. Convert into a specific drl file as
package rules.decision.tables;
//generated from Decision Table
import java.lang.StringBuilder;
import com.huan.drools.Student;
global java.lang.StringBuilder resultsInfo;
// rule values at B15, header at B10
rule "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 B10
rule "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 B10
rule "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 B10
rule "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 B10
rule "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 B10
rule "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
It can be seen from the above that the 第一个规则
of 规则名称
is different, and there is some descriptive information, which is specially handled in the decision table.
7. Test
1. Write test code
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 决策表的使用
*/
@Slf4j
public 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());
}
}
}
}
2. Test results
As can be seen from the above figure, our rules are executed normally.
5. Complete code
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-decision-table
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。