drools入门-02

一、 另一种方式

上一篇我们讲了一下基本理论和入门demo,这一篇我们接着讲

我们用springboot另一种方式整合(这个比较常用)

1. 引入依赖
<!-- 规则引擎 -->
<dependency><groupId>org.kie</groupId><artifactId>kie-spring</artifactId><version>7.17.0.Final</version><exclusions><exclusion><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></exclusion><exclusion><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></exclusion><exclusion><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></exclusion><exclusion><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></exclusion></exclusions>
</dependency>
2. 自动配置类

首先注意:这段代码,万年不变,所以大家可以拷贝直接用。

KieFileSystem:用于加载规则引擎文件

我们看一下下边这几个类的关系:

KieServices.Factory 创建 KieServices

KieServices 创建 KieBuilder

KieBuilder 创建 KieContainer

KieContainer 创建 KieBase

KieBase 创建 KieSession

package com.example.droolstest02.config;import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;import java.io.IOException;/*** @author 木子的昼夜编程*/
@Configuration
public class DroolsAutoConfiguration {private static final String RULES_PATH = "rules/";// 注入KieServices@Bean@ConditionalOnMissingBean(KieServices.class)public KieServices getKieServices() {return KieServices.Factory.get();}// 加载规则文件使用// 注意:一般而言,你放到resource下边的规则文件,每当执行一个规则匹配的时候,他会全部的扫描一遍。// 而不是每一个文件写一个kieFileSystem来加载@Bean@ConditionalOnMissingBean(KieFileSystem.class)public KieFileSystem kieFileSystem() throws IOException {KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();for (Resource file : getRuleFiles()) {kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));}return kieFileSystem;}private Resource[] getRuleFiles() throws IOException {ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");}// 注入KieContainer@Bean@ConditionalOnMissingBean(KieContainer.class)public KieContainer kieContainer() throws IOException {final KieRepository kieRepository = getKieServices().getRepository();kieRepository.addKieModule(() -> kieRepository.getDefaultReleaseId());KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());kieBuilder.buildAll();KieContainer kieContainer = getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());return kieContainer;}// 注入 KieBase@Bean@ConditionalOnMissingBean(KieBase.class)public KieBase kieBase() throws IOException {return kieContainer().getKieBase();}
}
3. 使用

我们上一篇已经写了Order.java 和 User.java 还有一个drl文件,这篇就不赘述了,不了解的可以去看上一篇。

这里我们就直接使用:

我们可以看到,除了创建session方式变了,其他代码一点没变。

