Springboot整合Drools 规则引擎
1.添加maven 依赖坐标,并创建springboot项目
<!-- drools规则引擎 -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>7.6.0.Final</version>
</dependency>
2.建立相应代码结构
1,创建实体类
@Data
public class Person {
private String names;
private List<String> list;
}
3.在resources文件夹下创建META-INF 文件夹 和rules规则文件夹
META-INF下文件内容
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<!--
name:指定kbase的名称,可以任意,但是需要唯一
packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
default:指定当前kbase是否为默认
-->
<kbase name="myKbase1" packages="rules" default="true">
<!--
name:指定ksession的名称,可以任意,但需要唯一
default:指定当前session是否为默认
-->
<ksession name="ksession-rule" default="true"/>
</kbase>
</kmodule>
Rules文件内容
package people;
import com.drools.demo.domain.Person
import com.drools.demo.service.DemoService
dialect "java" #指定java语言
global DemoService demoService #设置全局变量
/**
* 当前规则用于测试drools提供的操作运算符
activation-group 同组只能又一个执行
salience执行等级 salience 4 数值越大等级越高
*/
// 测试比较操作符contains #规则名称 全局唯一
rule "rule_comparison_contains"
when
Person(names contains "王小白")
then
demoService.test();
end
// 测试比较操作符contains
rule "rule_comparison_not_contains"
when
Person(names not contains "王小白") and
Person(list not contains names)
then
System.out.println("规则:rule_comparison_not_contains触发了...");
end
// 测试比较操作符memberOf
rule "rule_comparison_memberOf"
when
Person(names memberOf list)
then
System.out.println("规则:rule_comparison_memberOf触发了...");
end
// 测试比较操作符not memberOf
rule "rule_comparison_not_memberOf"
when
Person(names not memberOf list)
then
System.out.println("规则:rule_comparison_not_memberOf触发了...");
end
// 测试比较操作符matches
rule "rule_comparison_matches"
when
Person(names matches "王.*") // 正则表达式
then
System.out.println("规则:rule_comparison_matches触发了...");
end
// 测试比较操作符not matches
rule "rule_comparison_not_matches"
when
Person(names not matches "王.*") // 正则表达式
then
System.out.println("规则:rule_comparison_not_matches触发了...");
end
4.代码测试
@RestController
public class TestDemoController {
@Resource
private DemoService demoService;
@GetMapping("one")
public void test(){
KieServices kieServices = KieServices.Factory.get();
// 获取Kie容器对象(默认容器对象
KieContainer kieContainer = kieServices.newKieClasspathContainer();
// 从Kie容器对象中获取会话对象(默认session对象
KieSession kieSession = kieContainer.newKieSession();
kieSession.setGlobal("demoService",demoService);
Person fact = new Person();
String names = "王小白";
fact.setNames(names);
List<String> list = new ArrayList<String>();
list.add("小黑");
list.add("王小白");
list.add(names);
fact.setList(list);
// 将order对象插入工作内存
kieSession.insert(fact);
// 匹配对象
// 激活规则,由drools框架自动进行规则匹配。若匹配成功,则执行
kieSession.fireAllRules();
// 关闭会话
kieSession.dispose();
}
}
Drools基础语法
package:包名,package对应的不⼀定是真正的⽬录,可以任意写com.abc,同⼀个包下的drl⽂ 件可以相互访问
import:⽤于导⼊类或者静态⽅法
global:全局变量
function:⾃定义函数
query:查询
rule end:规则体
规则体语法结构
⼀个规则通常包括三个部分:属性部分(attribute) 、条件部分(LHS)和结果部分(RHS)
rule “ruleName” //rule关键字,表示规则开始,参数为规则的唯⼀名称
attributes //规则属性,是rule与when之间的参数,为可选项
when //关键字,后⾯是规则的条件部分
LHS //Left Hand Side,是规则的条件部分
then //后⾯跟规则的结果部分
RHS //是规则的结果或⾏为
end
条件部分
LHS(Left Hand Side):是规则的条件部分的通⽤名称。它由零个或多个条件元素组成。如果LHS 为空,则它将被视为始终为true的条件元素。
LHS部分由⼀个或者多个条件组成,条件⼜称为pattern。
pattern的语法结构为:绑定变量名:Object(Field约束)
其中绑定变量名可以省略,通常绑定变量名的命名⼀般建议以$开始。如果定义了绑定变量名,就可以
在规则体的RHS部分使⽤此绑定变量名来操作相应的Fact对象。Field约束部分是需要返回true或者false 的0个或多个表达式。
//规则1:100元以下, 不加分
rule “score_1”
when
//⼯作内存中必须存在Order这种类型的Fact对象-----类型约束
//Fact对象的amout属性值必须⼩于等于100------属性约束
$s : Order(amout <= 100)
then
$s.setScore(0);
System.out.println("成功匹配到规则1:100元以下, 不加分 ");
end
如果 LHS 部分为空的话,那么引擎会⾃动添加⼀个 eval(true)的条件,由于该条件总是返回 true,所 以 LHS 为空的规则总是返回 true
1.约束连接
在 LHS 当中,可以包含 0~n 个条件,多个pattern之间可以采⽤“&&” (and) 、 “||”(or)和“,”(and) 来实现,也可以不写,默认连接为and
//规则2:100元-500元 加100分
rule “score_2”
when
$s : Order(amout > 100 && amout <= 500)
then
$s.setScore(100);
System.out.println("成功匹配到规则2:100元-500元 加100分 ");
end
2.⽐较操作符
在 Drools当中共提供了⼗⼆种类型的⽐较操作符, 分别是: >、 >=、 <、 <=、 = =、 !=、
contains、 not contains、memberof、not memberof、matches、not matches;在这⼗⼆种类型的 ⽐较操作符当中,前六个是⽐较常⻅也是⽤的⽐较多的⽐较操作符
示例:
第⼀步:创建实体类,⽤于测试⽐较操作符
package com.demo.entity;
import java.util.List;
public class Customer {
//客户姓名
private String name;
private List<Order> orderList;//订单集合
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Order> getOrderList() {
return orderList;
}
public void setOrderList(List<Order> orderList) {
this.orderList = orderList;
}
}
第⼆步:在/resources/rules下创建规则⽂件customer-rules.drl
package rules
import com.chenj.entity.*;
//测试contains规则
rule "rule1"
when
$order:Order();
$customer:Customer(orderList contains $order);
then
System.out.println("测试contains规则触发:"+$customer.getName());
end
//测试not contains规则
rule "rule2"
when
$order:Order();
$customer:Customer(orderList not contains $order);
then
System.out.println("测试not contains规则触发:"+$customer.getName());
end
//测试⽐较操作符matches
rule "rule3"
when
Customer(name matches "张.*")
then
System.out.println("测试⽐较操作符matches触发...");
end
//测试⽐较操作符not matches
rule "rule4"
when
Customer(name not matches "张.*")
then
System.out.println("测试⽐较操作符not matches触发...");
end
第三步:编写单元测试
@Test
public void test2(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieContainer =
kieServices.getKieClasspathContainer();
//会话对象,⽤于和规则引擎交互
KieSession kieSession = kieContainer.newKieSession();
//构造订单对象,设置订单⾦额,由规则引擎计算获得的积分
Order order = new Order();
//匹配规则:$order:Order();
kieSession.insert(order);
Customer customer = new Customer();
List<Order> orderList = new ArrayList<>();
//匹配规则: $customer:Customer(orderList contains $order);
//orderList.add(order);
customer.setOrderList(orderList);
customer.setName("Jack");
//将数据交给规则引擎,规则引擎会根据提供的数据进⾏规则匹配
kieSession.insert(customer);
//激活规则引擎,如果匹配成功则执⾏规则
kieSession.fireAllRules();
//关闭会话
kieSession.dispose();
}
在 Drools 当中,在 RHS ⾥⾯,提供了⼀些对当前 Working Memory 实现快速操作的宏宏函数或对
象, ⽐如 insert/insertLogical、 update 和 retract 就可以实现对当前 Working Memory中的 Fact
对象进⾏新增、删除或者是修改
1.insert
函数insert的作⽤与我们在Java类当中调⽤StatefulKnowledgeSession对象的insert⽅法的作⽤相同,
都是⽤来将⼀个 Fact 对象插⼊到当前的 Working Memory 当中
需注意:⼀旦调⽤ insert 宏函数,那么 Drools 会重新与所有的规则再重新匹配⼀次, 对于没有设置
no-loop 属性为 true 的规则,如果条件满⾜,不管其之前是否执⾏过都会再执⾏⼀次,这个特性不仅
存在于 insert 宏函数上,后⾯介绍的 update、retract 宏函数同样具有该特性,所以在某些情况下因考
虑不周调⽤ insert、update 或 retract 容易发⽣死循环
//Drools提供的内置⽅法insert
rule “rule5”
when
eval(true); //默认成⽴
then
Customer cus=new Customer();
cus.setName(“张三”);
insert(cus);
System.out.println(“测试Drools提供的内置⽅法insert 触发…”);
end
rule “rule6”
when
c
u
s
t
o
m
e
r
:
C
u
s
t
o
m
e
r
(
n
a
m
e
=
=
"
张三
"
)
;
t
h
e
n
S
y
s
t
e
m
.
o
u
t
.
p
r
i
n
t
l
n
(
"
测试
D
r
o
o
l
s
提供的内置⽅法
i
n
s
e
r
t
触发
.
.
.
"
+
customer:Customer(name =="张三"); then System.out.println("测试Drools提供的内置⽅法insert 触 发..."+
customer:Customer(name=="张三");thenSystem.out.println("测试Drools提供的内置⽅法insert触发..."+customer.getName());
end
测试:
@Test
public void test3(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieContainer =
kieServices.getKieClasspathContainer();
//会话对象,⽤于和规则引擎交互
KieSession kieSession = kieContainer.newKieSession();
//激活规则引擎,如果匹配成功则执⾏规则
kieSession.fireAllRules();
//关闭会话
kieSession.dispose();
}
2.Update
update函数意义与其名称⼀样, ⽤来实现对当前Working Memory当中的 Fact进⾏更新,⽤来告诉当 前的 Working Memory 该 Fact 对象已经发⽣了变化
示例:
rule “rule7”
//no-loop true
when
$customer:Customer(name ==“李四”);
then
c
u
s
t
o
m
e
r
.
s
e
t
N
a
m
e
(
"
张三
"
)
;
u
p
d
a
t
e
(
customer.setName("张三"); update(
customer.setName("张三");update(customer);
System.out.println(“测试Drools提供的内置⽅法update 触发…”);
end
rule “rule8”
when
c
u
s
t
o
m
e
r
:
C
u
s
t
o
m
e
r
(
n
a
m
e
=
=
"
张三
"
)
;
t
h
e
n
S
y
s
t
e
m
.
o
u
t
.
p
r
i
n
t
l
n
(
"
测试
D
r
o
o
l
s
提供的内置⽅法
u
p
d
a
t
e
触发
.
.
.
"
+
customer:Customer(name =="张三"); then System.out.println("测试Drools提供的内置⽅法update 触 发..."+
customer:Customer(name=="张三");thenSystem.out.println("测试Drools提供的内置⽅法update触发..."+customer.getName());
end
测试
@Test
public void test3(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieContainer =
kieServices.getKieClasspathContainer();
//会话对象,⽤于和规则引擎交互
KieSession kieSession = kieContainer.newKieSession();
Customer customer = new Customer();
customer.setName(“李四”);
kieSession.insert(customer);
//激活规则引擎,如果匹配成功则执⾏规则
kieSession.fireAllRules();
//关闭会话
kieSession.dispose();
}
3.retract
retract⽤来将 Working Memory 当中某个 Fact 对象从 Working Memory 当中删除
//Drools提供的内置⽅法retract
rule “rule9”
when
c
u
s
t
o
m
e
r
:
C
u
s
t
o
m
e
r
(
n
a
m
e
=
=
"
李四
"
)
;
t
h
e
n
/
/
r
e
t
r
a
c
t
(
customer:Customer(name =="李四"); then //retract(
customer:Customer(name=="李四");then//retract(customer);
System.out.println(“测试Drools提供的内置⽅法retract 触发…”);
end
rule “rule10”
when
c
u
s
t
o
m
e
r
:
C
u
s
t
o
m
e
r
(
)
;
t
h
e
n
S
y
s
t
e
m
.
o
u
t
.
p
r
i
n
t
l
n
(
"
测试
D
r
o
o
l
s
提供的内置⽅法
r
e
t
r
a
c
t
触发
.
.
.
"
+
customer:Customer(); then System.out.println("测试Drools提供的内置⽅法retract 触 发..."+
customer:Customer();thenSystem.out.println("测试Drools提供的内置⽅法retract触发..."+customer.getName());
end
测试
@Test
public void test3(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieContainer =
kieServices.getKieClasspathContainer();
//会话对象,⽤于和规则引擎交互
KieSession kieSession = kieContainer.newKieSession();
Customer customer = new Customer();
customer.setName(“李四”);
kieSession.insert(customer);
//激活规则引擎,如果匹配成功则执⾏规则
kieSession.fireAllRules();
//通过规则过滤器实现只执⾏指定规则
//kieSession.fireAllRules(new
RuleNameEqualsAgendaFilter(“rule5”));
//关闭会话
kieSession.dispose();
}
属性部分
Drools中提供的属性如下表: