一、Drools高级语法概览
1.1 语法概览
前面章节我们已经知道了一套完整的规则文件内容构成如下:
本章节我们就来学习其中的几个关键字。
二、Drools高级语法讲解
2.1 global全局变量
global关键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能够被访问。可以用来为规则文件提供数据或服务。
语法结构为:global 对象类型 对象名称
在使用global定义的全局变量时有两点需要注意:
- 如果对象类型为包装类型时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。可以理解为它是当前规则代码中的global副本,规则内部修改不会影响全局的使用。
- 如果对象类型为集合类型或JavaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。
2.1.1 代码实现
2.1.1.1 编写规则文件
在/resources/rules下创建规则文件global.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.GlobalEntity
/*
用于测试Drools 属性: global
*/
global java.lang.Integer globalCount
global java.util.List globalList
rule "rule_global_1"
when
$globalEntity:GlobalEntity(num > 1)
then
System.out.println("规则 rule_global_1 开始...");
globalCount++ ;
globalList.add("张三");
globalList.add("李四");
System.out.println(globalCount);
System.out.println(globalList);
System.out.println("规则 rule_global_1 结束...");
end
rule "rule_global_2"
when
$globalEntity:GlobalEntity(num > 1)
then
System.out.println("规则 rule_global_2 开始...");
System.out.println(globalCount);
System.out.println(globalList);
System.out.println("规则 rule_global_2 结束...");
end
2.1.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
/**
* @author ningzhaosheng
* @date 2024/1/19 1:57:34
* @description global 全局变量实体
*/
@Data
public class GlobalEntity {
private Integer num;
}
2.1.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.GlobalEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
import java.util.ArrayList;
/**
* @author ningzhaosheng
* @date 2024/1/19 1:59:18
* @description global 全局变量测试类
*/
public class GlobalTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
GlobalEntity globalEntity = new GlobalEntity();
globalEntity.setNum(20);
ArrayList<Object> globalList = new ArrayList<>();
Integer globalCount = 10;
kieSession.setGlobal("globalCount", 10);
kieSession.setGlobal("globalList", globalList);
kieSession.insert(globalEntity);
kieSession.fireAllRules();
kieSession.dispose();
System.out.println("globalCount=" + globalCount);
System.out.println("globalList=" + globalList);
}
}
2.1.1.4 测试结果
注意:
- 后面的代码中定义了全局变量以后,前面的test都需要加,不然会出错。
- 需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.2 query查询
query查询提供了一种查询working memory中符合约束条件的Fact对象的简单方法。它仅包含规则文件中的LHS部分,不用指定“when”和“then”部分并且以end结束。具体语法结构如下:
query 查询的名称(可选参数)
LHS
end
2.2.1 代码实现
2.2.1.1 编写规则文件
在/resources/rules下创建规则文件query.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.QueryEntity
/*
用于测试Drools 方法: query
*/
//无参查询
query "query_1"
$queryEntity:QueryEntity(age>20)
end
//有参查询
query "query_2"(Integer qAge,String qName)
$queryEntity:QueryEntity(age > qAge && name == qName)
end
2.2.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 11:08:28
* @description query 查询实体
*/
@Data
@Accessors(chain = true)
public class QueryEntity {
private String name;
private Integer age;
}
2.2.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.QueryEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 11:06:12
* @description query 语法测试类
*/
public class QueryTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
QueryEntity queryEntity1 = new QueryEntity();
QueryEntity queryEntity2 = new QueryEntity();
QueryEntity queryEntity3 = new QueryEntity();
queryEntity1.setName("张三").setAge(10);
queryEntity2.setName("李四").setAge(20);
queryEntity3.setName("王五").setAge(30);
kieSession.insert(queryEntity1);
kieSession.insert(queryEntity2);
kieSession.insert(queryEntity3);
QueryResults results1 = kieSession.getQueryResults("query_1");
QueryResults results2 = kieSession.getQueryResults("query_2", 1, "张三");
for (QueryResultsRow queryResultsRow : results1) {
QueryEntity queryEntity = (QueryEntity) (queryResultsRow.get("$queryEntity"));
System.out.println("query_1" + queryEntity);
}
for (QueryResultsRow queryResultsRow : results2) {
QueryEntity queryEntity = (QueryEntity) (queryResultsRow.get("$queryEntity"));
System.out.println("query_2" + queryEntity);
}
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.2.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.3 function函数
function关键字用于在规则文件中定义函数,就相当于java类中的方法一样。可以在规则体中调用定义的函数。使用函数的好处是可以将业务逻辑集中放置在一个地方,根据需要可以对函数进行修改。
函数定义的语法结构如下:
function 返回值类型 函数名(可选参数){ //逻辑代码}
2.3.1 代码实现
2.3.1.1 编写规则文件
在/resources/rules下创建规则文件function.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.FunctionEntity
/*
用于测试Drools 方法: function
*/
//定义一个 加法 方法
function Integer add(Integer num){
return num+10;
}
rule "function"
when
$functionEntity:FunctionEntity(num>20)
then
Integer result = add($functionEntity.getNum());
System.out.println(result);
end
2.3.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
/**
* @author ningzhaosheng
* @date 2024/1/19 11:28:46
* @description function 函数规则实体
*/
@Data
public class FunctionEntity {
private Integer num;
}
2.3.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.FunctionEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 11:30:15
* @description function函数测试类
*/
public class FunctionTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
FunctionEntity functionEntity = new FunctionEntity();
functionEntity.setNum(30);
kieSession.insert(functionEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.3.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.4 条件-LHS加强
前面我们已经知道了在规则体中的LHS部分是介于when和then之间的部分,主要用于模式匹配,只有匹配结果为true时,才会触发RHS部分的执行。本章节我们会针对LHS部分学习几个新的用法。
2.4.1 复合值限制in/not in
复合值限制是指超过一种匹配值的限制条件,类似于SQL语句中的in关键字。Drools规则体中的LHS部分可以使用in或者not in进行复合值的匹配。具体语法结构如下:
Object(field in (比较值1,比较值2...))
2.4.1.1 代码实现
2.4.1.1.1 编写规则文件
在/resources/rules下创建规则文件lhs-in.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.LhsInEntity
/*
用于测试Drools LHS: in not in
*/
rule "lhs_in"
when
$lhsInEntity:LhsInEntity(name in ("张三","李四","王五"))
then
System.out.println("规则 lhs_in 触发");
end
rule "lhs_not_in"
when
$lhsInEntity:LhsInEntity(name not in ("张三","李四","王五"))
then
System.out.println("规则 lhs_not_in 触发");
end
2.4.1.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 11:45:12
* @description in / not in 语法对象
*/
@Data
@Accessors(chain = true)
public class LhsInEntity {
private String name;
private Integer age;
}
2.4.1.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.LhsInEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 11:43:24
* @description in/not in 测试类
*/
public class LhsInTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
LhsInEntity lhsInEntity = new LhsInEntity();
lhsInEntity.setName("张三");
//lhsInEntity.setName("马六");
kieSession.insert(lhsInEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.4.1.1.4 测试结果
测试张三,在in 规则里面,所以触发了lhs_in规则。下面我们换下,测试“马六”。
“马六”不在lhs_in规则里面,所以触发了lhs_not_in规则。
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.4.2 条件元素eval
eval用于规则体的LHS部分,并返回一个Boolean类型的值。语法结构如下:
eval(表达式)
2.4.2.1 代码实现
2.4.2.1.1 编写规则文件
在/resources/rules下创建规则文件lhs-eval.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.LhsEvalEntity
/*
用于测试Drools LHS: eval
*/
rule "lhs_eval"
when
$lhsInEntity:LhsEvalEntity(age > 10) and eval(2>1)
then
System.out.println("规则 lhs_eval 触发");
end
2.4.2.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 12:20:21
* @description eval 实体对象
*/
@Data
@Accessors(chain = true)
public class LhsEvalEntity {
private Integer age;
}
2.4.2.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.LhsEvalEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 12:21:35
* @description eval 测试类
*/
public class LhsEvalTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
LhsEvalEntity lhsEvalEntity = new LhsEvalEntity();
lhsEvalEntity.setAge(20);
kieSession.insert(lhsEvalEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.4.2.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.4.3 条件元素not
not用于判断Working Memory中是否存在某个Fact对象,如果不存在则返回true,如果存在则返回false。语法结构如下:
not Object(可选属性约束)
2.4.3.1 代码实现
2.4.3.1.1 编写规则文件
在/resources/rules下创建规则文件lhs-not.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.LhsNotEntity
/*
用于测试Drools LHS: not
*/
rule "lhs_not"
when
not $lhsNotEntity:LhsNotEntity(age > 10)
then
System.out.println("规则 lhs_not 触发");
end
2.4.3.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 15:30:02
* @description not 条件元素实体
*/
@Data
@Accessors(chain = true)
public class LhsNotEntity {
private Integer age;
}
2.4.3.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.LhsNotEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 15:28:31
* @description not 条件元素测试类
*/
public class LhsNotTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test(){
KieSession kieSession = kieBase.newKieSession();
LhsNotEntity lhsNotEntity = new LhsNotEntity();
lhsNotEntity.setAge(1);
kieSession.insert(lhsNotEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.4.3.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.4.4 条件元素exists
exists的作用与not相反,用于判断Working Memory中是否存在某个Fact对象,如果存在则返回true,不存在则返回false。语法结构如下:
exists Object(可选属性约束)
2.4.4.1 代码实现
2.4.4.1.1 编写规则文件
在/resources/rules下创建规则文件lhs-exists.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.LhsExistsEntity
/*
用于测试Drools LHS: exists
*/
rule "lhs_exists_1"
when
exists $lhsExistsEntity:LhsExistsEntity(age > 10)
then
System.out.println("规则 lhs_exists_1 触发");
end
rule "lhs_exists_2"
when
$lhsExistsEntity:LhsExistsEntity(age > 10)
then
System.out.println("规则 lhs_exists_2 触发");
end
2.4.4.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 15:40:35
* @description exists 条件元素实体
*/
@Data
@Accessors(chain = true)
public class LhsExistsEntity {
private Integer age;
}
2.4.4.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.LhsExistsEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 15:42:30
* @description exists 条件元素测试类
*/
public class LhsExistsTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
LhsExistsEntity lhsExistsEntity = new LhsExistsEntity();
lhsExistsEntity.setAge(30);
LhsExistsEntity lhsExistsEntity2 = new LhsExistsEntity();
lhsExistsEntity2.setAge(30);
kieSession.insert(lhsExistsEntity);
kieSession.insert(lhsExistsEntity2);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.4.4.1.4 测试结果
上面第一个规则只会执行一次,因为Working Memory中存在两个满足条件的Fact对象,第二个规则会执行两次。
可能有人会有疑问,我们前面在LHS部分进行条件编写时并没有使用exists也可以达到判断Working Memory中是否存在某个符合条件的Fact元素的目的,那么我们使用exists还有什么意义?
两者的区别:当向Working Memory中加入多个满足条件的Fact对象时,使用了exists的规则执行一次,不使用exists的规则会执行多次。
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.4.5 规则继承
规则之间可以使用extends关键字进行规则条件部分的继承,类似于java类之间的继承。
2.4.5.1 代码实现
2.4.5.1.1 编写规则文件
在/resources/rules下创建规则文件lhs-extends.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.LhsExtendsEntity
/*
用于测试Drools LHS: extends
*/
rule "lhs_extends_1"
when
$lhsExtendsEntity:LhsExtendsEntity(age > 10)
then
System.out.println("规则 lhs_extends_1 触发");
end
rule "lhs_extends_2" extends "lhs_extends_1"
when
LhsExtendsEntity(age < 20)
then
System.out.println("规则 lhs_extends_2 触发");
end
2.4.5.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 16:02:12
* @description extends 规则继承实体对象
*/
@Data
@Accessors(chain = true)
public class LhsExtendsEntity {
private Integer age;
}
2.4.5.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.LhsExtendsEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 16:00:10
* @description extends 继承规则测试类
*/
public class LhsExtendsTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
LhsExtendsEntity lhsExtendsEntity = new LhsExtendsEntity();
lhsExtendsEntity.setAge(15);
kieSession.insert(lhsExtendsEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.4.5.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.5 结果-RHS
规则文件的 RHS 部分的主要作用是通过**插入,删除或修改工作内存中的Fact数据**,来达到控制规则引擎执行的目的。Drools提供了一些方法可以用来操作工作内存中的数据,**操作完成后规则引擎会重新进行相关规则的匹配**,原来没有匹配成功的规则在我们修改数据完成后有可能就会匹配成功了。
2.5.1 insert方法
insert方法的作用是向工作内存中插入数据,并让相关的规则重新匹配。
2.5.1.1 代码实现
2.5.1.1.1 编写规则文件
在/resources/rules下创建规则文件rhs-insert.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.RhsInsertEntity
/*
用于测试Drools RHS: insert
*/
rule "rhs_insert_1"
when
$rhsInsertEntity:RhsInsertEntity(age <= 10)
then
RhsInsertEntity rhsInsertEntity = new RhsInsertEntity();
rhsInsertEntity.setAge(15);
insert(rhsInsertEntity);
System.out.println("规则 rhs_insert_1 触发");
end
rule "rhs_insert_2"
when
$rhsInsertEntity:RhsInsertEntity(age <=20 && age>10)
then
RhsInsertEntity rhsInsertEntity = new RhsInsertEntity();
rhsInsertEntity.setAge(25);
insert(rhsInsertEntity);
System.out.println("规则 rhs_insert_2 触发");
end
rule "rhs_insert_3"
when
$rhsInsertEntity:RhsInsertEntity(age > 20 )
then
System.out.println("规则 rhs_insert_3 触发");
end
2.5.1.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 16:39:38
* @description insert 方法实体
*/
@Data
@Accessors(chain = true)
public class RhsInsertEntity {
private Integer age;
}
2.5.1.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.RhsInsertEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 16:41:18
* @description insert 方法测试类
*/
public class RhsInsertTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
RhsInsertEntity rhsInsertEntity = new RhsInsertEntity();
rhsInsertEntity.setAge(5);
kieSession.insert(rhsInsertEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.5.1.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.5.2 update方法
update方法的作用是更新工作内存中的数据,并让相关的规则重新匹配。 (注意要避免死循环)
2.5.2.1 代码实现
2.5.2.1.1 编写规则文件
在/resources/rules下创建规则文件rhs-update.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.RhsUpdateEntity
/*
用于测试Drools RHS: update
*/
rule "rhs_update_1"
when
$rhsUpdateEntity:RhsUpdateEntity(age <= 10)
then
$rhsUpdateEntity.setAge(15);
update($rhsUpdateEntity);
System.out.println("规则 rhs_update_1 触发");
end
rule "rhs_update_2"
when
$rhsUpdateEntity:RhsUpdateEntity(age <=20 && age>10)
then
$rhsUpdateEntity.setAge(25);
update($rhsUpdateEntity);
System.out.println("规则 rhs_update_2 触发");
end
rule "rhs_update_3"
when
$rhsUpdateEntity:RhsUpdateEntity(age > 20 )
then
System.out.println("规则 rhs_update_3 触发");
end
2.5.2.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 17:00:46
* @description update方法实体
*/
@Data
@Accessors(chain = true)
public class RhsUpdateEntity {
private Integer age;
}
2.5.2.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.RhsUpdateEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 16:59:27
* @description update 方法测试类
*/
public class RhsUpdateTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
RhsUpdateEntity rhsUpdateEntity = new RhsUpdateEntity();
rhsUpdateEntity.setAge(5);
kieSession.insert(rhsUpdateEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.5.2.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.5.3 modify方法
modify方法的作用跟update一样,是更新工作内存中的数据,并让相关的规则重新匹配。只不过语法略有区别 (要注意避免死循环)
2.5.3.1 代码实现
2.5.1.3.1 编写规则文件
在/resources/rules下创建规则文件rhs-modify.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.RhsModifyEntity
/*
用于测试Drools RHS: modify
*/
rule "rhs_modify_1"
when
$rhsModifyEntity:RhsModifyEntity(age <= 10)
then
modify($rhsModifyEntity){
setAge(15)
}
System.out.println("规则 rhs_modify_1 触发");
end
rule "rhs_modify_2"
when
$rhsModifyEntity:RhsModifyEntity(age <=20 && age>10)
then
modify($rhsModifyEntity){
setAge(25)
}
System.out.println("规则 rhs_modify_2 触发");
end
rule "rhs_modify_3"
when
$rhsModifyEntity:RhsModifyEntity(age > 20 )
then
System.out.println("规则 rhs_modify_3 触发");
end
2.5.3.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/19 17:12:15
* @description modify 方法实体
*/
@Data
@Accessors(chain = true)
public class RhsModifyEntity {
private Integer age;
}
2.5.3.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.RhsModifyEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/19 17:13:56
* @description modify 方法测试类
*/
public class RhsModifyTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
RhsModifyEntity rhsModifyEntity = new RhsModifyEntity();
rhsModifyEntity.setAge(5);
kieSession.insert(rhsModifyEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.5.3.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.5.4 retract/delete方法
retract方法的作用是删除工作内存中的数据,并让相关的规则重新匹配。
2.5.4.1 代码实现
2.5.4.1.1 编写规则文件
在/resources/rules下创建规则文件rhs-retract.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.RhsRetractEntity
/*
用于测试Drools RHS: retract
*/
rule "rhs_retract_1"
when
$rhsRetractEntity:RhsRetractEntity(age <= 10)
then
// retract($rhsRetractEntity);
delete($rhsRetractEntity);
System.out.println("规则 rhs_retract_1 触发");
end
rule "rhs_retract_2"
when
$rhsRetractEntity:RhsRetractEntity(age <= 10)
then
System.out.println("规则 rhs_retract_2 触发");
end
2.5.4.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/20 15:21:44
* @description retract 方法实体
*/
@Data
@Accessors(chain = true)
public class RhsRetractEntity {
private Integer age;
}
2.5.4.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.RhsRetractEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/20 15:19:48
* @description retract 方法测试类
*/
public class RhsRetractTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
RhsRetractEntity rhsRetractEntity = new RhsRetractEntity();
rhsRetractEntity.setAge(5);
kieSession.insert(rhsRetractEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.5.4.1.4 测试结果
通过控制台输出可以发现,只有第一个规则触发了,因为在第一个规则中将工作内存中的数据删除了导致第二个规则并没有匹配成功。
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.6 RHS加强
RHS部分是规则体的重要组成部分,当LHS部分的条件匹配成功后,对应的RHS部分就会触发执行。一般在RHS部分中需要进行业务处理。
在RHS部分Drools为我们提供了一个内置对象,名称就是drools。本小节我们来介绍几个drools对象提供的方法。
2.6.1 halt
halt方法的作用是立即终止后面所有规则的执行。
2.6.1.1 代码实现
2.6.1.1.1 编写规则文件
在/resources/rules下创建规则文件rhs-haft.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.RhsHaftEntity
/*
用于测试Drools RHS: haft
*/
rule "rhs_haft_1"
when
$rhsHaftEntity:RhsHaftEntity(age <= 10)
then
drools.halt();
System.out.println("规则 rhs_haft_1 触发");
end
rule "rhs_haft_2"
when
$rhsHaftEntity:RhsHaftEntity(age <= 20)
then
System.out.println("规则 rhs_haft_2 触发");
end
2.6.1.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/20 15:32:44
* @description haft 实体对象
*/
@Data
@Accessors(chain = true)
public class RhsHaftEntity {
private Integer age;
}
2.6.1.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.RhsHaftEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/20 15:34:22
* @description haft 测试类
*/
public class RhsHaftTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
RhsHaftEntity rhsHaftEntity = new RhsHaftEntity();
rhsHaftEntity.setAge(5);
kieSession.insert(rhsHaftEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.6.1.1.4 测试结果
我们发现,其实满足条件的规则有两条,但是由于我们在规则一中执行了drools.halt();终止了后续的执行,所以规则二没有触发执行。
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.6.2 getWorkingMemory
getWorkingMemory方法的作用是返回工作内存对象。
2.6.2.1 代码实现
2.6.2.1.1 编写规则文件
在/resources/rules下创建规则文件rhs-drools-methods.drl,文件内容如下:
package rules
import com.ningzhaosheng.drools.entity.RhsDroolsMethodsEntity
/*
用于测试Drools RHS: getworkingmemory
*/
rule "rhs_get_working_memory_1"
when
$rhsDroolsMethodsEntity:RhsDroolsMethodsEntity(age <= 10)
then
System.out.println(drools.getWorkingMemory());
System.out.println("规则 rhs_get_working_memory_1 触发");
end
rule "rhs_rule_2"
when
$rhsDroolsMethodsEntity:RhsDroolsMethodsEntity(age <=20)
then
System.out.println(drools.getRule());
System.out.println("规则 rhs_rule_2 触发");
end
2.6.2.1.2 编写规则实体对象
package com.ningzhaosheng.drools.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/20 15:51:13
* @description getworkingmemory 方法实体
*/
@Data
@Accessors(chain = true)
public class RhsDroolsMethodsEntity {
private Integer age;
}
2.6.2.1.3 编写测试类
package com.ningzhaosheng.drools.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.entity.RhsDroolsMethodsEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/20 15:52:51
* @description getworkingmemory 方法测试类
*/
public class RhsDroolsMethodsTest extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void test() {
KieSession kieSession = kieBase.newKieSession();
RhsDroolsMethodsEntity rhsDroolsMethodsEntity = new RhsDroolsMethodsEntity();
rhsDroolsMethodsEntity.setAge(5);
kieSession.insert(rhsDroolsMethodsEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2.6.2.1.4 测试结果
注意:需要在VM参数上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,不然执行测试用例会报错。在生产环境所在规则引擎的JVM设置中,也需要设置此参数,以保证开发和生产的一致性。
2.6.3 getRule
getRule方法的作用是返回规则对象。
2.6.3.1 代码实现
rule "rhs_rule_2"
when
$rhsDroolsMethodsEntity:RhsDroolsMethodsEntity(age <=20)
then
System.out.println(drools.getRule());
System.out.println("规则 rhs_rule_2 触发");
end
具体参考上一小节3.6.2中的规则文件和相关实现代码。