package com.example.droolstest02;import com.example.droolstest02.entity.Order;
import com.example.droolstest02.entity.User;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;@SpringBootTest
class DroolsTest02ApplicationTests {@AutowiredKieBase kieBase;// 测试@Testpublic void droolsOrderTest() throws Exception {KieSession kieSession = kieBase.newKieSession();List<Order> orderList = getInitData();for (Order order: orderList) {// 1-规则引擎处理逻辑kieSession.insert(order);kieSession.fireAllRules();// 2-执行完规则后, 执行相关的逻辑addScore(order);}kieSession.dispose();}private static void addScore(Order o){System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());}// 初始化数据(模拟数据库获取的数据)private static List<Order> getInitData(){List<Order> orderList = new ArrayList<>();DateFormat df = new SimpleDateFormat("yyyy-MM-dd");// 张三买东西{Order order = new Order();order.setPrice(80);User user = new User();user.setName("张三");order.setUser(user);order.setScore(111);orderList.add(order);}// 李四买东西{Order order = new Order();order.setPrice(200);User user = new User();user.setName("李四");order.setUser(user);orderList.add(order);}// 王五买东西{Order order = new Order();order.setPrice(800);User user = new User();user.setName("王五");order.setUser(user);orderList.add(order);}// 孙子买东西{Order order = new Order();order.setPrice(1500);User user = new User();user.setName("孙子");order.setUser(user);orderList.add(order);}return orderList;}}

二、简单唠唠

1. drools组成及概念

Working Memory:

工作内存,drools规则引擎会从Working Memory中获取数据并和规则文件中定义的规则进行模式匹配,所以我们开发的时候仅需要把我们的业务数据插入到Working Memory中即可。

我们案例中的:kieSession.insert(order); 就是将对象order插入到工作内存中

Fact:

实时,是指drools规则应用中,将一个普通的JavaBean插入到Working Memory后的对象就是Facts对象,我们示例中的Order对象就是Fact对象

Rules:

规则,我们编写的规则文件,一个rule必须有一个触发它的conditon,以及触发后的action,其实就是if…than的意思。

Product Memory:

规则库,Drools引擎会将所有的规则Rules放到这个空间内。

规则库,我们在规则文件中定义的规则都会被加载到规则库中

Pattern Matcher:

模式匹配,这个就是drools引擎帮我们做的事情了,也是最伟大的事情,把我们的Fact与Rule进行匹配。匹配成功的规则会被放到Agenda中。

Agenda:

议程,存放经过模式匹配,成功激活的规则,也就是if条件符合的规则。

2.KIE介绍

Kie全称为Knowlege Is Everything ,即“知识就是一切”的缩写,我们可以看到,外国人也喜欢高一些看似高大上的东西命名,Kie是Jboos一系列项目的总称。官网描述:这个名字渗透在GitHub账户和Maven POMs中。随着范围扩大和新项目的开展,KIE被选为新的组名。KIE的名字被用于系统的共享方面;如统一构建、部署和使用。

讲实话,不知道说了一堆啥意思,就知道他是一个英文单词缩写就行,这个几个英文单词还怪有意思的。

三、规则文件开发

其他的都是浮云,这个才是重点。

我们多多少少都接过别人一些旧项目,第一步肯定是搭建环境,启动项目。就好比我们写drools的入门案例。

然后等项目熟悉之后就是那些繁琐、复杂的业务代码了,就好比我们的规则文件开发。

在这里还是老早之前说过的一句话,这些内容不是需要背过的,只是需要了解,在你遇到某些业务的时候,你能想到,我记得drools处理类似业务很简单,我们是不是需要引入呢?

1. 规则文件构成

在使用Drools时非常重要的一个工作就是编写规则文件,通常我们用的是xxx.drl(当然还支持其他的文件格式,我们之前有聊过)

drl是Drools Rule Language 缩写。

规则文件内容结构如下:

关键字 描述
package 包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用
import 用于导入类或者静态方法
global 全局变量
function 自定义函数
query 查询
rule end 规则体
2. 规则体语法结构

规则体是规则文件内容中的重要组成部分,是进行业务规则判断、处理业务结果的部分。

规则体语法结构如下:

rue "规则名称"attributeswhenLHSthenRHS
end

rule: 关键字,表示规则开始,参数为规则的唯一名称(规则名称)。

attribute: 规则属性,是rule与when之间的参数,为可选项。

when: 关键字,后面跟规则的条件部分

LHS(Left Hand Side): 是规则的条件部分的通用名称,他由0个或多个条件组成。

如果LHS为空,则他将被视为始终为true的条件元素。(左手边)

then: 关键字,后边跟规则的结果部分

RHS(Right Hand Side): 是规则的后果或行动部分的通用名称,就是如果符合LHS后需要做什么动作。(右手边)

end: 关键字,表示一个规则结束。

我们可以类比成if…else ,说到底不就是把if…else放到了规则文件嘛。

// if 类比 when
// 100 > 10 类比 LHS
// 条件为true 类比 then
// System.out.println("100 > 10"); 类比 RHS
// } 类比 end
if (100 > 10) {System.out.println("100 > 10");
}
3. 注释

单行注释://

多行注释:/**/

// 添加500分
rule "add500"no-loop truelock-on-active truesalience 1when$order : Order(price > 500 && price <= 1000)then$order.setScore(500);update($order)
end
/*如果大于1000 就加1000分*/
rule "add1000"no-loop truelock-on-active truesalience 1when$order : Order(price > 1000)then$order.setScore(1000);update($order)
end
4. Pattern模式匹配

前面我们了解了Drools中的匹配器可以将Rule Base中的所有规则和Fact对象进行模式匹配,我们需要在规则体的LHS部分进行规则的定义,然后进行模式匹配。LHS部分由1个或者多个条件组成,我们又称之为:pattern

pattern的语法结构为:绑定变量名:Object(Filed约束)

其中绑定变量名可以省略,通常建议绑定变量名以$开头。

如果定义了绑定变量名,就可以在规则体的RHS部分直接使用此绑定的变量名来操作相应的Fact对象。

Filed约束部分需要返回true或者false的0个或者多个表达式。

例如我们的例子中:

rule "add100"no-loop truelock-on-active truesalience 1when$order : Order(price > 100 && price <= 500)then$order.setScore(100);update($order)
end

$order: 定义绑定变量名

