規則引擎Drools

1.規則引擎概述

1.1 什么是規則引擎

規則引擎 全稱為業務規則管理系統,英文名為BRMS,規則引擎的主要思想是將應用程序中的業務決策部分分離出來,并使用預定義的語義模塊編寫業務規則,由用戶或開發者在需要時進行配置和管理。
需要注意的是規則引擎并不是一個具體的技術框架,而是指的一類系統,即業務規則管理系統。目前市面上具體的規則引擎產品有:drools、VisualRules、iLog等。
規則引擎實現了將業務決策從應用程序代碼中分離出來,接收數據輸入,解釋業務規則,并根據業務規則做出業務決策。規則引擎其實就是一個輸入輸出平臺。

1.2 使用規則引擎的優勢

  1. 業務規則與系統代碼分離,實現業務規則的集中管理
  2. 在不重啟服務的情況下隨時對業務規則進行擴展和維護
  3. 可以動態修改業務規則, 從而快速響應需求變更
  4. 規則引擎是相對獨立的
  5. 減少了硬編碼業務規則的成本和風險
  6. 使用規則引擎提供的規則編輯工具,使復雜的業務規則變得簡單

1.3 規則引擎應用場景

  1. 風險控制系統----風險貸款、風險評估
  2. 反欺詐項目----銀行貸款、征信驗證
  3. 決策平臺系統----財務計算
  4. 促銷平臺系統----滿減、打折、加價購

1.4 Drools 介紹

drools 是一款由JBoss組織提供的基于Java語言開發的開源規則引擎,可以將復雜且多變的業務規則從硬編碼中解放出來,以規則腳本的形式存放在文件或特定的存儲介質中(例如存放在數據庫中),使得業務規則的變更不需要修改項目代碼、重啟服務器就可以在線上環境立即生效。
drools官網地址:https://drools.org/
drools源碼下載地址:https://github.com/kiegroup/drools
在項目中使用drools時,即可以單獨使用也可以整合spring使用。如果單獨使用只需要導入如下maven坐標即可:

<dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.6.0.Final</version>
</dependency>

如果我們使用IDEA開發drools應用,IDEA中已經集成了drools插件。如果使用eclipse開發drools應用還需要單獨安裝drools插件。
drools API開發步驟如下:
在這里插入圖片描述

2. Drools 入門案例

首先通過一個Drools入門案例,初步了解Drools的使用方法,對Drools有一個整體概念。

2.1 業務場景說明

業務場景:消費者在圖書商城購買圖書,下單后需要在支付頁面顯示訂單優惠后的價格。具體優惠規則如下:

規則編號規則名稱描述
1規則一所購圖書總價在100元的沒有優惠
2規則二所購圖書總價在100元到200元的優惠20元
3規則三所購圖書總價在200到300元的優惠50元
4規則四所購圖書總價在300元以上的優惠100元
現在需要根據上面的規則計算優惠后的價格。

3.2 開發實現

第一步:創建maven工程drools_quickstart并導入drools相關maven坐標

<dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.10.0.Final</version>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version>
</dependency>

第二步:根據drools要求創建resources/META-INF/kmodule.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/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>

注意:上面配置文件的名稱和位置都是固定寫法,不能更改

第三步:創建實體類Order

package com.itheima.drools.entity;/*** 訂單*/
public class Order {private Double originalPrice;//訂單原始價格,即優惠前價格private Double realPrice;//訂單真實價格,即優惠后價格public String toString() {return "Order{" +"originalPrice=" + originalPrice +", realPrice=" + realPrice +'}';}public Double getOriginalPrice() {return originalPrice;}public void setOriginalPrice(Double originalPrice) {this.originalPrice = originalPrice;}public Double getRealPrice() {return realPrice;}public void setRealPrice(Double realPrice) {this.realPrice = realPrice;}
}

第四步:創建規則文件resources/rules/bookDiscount.drl

//圖書優惠規則
package book.discount
import com.itheima.drools.entity.Order//規則一:所購圖書總價在100元以下的沒有優惠
rule "book_discount_1"when$order:Order(originalPrice < 100)then$order.setRealPrice($order.getOriginalPrice());System.out.println("成功匹配到規則一:所購圖書總價在100元以下的沒有優惠");
end//規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"when$order:Order(originalPrice < 200 && originalPrice >= 100)then$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規則二:所購圖書總價在100到200元的優惠20元");
end//規則三:所購圖書總價在200到300元的優惠50元
rule "book_discount_3"when$order:Order(originalPrice <= 300 && originalPrice >= 200)then$order.setRealPrice($order.getOriginalPrice() - 50);System.out.println("成功匹配到規則三:所購圖書總價在200到300元的優惠50元");
end//規則四:所購圖書總價在300元以上的優惠100元
rule "book_discount_4"when$order:Order(originalPrice >= 300)then$order.setRealPrice($order.getOriginalPrice() - 100);System.out.println("成功匹配到規則四:所購圖書總價在300元以上的優惠100元");
end

第五步:編寫單元測試

@Test
public void test1(){KieServices kieServices = KieServices.Factory.get();KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();//會話對象,用于和規則引擎交互KieSession kieSession = kieClasspathContainer.newKieSession();//構造訂單對象,設置原始價格,由規則引擎根據優惠規則計算優惠后的價格Order order = new Order();order.setOriginalPrice(210D);//將數據提供給規則引擎,規則引擎會根據提供的數據進行規則匹配kieSession.insert(order);//激活規則引擎,如果規則匹配成功則執行規則kieSession.fireAllRules();//關閉會話kieSession.dispose();System.out.println("優惠前原始價格:" + order.getOriginalPrice() +",優惠后價格:" + order.getRealPrice());
}

通過上面的入門案例我們可以發現,使用drools規則引擎主要工作就是編寫規則文件,在規則文件中定義跟業務相關的業務規則,例如本案例定義的就是圖書優惠規則。規則定義好后就需要調用drools提供的API將數據提供給規則引擎進行規則模式匹配,規則引擎會執行匹配成功的規則并將計算的結果返回給我們。

可能大家會有疑問,就是我們雖然沒有在代碼中編寫規則的判斷邏輯,但是我們還是在規則文件中編寫了業務規則,這跟在代碼中編寫規則有什么本質的區別呢?

我們前面其實已經提到,使用規則引擎時業務規則可以做到動態管理。業務人員可以像管理數據一樣對業務規則進行管理,比如查詢、添加、更新、統計、提交業務規則等。這樣就可以做到在不重啟服務的情況下調整業務規則。

3.3 小結

3.3.1 規則引擎構成

drools規則引擎由以下三部分構成:

  • Working Memory(工作內存)
  • Rule Base(規則庫)
  • Inference Engine(推理引擎)

其中Inference Engine(推理引擎)又包括:

  • Pattern Matcher(匹配器)
  • Agenda(議程)
  • Execution Engine(執行引擎)

如下圖所示:
在這里插入圖片描述

3.3.2 相關概念說明

Working Memory:工作內存,drools規則引擎會從Working Memory中獲取數據并和規則文件中定義的規則進行模式匹配,所以我們開發的應用程序只需要將我們的數據插入到Working Memory中即可,例如本案例中我們調用kieSession.insert(order)就是將order對象插入到了工作內存中。

Fact:事實,是指在drools 規則應用當中,將一個普通的JavaBean插入到Working Memory后的對象就是Fact對象,例如本案例中的Order對象就屬于Fact對象。Fact對象是我們的應用和規則引擎進行數據交互的橋梁或通道。

Rule Base:規則庫,我們在規則文件中定義的規則都會被加載到規則庫中。

Pattern Matcher:匹配器,將Rule Base中的所有規則與Working Memory中的Fact對象進行模式匹配,匹配成功的規則將被激活并放入Agenda中。

Agenda:議程,用于存放通過匹配器進行模式匹配后被激活的規則。

Execution Engine:執行引擎,執行Agenda中被激活的規則。

3.3.3 規則引擎執行過程

在這里插入圖片描述

3.3.4 KIE介紹

我們在操作Drools時經常使用的API以及它們之間的關系如下圖:

在這里插入圖片描述

通過上面的核心API可以發現,大部分類名都是以Kie開頭。Kie全稱為Knowledge Is Everything,即"知識就是一切"的縮寫,是Jboss一系列項目的總稱。如下圖所示,Kie的主要模塊有OptaPlanner、Drools、UberFire、jBPM。

通過上圖可以看到,Drools是整個KIE項目中的一個組件,Drools中還包括一個Drools-WB的模塊,它是一個可視化的規則編輯器。

3. Drools基礎語法

3.1 規則文件構成

在使用Drools時非常重要的一個工作是編寫規則文件,通常規則文件的后綴為drl
drl 的Drools Rule Language 的縮寫,在規則文件中編寫內容的規則如下:

關鍵字描述
package包名,只限于邏輯上的管理,同一個包名下的查詢或者函數可以直接調用
import用于導入類或者靜態方法
global全局變量
function自定義函數
query查詢
rule end規則體

Drools支持的規則文件,除了drl形式,還有Excel文件類型的。

3.2 規則體語法結構

規則體是規則文件內容中的重要組成部分,是進行業務規則判斷、處理業務結果的部分。

規則體語法結構如下:

rule "ruleName"attributeswhenLHSthenRHS
end

rule:關鍵字,表示規則開始,參數為規則的唯一名稱。

attribute:規則屬性, 是rule與when之間的參數,為可選項

when :關鍵字,后面跟規則的條件部分

LHS:是規則的條件部分的通用名稱。它由零個或多個條件元素組成。如果LHS為空,則它將被視為始終為true的條件元素。

then:關鍵字,后面跟規則的結果部分。

RHS(Right Hand Side):是規則的后果或行動部分的通用名稱。

end:關鍵字,表示一個規則結束。

3.3 注釋

在drl形式的規則文件中使用注釋和Java類中使用注釋一致,分為單行注釋和多行注釋。

單行注釋用"//“進行標記,多行注釋以”/*“開始,以”*/"結束。如下示例:

//規則rule1的注釋,這是一個單行注釋
rule "rule1"whenthenSystem.out.println("rule1觸發");
end/*
規則rule2的注釋,
這是一個多行注釋
*/
rule "rule2"whenthenSystem.out.println("rule2觸發");
end

3.4 Pattern模式匹配

前面我們已經知道了Drools中的匹配器可以將Rule Base中的所有規則與Working Memory中的Fact對象進行模式匹配,那么我們就需要在規則體的LHS部分定義規則并進行模式匹配。LHS部分由一個或者多個條件組成,條件又稱為pattern。

pattern的語法結構為:綁定變量名:Object(Field約束)

其中綁定變量名可以省略,通常綁定變量名的命名一般建議以$開始。如果定義了綁定變量名,就可以在規則體的RHS部分使用此綁定變量名來操作相應的Fact對象。Field約束部分是需要返回true或者false的0個或多個表達式。

例如我們的入門案例中:

//規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"when//Order為類型約束,originalPrice為屬性約束$order:Order(originalPrice < 200 && originalPrice >= 100)then$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規則二:所購圖書總價在100到200元的優惠20元");
end

通過上面的例子我們可以知道,匹配的條件為:

1、工作內存中必須存在Order這種類型的Fact對象-----類型約束

2、Fact對象的originalPrice屬性值必須小于200------屬性約束

3、Fact對象的originalPrice屬性值必須大于等于100------屬性約束

以上條件必須同時滿足當前規則才有可能被激活。

綁定變量既可以用在對象上,也可以用在對象的屬性上。例如上面的例子可以改為:

//規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"when$order:Order($op:originalPrice < 200 && originalPrice >= 100)thenSystem.out.println("$op=" + $op);$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規則二:所購圖書總價在100到200元的優惠20元");
end

LHS部分還可以定義多個pattern,多個pattern之間可以使用and或者or進行連接,也可以不寫,默認連接為and。

//規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"when$order:Order($op:originalPrice < 200 && originalPrice >= 100) and$customer:Customer(age > 20 && gender=='male')thenSystem.out.println("$op=" + $op);$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規則二:所購圖書總價在100到200元的優惠20元");
end

3.5 比較操作符

Drools提供的比較操作符,如下表:

符號說明
>大于
<小于
>=大于等于
<=小于等于
==等于
!=不等于
contains檢查一個Fact對象的某個屬性值是否包含一個指定的對象值
not contains檢查一個Fact對象的某個屬性值是否不包含一個指定的對象值
memberOf判斷一個Fact對象的某個屬性是否在一個或多個集合中
not memberOf判斷一個Fact對象的某個屬性是否不在一個或多個集合中
matches判斷一個Fact對象的屬性是否與提供的標準的Java正則表達式進行匹配
not matches判斷一個Fact對象的屬性是否不與提供的標準的Java正則表達式進行匹配