  1. 工作内存必须存在Order这种类型的Fact对象 – 类型约束

  2. Fact对象的Price属性必须大于100 – 属性约束

  3. Fact对象的Price属性必须小于等于500 – 属性约束

  4. 可以在RHS中直接使用绑定变量名 $order.setScore(100);

    满足条件1、2、3 这个规则才会被激活。

绑定变量可以用在对象上,也可以用在对象的属性上。例如:

// 编写规则
rule "add0"no-loop truelock-on-active truesalience 1when$order : Order($price001:price <= 100)thenSystem.out.println($price001);$order.setScore(0);update($order)
end

LHS 部分还可以定义多个pattern,多个pattern之间可以使用and或者or进行连接,也可以不写,默认连接为and

// 编写规则
rule "add0"no-loop truelock-on-active truesalience 1when$order : Order(price <= 100)$user : User(name == "张三")thenSystem.out.println("就是为了测试");
end

上边的等同于:

可以看到只加了一个and,因为默认是and

// 编写规则
rule "add0"no-loop truelock-on-active truesalience 1when$order : Order(price <= 100)  and$user : User(name == "张三")thenSystem.out.println("就是为了测试");
end
5. 比较符

drools提供很多个比较符操作:

符号 说明
> 大于
< 小于
>= 大于等于
<= 小于等于
== 等于
!= 不等于
contains 检查一个fact对象的某个属性值是否包含一个指定的对象值
not contains 不包含
memberOf 判断一个fact对象的某个属性是否存在一个或多个集合中
not memberOf 不存在集合
matchs 用Fact对象的某个属性与提供的标准的Java正则表达式进行匹配
not matchs 不匹配

前边大于、小于、大于等于、小于等于、等于、不等于 就不聊了

我们聊一下后边几个:

注意:如果我们启动报错了,一般不是代码写错了,而是规则文件错了,比如规则名称重复等等 。

TestEntity.java

package com.example.droolstest02.entity;import lombok.Builder;
import lombok.Data;
import lombok.ToString;import java.util.List;/*** @author 木子的昼夜编程*/
@Data
@Builder
@ToString
public class TestEntity {List<String> list;String[] arr;String names;
}

resource/rules/comparison-rules.drl

package rules;// 引入实体
import com.example.droolstest02.entity.TestEntity;// 编写规则
rule "rule_test_contains"no-loop truelock-on-active truesalience 1when// 字符串$test : TestEntity(names contains "张三") and// 集合 包含TestEntity(list contains names) and// 数组包含TestEntity(arr contains names)thenSystem.out.println("rule_test_contains-->对象值:"+$test);
endrule "rule_test_not_contains"no-loop truelock-on-active truesalience 1when// 字符串$test : TestEntity(names not contains "张三") and// 集合 包含TestEntity(list not contains names) and// 数组包含TestEntity(arr not contains names)thenSystem.out.println("rule_test_not_contains-->对象值:"+$test);
endrule "rule_test_memberOf"no-loop truelock-on-active truesalience 1when// 字符串$test : TestEntity(names memberOf list) and// 集合 包含TestEntity(names memberOf arr)thenSystem.out.println("rule_test_memberOf-->对象值:"+$test);
endrule "rule_test_not_memberOf"no-loop truelock-on-active truesalience 1when// 字符串$test : TestEntity(names not memberOf list) and// 集合 包含TestEntity(names not memberOf arr)thenSystem.out.println("rule_test_not_memberOf-->对象值:"+$test);
endrule "rule_test_matches"no-loop truelock-on-active truesalience 1when// 字符串$test : TestEntity(names matches "张.*")thenSystem.out.println("rule_test_matches-->对象值:"+$test);
endrule "rule_test_not_matches"no-loop truelock-on-active truesalience 1when// 字符串$test : TestEntity(names not matches "张.*")thenSystem.out.println("rule_test_not_matches-->对象值:"+$test);
end

ComparisonTests.java

package com.example.droolstest02;import com.example.droolstest02.entity.TestEntity;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;@SpringBootTest
class ComparisonTests {@AutowiredKieBase kieBase;// 测试@Testpublic void Test() throws Exception {KieSession kieSession = kieBase.newKieSession();List<TestEntity> list = getInitData();System.out.println("==============开始匹配===================");for (TestEntity testEntity: list) {// 1-规则引擎处理逻辑kieSession.insert(testEntity);kieSession.fireAllRules();}System.out.println("==============匹配结束===================");kieSession.dispose();}// 初始化数据(模拟数据库获取的数据)private static List<TestEntity> getInitData(){List<TestEntity> list = new ArrayList<>();//{TestEntity entity = TestEntity.builder().names("张三").list(Arrays.asList("张三", "李四")).arr(new String[]{"张三", "王五"}).build();list.add(entity);}{TestEntity entity = TestEntity.builder().names("诸葛十三").list(Arrays.asList("诸葛十四", "欧阳哇哇")).arr(new String[]{"诸葛十四", "欧阳哇哇"}).build();list.add(entity);}return list;}}

输出:

6. 指定规则

我们一般业务会写很多很多个规则,那我们可以指定某个规则吗?当然