前6個比較操作符和Java中的完全相同,下面我們重點學習后6個比較操作符。

3.5.1 語法
  • contains | not contains語法結構

    Object(Field[Collection/Array] contains value)

    Object(Field[Collection/Array] not contains value)

  • memberOf | not memberOf語法結構

    Object(field memberOf value[Collection/Array])

    Object(field not memberOf value[Collection/Array])

  • matches | not matches語法結構

    Object(field matches “正則表達式”)

    Object(field not matches “正則表達式”)

3.5.2 操作步驟

第一步:創建實體類,用于測試比較操作符

package com.itheima.drools.entity;
import java.util.List;/*** 實體類* 用于測試比較操作符*/
public class ComparisonOperatorEntity {private String names;private List<String> list;public String getNames() {return names;}public void setNames(String names) {this.names = names;}public List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}
}

第二步:在/resources/rules下創建規則文件comparisonOperator.drl

package comparisonOperator
import com.itheima.drools.entity.ComparisonOperatorEntity
/*當前規則文件用于測試Drools提供的比較操作符
*///測試比較操作符contains
rule "rule_comparison_contains"whenComparisonOperatorEntity(names contains "張三")ComparisonOperatorEntity(list contains names)thenSystem.out.println("規則rule_comparison_contains觸發");
end//測試比較操作符not contains
rule "rule_comparison_notContains"whenComparisonOperatorEntity(names not contains "張三")ComparisonOperatorEntity(list not contains names)thenSystem.out.println("規則rule_comparison_notContains觸發");
end//測試比較操作符memberOf
rule "rule_comparison_memberOf"whenComparisonOperatorEntity(names memberOf list)thenSystem.out.println("規則rule_comparison_memberOf觸發");
end//測試比較操作符not memberOf
rule "rule_comparison_notMemberOf"whenComparisonOperatorEntity(names not memberOf list)thenSystem.out.println("規則rule_comparison_notMemberOf觸發");
end//測試比較操作符matches
rule "rule_comparison_matches"whenComparisonOperatorEntity(names matches "張.*")thenSystem.out.println("規則rule_comparison_matches觸發");
end//測試比較操作符not matches
rule "rule_comparison_notMatches"whenComparisonOperatorEntity(names not matches "張.*")thenSystem.out.println("規則rule_comparison_notMatches觸發");
end

第三步:編寫單元測試

//測試比較操作符@Testpublic void test2() {KieServices kieServices = KieServices.Factory.get();KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();KieSession kieSession = kieClasspathContainer.newKieSession();ComparisonOperatorEntity comparisonOperatorEntity = new ComparisonOperatorEntity();comparisonOperatorEntity.setNames("張三");List<String> list = new ArrayList<>();list.add("張三");list.add("李四");comparisonOperatorEntity.setList(list);//將數據提供給規則引擎,規則引擎會根據提供的數據進行規則匹配,如果規則匹配成功則執行規則kieSession.insert(comparisonOperatorEntity);/*  //激活全部規則kieSession.fireAllRules();*///通過規則過濾器實現只執行指定規則kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule_comparison_contains"));kieSession.dispose();}

3.6 Drools內置方法

規則文件的RHS部分的主要作用是通過插入,刪除或修改工作內存中的Fact數據,來達到控制規則引擎執行的目的。Drools提供了一些方法可以用來操作工作內存中的數據,操作完成后規則引擎會重新進行相關規則的匹配,原來沒有匹配成功的規則在我們修改數據完成后有可能就會匹配成功了。

3.6.1 update方法

update方法的作用是更新工作內存中的數據,并讓相關的規則重新匹配。

第一步:編寫規則文件/resources/rules/student.drl,文件內容如下

package student
import com.itheima.drools.entity.Student/*當前規則文件用于測試Drools提供的內置方法
*/rule "rule_student_age小于10歲"when$s:Student(age < 10)then$s.setAge(15);update($s);//更新數據,導致相關的規則會重新匹配System.out.println("規則rule_student_age小于10歲觸發");
endrule "rule_student_age小于20歲同時大于10歲"when$s:Student(age < 20 && age > 10)then$s.setAge(25);update($s);//更新數據,導致相關的規則會重新匹配System.out.println("規則rule_student_age小于20歲同時大于10歲觸發");
endrule "rule_student_age大于20歲"when$s:Student(age > 20)thenSystem.out.println("規則rule_student_age大于20歲觸發");
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();Student student = new Student();
student.setAge(5);//將數據提供給規則引擎,規則引擎會根據提供的數據進行規則匹配,如果規則匹配成功則執行規則
kieSession.insert(student);kieSession.fireAllRules();
kieSession.dispose();

通過控制臺的輸出可以看到規則文件中定義的三個規則都觸發了。
在這里插入圖片描述

3.6.2 insert方法

insert方法作用是向工作內容中插入數據,并讓相關規則重新匹配
直接修改student.drl即可

rule "rule_student_age等于10歲"when$s:Student(age == 10)thenStudent student = new Student();student.setAge(5);insert(student);//插入數據,導致相關的規則會重新匹配System.out.println("規則rule_student_age等于10歲觸發");
end
3.6.3 retract方法

retract方法的作用是刪除工作內存中的數據,并讓相關的規則重新匹配。
第一步:修改student.drl文件內容如下

package student
import com.itheima.drools.entity.Student/*當前規則文件用于測試Drools提供的內置方法
*/rule "rule_student_age等于10歲時刪除數據"/*salience:設置當前規則的執行優先級,數值越大越優先執行,默認值為0.因為當前規則的匹配條件和下面規則的匹配條件相同,為了保證先執行當前規則,需要設置優先級*/salience 100 when$s:Student(age == 10)thenretract($s);//retract方法的作用是刪除工作內存中的數據,并讓相關的規則重新匹配。System.out.println("規則rule_student_age等于10歲時刪除數據觸發");
endrule "rule_student_age等于10歲"when$s:Student(age == 10)thenStudent student = new Student();student.setAge(5);insert(student);System.out.println("規則rule_student_age等于10歲觸發");
endrule "rule_student_age小于10歲"when$s:Student(age < 10)then$s.setAge(15);update($s);System.out.println("規則rule_student_age小于10歲觸發");
endrule "rule_student_age小于20歲同時大于10歲"when$s:Student(age < 20 && age > 10)then$s.setAge(25);update($s);System.out.println("規則rule_student_age小于20歲同時大于10歲觸發");
endrule "rule_student_age大于20歲"when$s:Student(age > 20)thenSystem.out.println("規則rule_student_age大于20歲觸發");
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();Student student = new Student();
student.setAge(10);//將數據提供給規則引擎,規則引擎會根據提供的數據進行規則匹配,如果規則匹配成功則執行規則
kieSession.insert(student);kieSession.fireAllRules();
kieSession.dispose();