    // 测试@Testpublic void Test() throws Exception {KieSession kieSession = kieBase.newKieSession();List<TestEntity> list = getInitData();System.out.println("==============开始匹配===================");for (TestEntity testEntity: list) {// 1-规则引擎处理逻辑kieSession.insert(testEntity);// 指定规则:rule_test_containskieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule_test_contains"));}System.out.println("==============匹配结束===================");kieSession.dispose();}

输出:

这里还有很多种好玩儿的用法,可以自己尝试一下,比如:

如果你需要哪种特殊的操作,百度就完事儿了~~

我们其实开发中可以以业务线名称来命名,比如订单就用order开头,优惠就用discount开头,班级就用class开头

7. 关键字

Drools关键字分为:硬关键字(Hard keywords)和 软关键字(Soft keywords)

顾名思义,硬关键字比较强硬,我们在规则文件定义包名、规则名时不能使用,否则程序会报错。软关键字虽然可以使用,但是不建议。

在团队里使用的时候,领导者可以直接要求,硬软都不用,避免出现一些难以捉摸的问题。

硬关键字包括:true false null

软关键字包括:lock-on-active date-effective date-expires no-loop auto-focus activation-group agenda-

group ruleflow-group entry-point duration package import dialect salience enabled attributes rule extend

when then template query declare function global eval not in or and exists forall accumulate collect from

action reverse result end over init

未完待续…

下一篇写一写Drools的一些规则属性,有几个很重要的

感兴趣的同学可以关注公众号:木子的昼夜编程

drools入门-02相关推荐

  1. IOS基础之UIDynamicAnimator动力学入门-02

    IOS基础之UIDynamicAnimator动力学入门-02 10-弹性附着 // // ViewController.m // 10-弹性附着 // // Created by 鲁军 on 202 ...

  2. 【网络爬虫入门02】HTTP客户端库Requests的基本原理与基础应用

    [网络爬虫入门02]HTTP客户端库Requests的基本原理与基础应用 广东职业技术学院  欧浩源 2017-10-15  1.引言 实现网络爬虫的第一步就是要建立网络连接并向服务器或网页等网络资源 ...