通過控制臺輸出可以發現,只有第一個規則觸發了,因為在第一個規則中將工作內存中的數據刪除了導致第二個規則并沒有匹配成功。
在這里插入圖片描述

4.規則屬性

規則體的構成如下:

rule "ruleName"attributeswhenLHSthenRHS
end

Drools中提供的屬性如下表(部分屬性)):

屬性名說明
salience指定規則執行優先級
dialect指定規則使用的語言類型,取值為java和mvel
enabled指定規則是否啟用
date-effective指定規則生效時間
date-expires指定規則失效時間
activation-group激活分組,具有相同分組名稱的規則只能有一個規則觸發
agenda-group議程分組,只有獲取焦點的組中的規則才有可能觸發
timer定時器,指定規則觸發的時間
auto-focus自動獲取焦點,一般結合agenda-group一起使用
no-loop防止死循環

4.1 enabled屬性

enabled屬性對應的取值為true和false,默認值為true。
用于指定當前規則是否啟用,如果設置的值為false則當前規則無論是否匹配成功都不會觸發。

4.2 dialect 屬性

dialect 屬性用于指定當前規則使用的語言類型,取值為java和mvel默認為java

注:mvel是一種基于java語法的表達式語言。
mvel像正則表達式一樣,有直接支持集合、數組和字符串匹配的操作符。
mvel還提供了用來配置和構造字符串的模板語言。
mvel表達式內容包括屬性表達式,布爾表達式,方法調用,變量賦值,函數定義等。

4.3 salience屬性

salience屬性用于指定,規則的執行優先級,取值為Integer。數值越大越先執行,每個規則都有一個默認的執行順序,如果不設置salience屬性,規則體的執行順序為由上到下。

4.4no-loop 屬性

no-loop屬性用于防止死循環,當規則通過update之類的函數修改了Fact對象時,可能使當前規則再次被激活從而導致死循環。取值類型為Boolean,默認值為false。測試步驟如下:
第一步:編寫規則文件/resource/rules/noloop.drl

package testnoloop
import com.itheima.drools.entity.Student
/*此規則文件用于測試no-loop屬性
*/
rule "rule_noloop"when// no-loop true$student:Student(age == 25)thenupdate($student);//注意此處執行update會導致當前規則重新被激活System.out.println("規則rule_noloop觸發");
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();Student student = new Student();
student.setAge(25);//將數據提供給規則引擎,規則引擎會根據提供的數據進行規則匹配,如果規則匹配成功則執行規則
kieSession.insert(student);kieSession.fireAllRules();
kieSession.dispose();

通過控制臺可以看到,由于我們沒有設置no-loop屬性的值,所以發生了死循環。接下來設置no-loop的值為true再次測試則不會發生死循環。

4.5 activation-group屬性

activation-group屬性是指激活分組,取值為String類型。具有相同分組名稱的規則只能有一個規則被觸發。

第一步:編寫規則文件/resources/rules/activationgroup.drl

package testactivationgroup
/*此規則文件用于測試activation-group屬性
*/rule "rule_activationgroup_1"activation-group "mygroup"whenthenSystem.out.println("規則rule_activationgroup_1觸發");
endrule "rule_activationgroup_2"activation-group "mygroup"whenthenSystem.out.println("規則rule_activationgroup_2觸發");
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
kieSession.fireAllRules();
kieSession.dispose();

通過控制臺可以發現,上面的兩個規則因為屬于同一個分組,所以只有一個觸發了。同一個分組中的多個規則如果都能夠匹配成功,具體哪一個最終能夠被觸發可以通過salience屬性確定。

4.6 agenda-group屬性

agenda-group屬性為議程分組,屬于另一種可控的規則執行方式。用戶可以通過設置agenda-group來控制規則的執行,只有獲取焦點的組中的規則才會被觸發。

第一步:創建規則文件/resources/rules/agendagroup.drl

package testagendagroup
/*此規則文件用于測試agenda-group屬性
*/
rule "rule_agendagroup_1"agenda-group "myagendagroup_1"whenthenSystem.out.println("規則rule_agendagroup_1觸發");
endrule "rule_agendagroup_2"agenda-group "myagendagroup_1"whenthenSystem.out.println("規則rule_agendagroup_2觸發");
end
//========================================================
rule "rule_agendagroup_3"agenda-group "myagendagroup_2"whenthenSystem.out.println("規則rule_agendagroup_3觸發");
endrule "rule_agendagroup_4"agenda-group "myagendagroup_2"whenthenSystem.out.println("規則rule_agendagroup_4觸發");
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();//設置焦點,對應agenda-group分組中的規則才可能被觸發
kieSession.getAgenda().getAgendaGroup("myagendagroup_1").setFocus();kieSession.fireAllRules();
kieSession.dispose();

通過控制臺可以看到,只有獲取焦點的分組中的規則才會觸發。與activation-group不同的是,activation-group定義的分組中只能夠有一個規則可以被觸發,而agenda-group分組中的多個規則都可以被觸發。

4.7 auto-focus屬性

auto-focus屬性為自動獲取焦點,取值類型為Boolean,默認值為false。一般結合agenda-group屬性使用,當一個議程分組未獲取焦點時,可以設置auto-focus屬性來控制。

第一步:修改/resources/rules/agendagroup.drl文件內容如下

package testagendagrouprule "rule_agendagroup_1"agenda-group "myagendagroup_1"whenthenSystem.out.println("規則rule_agendagroup_1觸發");
endrule "rule_agendagroup_2"agenda-group "myagendagroup_1"whenthenSystem.out.println("規則rule_agendagroup_2觸發");
end
//========================================================
rule "rule_agendagroup_3"agenda-group "myagendagroup_2"auto-focus true //自動獲取焦點whenthenSystem.out.println("規則rule_agendagroup_3觸發");
endrule "rule_agendagroup_4"agenda-group "myagendagroup_2"auto-focus true //自動獲取焦點whenthenSystem.out.println("規則rule_agendagroup_4觸發");
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
kieSession.fireAllRules();
kieSession.dispose();

通過控制臺可以看到,設置auto-focus屬性為true的規則都觸發了。

4.8 timer屬性

timer屬性可以通過定時器的方式指定規則執行的時間,使用方式有兩種:

方式一:timer (int: <initial delay> <repeat interval>?)

此種方式遵循java.util.Timer對象的使用方式,第一個參數表示幾秒后執行,第二個參數表示每隔幾秒執行一次,第二個參數為可選。

方式二:timer(cron: <cron expression>)

此種方式使用標準的unix cron表達式的使用方式來定義規則執行的時間。

第一步:創建規則文件/resources/rules/timer.drl

package testtimer
import java.text.SimpleDateFormat
import java.util.Date
/*此規則文件用于測試timer屬性
*/rule "rule_timer_1"timer (5s 2s) //含義:5秒后觸發,然后每隔2秒觸發一次whenthenSystem.out.println("規則rule_timer_1觸發,觸發時間為:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
endrule "rule_timer_2"timer (cron:0/1 * * * * ?) //含義:每隔1秒觸發一次whenthenSystem.out.println("規則rule_timer_2觸發,觸發時間為:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
final KieSession kieSession = kieClasspathContainer.newKieSession();new Thread(new Runnable() {public void run() {//啟動規則引擎進行規則匹配,直到調用halt方法才結束規則引擎kieSession.fireUntilHalt();}
}).start();Thread.sleep(10000);
//結束規則引擎
kieSession.halt();
kieSession.dispose();

注意:單元測試的代碼和以前的有所不同,因為我們規則文件中使用到了timer進行定時執行,需要程序能夠持續一段時間才能夠看到定時器觸發的效果。

4.9 date-effective屬性

date-effective屬性用于指定規則的生效時間,即只有當前系統時間大于等于設置的時間或者日期規則才有可能觸發。默認日期格式為:dd-MMM-yyyy。用戶也可以自定義日期格式。

第一步:編寫規則文件/resources/rules/dateeffective.drl

package testdateeffective
/*此規則文件用于測試date-effective屬性
*/
rule "rule_dateeffective_1"date-effective "2020-10-01 10:00"whenthenSystem.out.println("規則rule_dateeffective_1觸發");
end

第二步:編寫單元測試

//設置日期格式
System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
kieSession.fireAllRules();
kieSession.dispose();

注意:上面的代碼需要設置日期格式,否則我們在規則文件中寫的日期格式和默認的日期格式不匹配程序會報錯。

4.10 date-expires屬性

date-expires屬性用于指定規則的失效時間,即只有當前系統時間小于設置的時間或者日期規則才有可能觸發。默認日期格式為:dd-MMM-yyyy。用戶也可以自定義日期格式。

第一步:編寫規則文件/resource/rules/dateexpires.drl

package testdateexpires
/*此規則文件用于測試date-expires屬性
*/rule "rule_dateexpires_1"date-expires "2019-10-01 10:00"whenthenSystem.out.println("規則rule_dateexpires_1觸發");
end

第二步:編寫單元測試

//設置日期格式
System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
kieSession.fireAllRules();
kieSession.dispose();

注意:上面的代碼需要設置日期格式,否則我們在規則文件中寫的日期格式和默認的日期格式不匹配程序會報錯。

5 Drools 全局變量

global關鍵字用于在規則文件中定義全局變量,它可以讓應用程序的對象在規則文件中能夠被訪問。可以用來為規則文件提供數據或服務。
語法結構為:global 對象類型 對象名稱
在使用global定義的全局變量時有兩點需要注意:

1、如果對象類型為包裝類型時,在一個規則中改變了global的值,那么只針對當前規則有效,對其他規則中的global不會有影響。可以理解為它是當前規則代碼中的global副本,規則內部修改不會影響全局的使用。

2、如果對象類型為集合類型或JavaBean時,在一個規則中改變了global的值,對java代碼和所有規則都有效。
代碼如下:
第一步:創建UserService類

package com.itheima.drools.service;public class UserService {public void save(){System.out.println("UserService.save()...");}
}

第二步:編寫規則文件/resources/rules/global.drl

package testglobal
/*此規則文件用于測試global全局變量
*/global java.lang.Integer count //定義一個包裝類型的全局變量
global com.itheima.drools.service.UserService userService //定義一個JavaBean類型的全局變量
global java.util.List gList //定義一個集合類型的全局變量rule "rule_global_1"whenthencount += 10; //全局變量計算,只對當前規則有效,其他規則不受影響userService.save();//調用全局變量的方法gList.add("itcast");//向集合類型的全局變量中添加元素,Java代碼和所有規則都受影響gList.add("itheima");System.out.println("count=" + count);System.out.println("gList.size=" + gList.size());
endrule "rule_global_2"whenthenuserService.save();System.out.println("count=" + count);System.out.println("gList.size=" + gList.size());
end

第三步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();//設置全局變量,名稱和類型必須和規則文件中定義的全局變量名稱對應
kieSession.setGlobal("userService",new UserService());
kieSession.setGlobal("count",5);
List list = new ArrayList();//size為0
kieSession.setGlobal("gList",list);kieSession.fireAllRules();
kieSession.dispose();//因為在規則中為全局變量添加了兩個元素,所以現在的size為2
System.out.println(list.size());

5.2query查詢

query查詢提供了一種查詢working memory中符合約束條件的Fact對象的簡單方法。它僅包含規則文件中的LHS部分,不用指定“when”和“then”部分并且以end結束。具體語法結構如下:

query 查詢的名稱(可選參數)LHS
end

具體操作步驟:

第一步:編寫規則文件/resources/rules/query.drl

package testquery
import com.itheima.drools.entity.Student
/*此規則文件用于測試query查詢
*///不帶參數的查詢
//當前query用于查詢Working Memory中age>10的Student對象
query "query_1"$student:Student(age > 10)
end//帶有參數的查詢
//當前query用于查詢Working Memory中age>10同時name需要和傳遞的參數name相同的Student對象
query "query_2"(String sname)$student:Student(age > 20 && name == sname)
end

第二步:編寫單元測試

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();Student student1 = new Student();
student1.setName("張三");
student1.setAge(12);Student student2 = new Student();
student2.setName("李四");
student2.setAge(8);Student student3 = new Student();
student3.setName("王五");
student3.setAge(22);//將對象插入Working Memory中
kieSession.insert(student1);
kieSession.insert(student2);
kieSession.insert(student3);//調用規則文件中的查詢
QueryResults results1 = kieSession.getQueryResults("query_1");
int size = results1.size();
System.out.println("size=" + size);
for (QueryResultsRow row : results1) {Student student = (Student) row.get("$student");System.out.println(student);
}//調用規則文件中的查詢
QueryResults results2 = kieSession.getQueryResults("query_2","王五");
size = results2.size();
System.out.println("size=" + size);
for (QueryResultsRow row : results2) {Student student = (Student) row.get("$student");System.out.println(student);
}
//kieSession.fireAllRules();
kieSession.dispose();

5.3 function函數

function關鍵字用于在規則文件中定義函數,就相當于java類中的方法一樣。可以在規則體中調用定義的函數。使用函數的好處是可以將業務邏輯集中放置在一個地方,根據需要可以對函數進行修改。

函數定義的語法結構如下:

function 返回值類型 函數名(可選參數){//邏輯代碼
}

具體操作步驟:

第一步:編寫規則文件/resources/rules/function.drl

package testfunction
import com.itheima.drools.entity.Student
/*此規則文件用于測試function函數
*///定義一個函數
function String sayHello(String name){return "hello " + name;
}rule "rule_function_1"when$student:Student(name != null)then//調用上面定義的函數String ret = sayHello($student.getName());System.out.println(ret);
end

5.4 LHS加強

5.4.1 符合值限制in/not

復合值限制是指超過一直匹配值 的限制條件,類似于SQL語句中的in關鍵字,Drools規則體中的LHS部分可以使用in或者not in 進行復合值的匹配
舉例:

$s:Student(name in ("張三","李四","王五"))
$s:Student(name not in ("張三","李四","王五"))
5.4.2 條件元素eval

eval用于規則體的LHS部分,并返回一個Boolean類型的值。語法結構如下:

eval(表達式)

舉例:

eval(true)
eval(false)
eval(1 == 1)
5.4.3 條件元素not

not用于判斷Working Memory中是否存在某個Fact對象,如果不存在則返回true,如果存在則返回false。語法結構如下:

not Object(可選屬性約束)

舉例:

not Student()
not Student(age < 10)
5.4.4 條件元素exists

exists的作用與not相反,用于判斷Working Memory中是否存在某個Fact對象,如果存在則返回true,不存在則返回false。語法結構如下:

exists Object(可選屬性約束)

舉例:

exists Student()
exists Student(age < 10 && name != null)

可能有人會有疑問,我們前面在LHS部分進行條件編寫時并沒有使用exists也可以達到判斷Working Memory中是否存在某個符合條件的Fact元素的目的,那么我們使用exists還有什么意義?

兩者的區別:當向Working Memory中加入多個滿足條件的Fact對象時,使用了exists的規則執行一次,不使用exists的規則會執行多次。

例如:

規則文件(只有規則體):

rule "使用exists的規則"whenexists Student()thenSystem.out.println("規則:使用exists的規則觸發");
endrule "沒有使用exists的規則"whenStudent()thenSystem.out.println("規則:沒有使用exists的規則觸發");
end

Java代碼:

kieSession.insert(new Student());
kieSession.insert(new Student());
kieSession.fireAllRules();

上面第一個規則只會執行一次,因為Working Memory中存在兩個滿足條件的Fact對象,第二個規則會執行兩次。

5.4.5 規則繼承

規則之間可以使用extends關鍵字進行規則條件部分的繼承,類似于java類之間的繼承。

例如:

rule "rule_1"whenStudent(age > 10)thenSystem.out.println("規則:rule_1觸發");
endrule "rule_2" extends "rule_1" //繼承上面的規則when/*此處的條件雖然只寫了一個,但是從上面的規則繼承了一個條件,所以當前規則存在兩個條件,即Student(age < 20)和Student(age > 10)*/Student(age < 20) thenSystem.out.println("規則:rule_2觸發");
end

5.5 RHS加強

RHS部分是規則體的重要組成部分,當LHS部分的條件匹配成功后,對應的RHS部分就會觸發執行。一般在RHS部分中需要進行業務處理。

5.5.1halt

halt 方法的作用是立即終止后面所有規則的執行

package testhalt
rule "rule_halt_1"whenthenSystem.out.println("規則:rule_halt_1觸發");drools.halt();//立即終止后面所有規則執行
end//當前規則并不會觸發,因為上面的規則調用了halt方法導致后面所有規則都不會執行
rule "rule_halt_2"whenthenSystem.out.println("規則:rule_halt_2觸發");
end
5.5.2
getWorkingMemory

getWorkingMemory方法的作用是返回工作內存對象。

package testgetWorkingMemory
rule "rule_getWorkingMemory"whenthenSystem.out.println(drools.getWorkingMemory());
end
5.5.3 getRule

getRule方法的作用是返回規則對象。

package testgetRule
rule "rule_getRule"whenthenSystem.out.println(drools.getRule());
end

5.6 規則文件編碼規范

我們在進行drl規則文件編碼時應盡量遵循如下規范:

  • 所有規則文件(.drl)統一放在一個規定的文件夾中,如:/rules文件夾
  • 書寫的每個規則應盡量加上注釋
  • 統一類型的對象盡量放在規則文件中,如所有Student類型的對象盡量放在一個規則文件中
  • 規則結果部分(RHS)盡量不要有條件語句,如if(…),盡量不要有復雜的邏輯和深層次的嵌套語句
  • 每個規則最好都加上salience屬性,明確執行順序
  • Drools默認dialect為java盡量避免使用mvel

6. Spring整合Drools

6.1 Spring簡單整合Drools

在項目中使用Drools時往往會跟Spring整合來使用。具體整合步驟如下:

第一步:創建maven工程drools_spring并配置pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>drools_spring</artifactId><version>1.0-SNAPSHOT</version><properties><drools.version>7.10.0.Final</drools.version><spring.version>5.0.5.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>${drools.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.kie</groupId><artifactId>kie-spring</artifactId><version>${drools.version}</version><!--注意:此處必須排除傳遞過來的依賴,否則會跟我們自己導入的Spring jar包產生沖突--><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><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency></dependencies>
</project>

第二步:創建規則目錄/resources/rules,中rules目錄中創建規則文件helloworld.drl

package helloworldrule "rule_helloworld"wheneval(true)thenSystem.out.println("規則:rule_helloworld觸發...");
end

第三步:創建Spring配置文件/resources/spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:kie="http://drools.org/schema/kie-spring"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://drools.org/schema/kie-springhttp://drools.org/schema/kie-spring.xsd"><kie:kmodule id="kmodule"><kie:kbase name="kbase" packages="rules"><kie:ksession name="ksession"></kie:ksession></kie:kbase></kie:kmodule><bean class="org.kie.spring.annotations.KModuleAnnotationPostProcessor"></bean>
</beans>

第四步:編寫單元測試類

package com.itheima.test;import org.junit.Test;
import org.junit.runner.RunWith;
import org.kie.api.KieBase;
import org.kie.api.cdi.KBase;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring.xml")
public class DroolsSpringTest {@KBase("kbase")private KieBase kieBase;//注入KieBase對象@Testpublic void test1(){KieSession kieSession = kieBase.newKieSession();kieSession.fireAllRules();kieSession.dispose();}
}

6.2 Spring Boot整合Drools

目前在企業開發中Spring Boot已經成為主流,主要進行Spring Boot整合Drools。具體操作步驟:

第一步:創建maven工程drools_springboot并配置pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starters</artifactId><version>2.0.6.RELEASE</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>drools_springboot</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><!--drools規則引擎--><dependency><groupId>org.drools</groupId><artifactId>drools-core</artifactId><version>7.6.0.Final</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.6.0.Final</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-templates</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.kie</groupId><artifactId>kie-spring</artifactId><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><version>7.6.0.Final</version></dependency></dependencies><build><finalName>${project.artifactId}</finalName><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes><filtering>false</filtering></resource></resources><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build>
</project>

第二步:創建/resources/application.yml文件

server:port: 8080
spring:application:name: drools_springboot

第三步:創建規則文件/resources/rules/helloworld.drl

package helloworld
rule "rule_helloworld"wheneval(true)thenSystem.out.println("規則:rule_helloworld觸發...");
end

第四步:編寫配置類DroolsConfig

package com.itheima.drools.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.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.Resource;
import java.io.IOException;
/*** 規則引擎配置類*/
@Configuration
public class DroolsConfig {//指定規則文件存放的目錄private static final String RULES_PATH = "rules/";private final KieServices kieServices = KieServices.Factory.get();@Bean@ConditionalOnMissingBeanpublic KieFileSystem kieFileSystem() throws IOException {KieFileSystem kieFileSystem = kieServices.newKieFileSystem();ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");String path = null;for (Resource file : files) {path = RULES_PATH + file.getFilename();kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));}return kieFileSystem;}@Bean@ConditionalOnMissingBeanpublic KieContainer kieContainer() throws IOException {KieRepository kieRepository = kieServices.getRepository();kieRepository.addKieModule(kieRepository::getDefaultReleaseId);KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());kieBuilder.buildAll();return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());}@Bean@ConditionalOnMissingBeanpublic KieBase kieBase() throws IOException {return kieContainer().getKieBase();}@Bean@ConditionalOnMissingBeanpublic KModuleBeanFactoryPostProcessor kiePostProcessor() {return new KModuleBeanFactoryPostProcessor();}
}

第五步:創建RuleService類

package com.itheima.drools.service;import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class RuleService {@Autowiredprivate KieBase kieBase;public void rule(){KieSession kieSession = kieBase.newKieSession();kieSession.fireAllRules();kieSession.dispose();}
}

第六步:創建HelloController類

package com.itheima.drools.controller;import com.itheima.drools.service.RuleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/hello")
public class HelloController {@Autowiredprivate RuleService ruleService;@RequestMapping("/rule")public String rule(){ruleService.rule();return "OK";}
}

第七步:創建啟動類DroolsApplication

package com.itheima.drools;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class DroolsApplication {public static void main(String[] args) {SpringApplication.run(DroolsApplication.class,args);}
}

第八步:啟動服務,訪問http://localhost:8080/hello/rule
頁面返回OK

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/76710.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/76710.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/76710.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

框架PasteForm實際開發案例,換個口味顯示數據,支持echarts,只需要標記幾個特性即可在管理端顯示(2)

PasteForm框架的主要思想就是對Dto進行標記特性,然后管理端的頁面就會以不一樣的UI呈現 使用PasteForm框架開發,讓你免去開發管理端的煩惱,你只需要專注于業務端和用戶端! 在管理端中,如果說表格是基本的顯示方式,那么圖表chart就是一個錦上添花的體現! 如果一個項目擁…

【工具】在 Visual Studio 中使用 Dotfuscator 對“C# 類庫(DLL)或應用程序(EXE)”進行混淆

在 Visual Studio 中使用 Dotfuscator 進行混淆 Dotfuscator 是 Visual Studio 自帶的混淆工具&#xff08;Dotfuscator Community Edition&#xff0c;簡稱 CE&#xff09;。它可以混淆 C# 類庫&#xff08;DLL&#xff09;或應用程序&#xff08;EXE&#xff09;&#xff0c…

線程同步與互斥(上)

上一篇&#xff1a;線程概念與控制https://blog.csdn.net/Small_entreprene/article/details/146704881?sharetypeblogdetail&sharerId146704881&sharereferPC&sharesourceSmall_entreprene&sharefrommp_from_link我們學習了線程的控制及其相關概念之后&#…

[Linux系統編程]進程信號

進程信號 1. 信號入門1.1 信號基本概念1.2 技術應用角度的信號2. 信號的產生2.1 通過終端按鍵(如鍵盤)產生信號2.2 通過異常產生信號2.3 調用系統函數向進程發信號2.4 由軟件條件產生信號2.5 總結3. 阻塞信號3.1 信號其他相關常見概念3.2 內核中的信號表示3.3 sigset_t3.3.1 …

要素的選擇與轉出

1.要素選擇的三種方式 當要在已有的數據中選擇部分要素時&#xff0c;ArcMap提供了三種方式:按屬性選擇、位置選擇及按圖形選擇。 1)按屬性選擇 通過設置 SQL查詢表達式&#xff0c;用來選擇與選擇條件匹配的要素。 (1)單擊主菜單下【選擇】【按屬性選擇】&#xff0c;打開【按…

Springboot + Vue + WebSocket + Notification實現消息推送功能

實現功能 基于Springboot與Vue架構&#xff0c;首先使用Websocket實現頻道訂閱&#xff0c;在實現點對點與群發功能后&#xff0c;在前端調用windows自帶的消息通知&#xff0c;實現推送功能。 開發環境 Springboot 2.6.7vue 2.6.11socket-client 1.0.0 準備工作 在 Vue.js…

云手機如何防止設備指紋被篡改

云手機如何防止設備指紋被篡改 云手機作為虛擬化設備&#xff0c;其設備指紋的防篡改能力直接關系到賬戶安全、反欺詐和隱私保護。以下以亞矩陣云手機為例&#xff0c;講解云手機防止設備指紋被篡改的核心技術及實現方式&#xff1a; 系統層加固&#xff1a;硬件級安全防護 1…

有人DTU使用MQTT協議控制Modbus協議的下位機-含數據庫

本文為備忘錄&#xff0c;不做太多解釋。 DTU型號&#xff1a;G780 服務器&#xff1a;win2018 一。DTU設置 正確設置波特率&#xff0c;進入配置狀態&#xff0c;獲取當前參數&#xff0c;修改參數&#xff0c;設置并保存所有參數。 1.通道1設置 2.Modbus輪詢設置 二&am…

湖北師范大學計信學院研究生課程《工程倫理》9.6章節練習

以下是圖片中識別出的文字內容: 1【單選題】當工程師發現所在的企業或公司進行的工程活動會對環境、社會和公眾的人身安全產生危害時,應該及時地給予反映或揭發。這屬于工程師的( ) A、職業倫理責任 B、社會倫理責任 C、個人倫理責任 D、法律責任 2【單選題】下列哪個不屬于工…

Axure RP 9 詳細圖文安裝流程(附安裝包)教程包含下載、安裝、漢化、授權

文章目錄 前言一、Axure RP 9介紹二、Axure RP 9 安裝流程1. Axure RP 9 下載2. 啟動安裝程序3. 安裝向導操作4.完成安裝 三、Axure RP 9 漢化四、Axure RP 9授權 前言 本基礎安裝流程教程&#xff0c;將以清晰、詳盡且易于遵循的步驟介紹Axure RP 9 詳細圖文安裝流程&#xf…

SpringBoot全局exception處理最佳實踐

目錄 自定義異常類 拋出異常 全局異常處理器 自定義異常類 通常會繼承 Exception 或其子類(如 RuntimeException)來定義業務異常類,用于封裝業務相關的錯誤信息。一般選擇繼承 RuntimeException,因為它是一個非受檢異常,在方法中拋出時不需要顯式聲明。 // 自定義業…

node ---- 解決錯誤【Error: error:0308010C:digital envelope routines::unsupported】

1. 報錯 在 Node.js 18.18.0 的版本中&#xff0c;遇到以下錯誤&#xff1a; this[kHandle] new _Hash(algorithm, xofLen);^ Error: error:0308010C:digital envelope routines::unsupported這個錯誤通常發生在運行項目或構建時&#xff0c;尤其是在使用 Webpack、Vite 或其他…

浙江大學鄭小林教授解讀智能金融與AI的未來|附PPT下載方法

導 讀INTRODUCTION 隨著人工智能技術的飛速發展&#xff0c;智能金融已成為金融行業的重要變革力量。浙江大學人工智能研究所的鄭小林教授在2025年3月24日的《智能金融&#xff1a;AI驅動的金融變革》講座中&#xff0c;深入探討了新一代人工智能在金融領域的應用及未來展望。 …

如何實現瀏覽器中的報表打印

在瀏覽器中實現打印一個報表&#xff0c;可以通過以下幾種方法來完成。這里介紹一個基本的流程和相關代碼示例&#xff1a; 1. 使用 JavaScript 的 window.print() 方法 這是最簡單的方法&#xff0c;它會打開打印對話框&#xff0c;讓用戶選擇打印選項。 示例代碼&#xff1…

Linux系統調用編程

進程和線程 進程是操作系統資源分配的基本單位&#xff0c;擁有獨立的地址空間、內存、文件描述符等資源&#xff0c;進程間相互隔離。每個進程由程序代碼、數據段和進程控制塊&#xff08;PCB&#xff09;組成&#xff0c;PCB記錄了進程狀態、資源分配等信息。 線程是…

【力扣hot100題】(054)全排列

挺經典的回溯題的。 class Solution { public:vector<vector<int>> result;void recursion(vector<int>& nums,vector<int>& now){if(nums.size()0){result.push_back(now);return ;}for(int i0;i<nums.size();i){now.push_back(nums[i]);…

【Ragflow】11. 文件解析流程分析/批量解析實現

概述 本文繼續對ragflow文檔解析部分進行分析&#xff0c;并通過腳本的方式實現對文件的批量上傳解析。 文件解析流程 文件解析的請求處理流程大致如下&#xff1a; 1.前端上傳文件&#xff0c;通過v1/document/run接口&#xff0c;發起文件解析請求 2.后端api\apps\docum…

2024年零知識證明(ZK)研究進展

Sumcheck 整個領域正在轉向更多地依賴于 Sumcheck Protocol Sumcheck是用于驗證多項式承諾的協議,常用于零知識證明(ZKP)中,尤其是在可驗證計算和擴展性上。它的主要目的是通過對多項式進行分段檢查,從而保證某個多項式在給定輸入上的正確性,而不需要直接計算出整個多項…

thinkphp每條一級欄目中可自定義添加多條二級欄目,每條二級欄目包含多個字段信息

小程序客戶端需要展示團購詳情這種結構的內容,后臺會新增多條套餐,每條套餐可以新增多條菜品信息,每條菜品信息包含菜品名稱,價格,份數等字段信息,類似于購物網的商品多規格屬性,數據表中以json類型存儲,手寫了一個后臺添加和編輯的demo 添加頁面 編輯頁面(json數據…

Vue3引入ElementPlus

1.ElementPlus屬于第三方的應用框架&#xff0c;官網地址&#xff1a;設計 | Element Plus &#xff0c;學習可以參考該網站的指南。 2.安裝element-plus &#xff0c;指令為&#xff1a;npm install element-plus --save 3.引入elementplus的全局&#xff0c;組件、樣式、圖標…