  3. java编程菜鸟入门02

    写在前面: 此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 传送门: java编程菜鸟入门01 java编程菜鸟入门02 ...

  4. 图像篡改入门02 利用空间结构篡改定位

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 @图像篡改入门02 利用空间结构篡改定位 图像篡改被动取证 利用图像空间结构进行篡改定位 使用一个CNN-LSTM的网络模型捕获篡改边 ...

  5. Linux 基础入门 02

    Linux 基础入门 02 一.用户&组管理 1.1 usermod 用来修改用户账号的各项设定 -c<备注> #修改用户帐号的备注文字. -d登入目录> #修改用户登入时的 ...

  6. Babylonjs入门02——VsCode+vue+babylonjs开发第一个babylon项目程序

    Babylonjs入门02--VsCode+vue+babylonjs开发第一个babylon项目程序 1 环境搭建 2 创建vue项目 3 基于vue项目写第一个babylon项目 4 下一期再见 ...

  7. ESPHome入门02 - 开关控制 (小白入门 - (继电器控制) 开关卧室灯)

    ESPHome入门02 - 开关控制 (小白入门 - (继电器控制) 开关卧室灯) 现在开始正式进入ESPHome的编程 (确切来说只是配置一些参数, 不要担心学不会, 根据教程 一步步来 很容易实现 ...

  8. CSS3基础入门02

    目录 CSS3 基础入门02 边框相关属性 border-radius border-image box-shadow CSS3 弹性盒子模型 什么是弹性盒子模型 新旧版本的弹性盒子 相关概念 弹性容 ...

  9. Drools入门系列

    Drools入门系列(一)HelloWorld Drools入门系列(二)HelloWorld详解之Sample.drl Drools入门系列(三)HelloWorld详解之kmodule.xml D ...

最新文章

  1. 中盐总公司:盐业公司24小时配送保供应
  2. boost::callable_traits下qualified_class_of的测试程序
  3. JAVA入门级教学之(内存地址的引用示例)
  4. 2018年云计算大调查:五成开发者月入过万 阿里云称霸公有云市场
  5. 眼手组合-眼低手低者
  6. Atitit..net clr il指令集 以及指令分类  与指令详细说明
  7. 小猿圈之Python开发的技巧一?
  8. 安装SQL Server 2000 出现挂起文件,需要重启该如何解决?
  9. 收件服务器位置,如何查看邮箱的收件服务器地址
  10. 【STM32H7的DSP教程】第14章 DSP统计函数-最大值,最小值,平均值和功率
  11. 下列python语句的输出结果是_下列Python语句的输出结果是 __________ 。 print(数量%4d,单价%3.3f %(100,285.6)) (3.0分)_学小易找答案...
  12. 「 LaTex 」使用多级标题
  13. 微信3.1.0.41逆向-微信3.1.0.41HOOK接口(WeChatHelper3.1.0.41.dll)使用说明
  14. Debian11安装mysql5.7
  15. 2019-2-16-WPF-封装-dotnet-remoting-调用其他进程
  16. 更换Ubuntu的软件仓库为国内的镜像
  17. Java程序员高效学习的六个中肯建议
  18. java h264 sps解码,H264 SPS解析
  19. 【正点原子Linux连载】第二十二章 AP3216C 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2
  20. keyshot渲染图文教程_KeyShot渲染汽车教程 - 纳金网

热门文章

  1. glusterfs 文件服务器 搭建
  2. 用matlab写的视频截取图像桢,基于MATLAB的储粮害虫图像处理方法
  3. 回归(Regression)是什么意思
  4. 京东面经!让你的春招不再迷茫!
  5. 软件测试设计——按类型划分
  6. 如何在Python中安装NumPy
  7. 51单片机-4G模块
  8. 一点资讯signature分析
  9. matlab打开F90文件,ifort编译f90程序命令
  10. 【转载】磁盘空间引起ES集群shard unassigned的处理过程