日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Drools 规则引擎一文读懂

發布時間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Drools 规则引擎一文读懂 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

一、Drools 簡介

電商平臺的促銷活動

規則引擎

Drools 簡介

二、Drools 快速入門?

電商平臺促銷積分規則

開發實現

三、Drools 規則引擎構成及其核心類

Drools規則引擎構成

Drools規則引擎概念

四、Drools 基礎語法

規則文件構成

?規則體語法結構

規則注釋

Pattern模式匹配

規則比較操作符

操作步驟?

執行指定規則?

關鍵字

?五、Drools 規則屬性 attributes

enabled屬性?

dialect屬性

salience屬性?

no-loop屬性

?lock-on-active屬性

activation-group屬性

agenda-group屬性

auto-focus屬性

timer屬性

date-effective屬性

date-expires屬性

六、Drools高級語法

?global全局變量

query查詢

?function函數

條件-LHS加強

復合值限制in/not in

條件元素eval

條件元素not

條件元素exists

規則繼承

結果-RHS

insert方法

update方法

modify方法

retract/delete方法

RHS加強

halt

getWorkingMemory

getRule

規則文件編碼規范

七、WorkBench

?WorkBench簡介

配置 Tomcat

啟動服務器

WorkBench使用?

創建空間、項目

創建數據對象和drl文件

設置KieBase+KieSession

代碼使用?


一、Drools 簡介

電商平臺的促銷活動

????????小明是一家互聯網公司的軟件工程師,他們公司為了吸引新用戶經常會搞活動,小明常常為了做活動加班加點很煩躁,這不今天呀又來了一個活動需求,我們大家一起幫他看看。

????????活動規則是根據用戶購買訂單的金額給用戶送相應的積分,購買的越多送的積分越多,用戶可以使用積分來兌換相應的商品,我們這次活動的力度很大,肯定會吸引很多的用戶參加,產品經理小王興高采烈唾液橫飛的對小明講到。小明心想,又tm來這套,這次需求又要變更多少次呢?表面上還的配合,說趕緊把規則給我們吧,早點開發早點上線,小王說這次需求老簡單啦,估計你們兩個小時就搞定了,不信你看需求文檔。

100元以下, 不加分 100元-500元 加100分 500元-1000元 加500分 1000元 以上 加1000分

小明一看,這需求果然簡單呀,作為一個工作了兩三年的程序員來講,這不就是小case,半天搞定,送積分的核心代碼如下:

public void execute() throws Exception { List<Order> orderList = getInitData();for (int i=0; i<orderList.size(); i++){ Order order = orderList.get(i); if (order.getAmout() <= 100){ order.setScore(0); addScore(order); }else if(order.getAmout() > 100 && order.getAmout() <= 500){ order.setScore(100); addScore(order); }else if(order.getAmout() > 500 && order.getAmout() <= 1000){ order.setScore(500); addScore(order); }else{ order.setScore(1000); addScore(order); } } }

????????上線運行了半天之后,財務部的小財突然監測到活動賬戶的金額大為減少,發現產品做活動竟然沒有通知到他,非常不爽,于是給領導小馬說,這樣大規模的活動,對公司財務有壓力,領導小馬權衡了一番說,這樣吧活動繼續,但是金額翻倍再送積分,于是規則變成了這樣:200元以下不給積分,1000元以下給100積分…

????????小明看領導都發話了,沒辦法改呀,不過也簡單,就是將里面的值都翻了倍,在投產上去,只是挨了不少測試的白眼。

????????活動又進行了一天,運營人員通過后臺監控發現提到2倍以后,用戶積極性變的很差,活動效果不理想,和領導商議了一下,改為最初規則的1.5倍,及150元一下不給積分,750元以下給100積分… 小明這時候的心情大概是這樣子的,一萬個下圖動物狂奔而過。

????????沒辦法還得改不是,當然這次小明可學乖了,將這些數據(多少元送多少分)存到了數據庫中,當老板再改主意的時候,只要改一下數據庫的值就可以了,小明為自己的明聰明到有點小高興。?

核心代碼:

public void execute() throws Exception { List<Order> orderList = getInitData();List<int> values = getTableValues();for (int i=0; i<orderList.size(); i++){ Order order = orderList.get(i); if (order.getAmout() <= values.get(0)){ order.setScore(values.get(3)); addScore(order); }else if(order.getAmout() > values.get(0) && order.getAmout() <= values.get(1)){ order.setScore(values.get(4)); addScore(order); }else if(order.getAmout() > values.get(1) && order.getAmout() <= values.get(2)){ order.setScore(values.get(5)); addScore(order); }else{ order.setScore(values.get(6)); addScore(order); } } }

????????正當小明得意洋洋的打了個最新版本投產上線之后,產品經理小王說積分規則層次太少了,由以前的4組變成8組,小明此刻的心情:kao …

????????小明想這樣下去非得被他們弄死,必須要找找有什么技術可以將活動規則和代碼解耦,不管規則如何變化,執行端不用動。小明搜了半天還真有這樣的東西,那就是規則引擎,那么規則引擎到底是什么東西呢?我們來看看。

規則引擎

????????規則引擎:全稱為業務規則管理系統,英文名為BRMS。規則引擎的主要思想是將應用程序中的業務決策部分分離出來,并使用預定義的語義模塊編寫業務決策(業務規則),由用戶或 開發者在需要時進行配置、管理。需要注意的是規則引擎并不是一個具體的技術框架,而是指的一類系統,即業務規則管理系統。

????????java開源的規則引擎有:Drools、Easy Rules、Mandarax、IBM ILOG。使用最為廣泛并且開源的是Drools。

主要應用場景:

????????對于一些存在比較復雜的業務規則并且業務規則會頻繁變換的系統比較適合使用規則引擎,如下:

  • 風控系統-------風險貸款、風險評估
  • 反欺詐項目-----銀行貸款、征信驗證
  • 決策平臺-------財務計算
  • 電商平臺------滿減、打折、加價購

Drools 簡介

????????Drools 是用 Java 語言編寫的開放源碼規則引擎,使用 Rete 算法對所編寫的規則求值。Drools 允許使用聲明方式表達業務邏輯。可以使用非 XML 的本地語言編寫規則,從而便于學習和理解。并且,還可以將 Java 代碼直接嵌入到規則文件中,這令 Drools 的學習更加吸引人。

Drools 還具有其他優點:

  • 非常活躍的社區支持
  • 易用
  • 快速的執行速度
  • 在 Java 開發人員中流行
  • 與 Java Rule Engine API(JSR 94)兼容

Drools 是業務邏輯集成平臺,被分為4個項目:

  • Drools Guvnor (BRMS/BPMS):業務規則管理系統
  • Drools Expert (rule engine):規則引擎,drools的核心部分
  • Drools Flow (process/workflow):工作流引擎
  • Drools Fusion (cep/temporal reasoning):事件處理

官網:http://www.drools.org/#
官方文檔:http://www.drools.org/learn/documentation.html

在項目中使用drools 時,即可以單獨使用也可以整合spring使用,如果是單獨使用僅需要導入以下maven 依賴即可。

<!--添加規則引擎依賴--><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.73.0.Final</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-mvel</artifactId><version>7.73.0.Final</version></dependency>

Drools API 開發步驟如下:

二、Drools 快速入門?

電商平臺促銷積分規則

100元以下, 不加分 100元-500元 加100分 500元-1000元 加500分 1000元 以上 加1000分

開發實現

第一步:創建Maven項目,添加Drools 規則引擎依賴。

<!--添加規則引擎依賴--><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.73.0.Final</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-mvel</artifactId><version>7.73.0.Final</version></dependency><!--添加單元測試工具類--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency>

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

需要有一個配置文件告訴代碼規則文件drl 在哪里,在drools中這個文件就是kmodule.xml。

<?xml version="1.0" encoding="UTF-8"?> <kmodule xmlns="http://www.drools.org/xsd/kmodule"><!--name:指定kbase 名稱,可以是任意但必須唯一packages:指定規則文件存放目錄,依據實際情況進行填寫default:指定當前的kbase 是否為默認--><kbase name="rules" packages="rules" default="true"><!--name:指定ksession名稱,可以是任意但必須唯一default:指定ksession 是否為默認--><ksession name="ksession-rules" default="true"/></kbase> </kmodule>

第三步:創建業務實體對象

package com.zzg.model;public class Order implements java.io.Serializable {private int amount; //訂單金額private int score; //訂單積分@Overridepublic String toString() {return "Order{" +"amount=" + amount +", score=" + score +'}';}public int getAmount() {return amount;}public void setAmount(int amount) {this.amount = amount;}public int getScore() {return score;}public void setScore(int score) {this.score = score;} }

第四步:創建規則文件,在resources/rules/score-rules.drl

package rules;import com.zzg.model.Order;// 100 元以下不加分 rule "score_1" when$order:Order(amount<100); then$order.setScore(0);System.out.println("觸發100元以下,不加積分"); end // 100-500 元, 加100積分 rule "score_2" when$order:Order(amount>100 && amount <= 500); then$order.setScore(100);System.out.println("觸發100-500 元, 加100積分"); end // 500-10000 元, 加500積分 rule "score_3" when$order:Order(amount>500 && amount <= 1000); then$order.setScore(500);System.out.println("觸發500-1000 元, 加500積分"); end // 大于1000 元, 加1000積分 rule "score_4" when$order:Order(amount>1000); then$order.setScore(1000);System.out.println("觸發大于1000 元, 加1000積分"); end

第五步:單元測試

package com.zzg;import com.zzg.model.Order; import org.junit.Test; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession;public class TestDrools {@Testpublic void test1() {// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步KieContainer kieContainer = kieServices.getKieClasspathContainer();// 第三步KieSession kieSession = kieContainer.newKieSession();// 業務對象Order order = new Order();order.setAmount(100);// 第四步kieSession.insert(order);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();System.out.println("指定規則引擎后的結果:" + order.getScore());} }

效果截圖:

23:01:01.112 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: rules 23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES 23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING 23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE 23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED 指定規則引擎后的結果:0

三、Drools 規則引擎構成及其核心類

Drools規則引擎構成

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

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

其中Inference Engine(t推理引擎)又包含如下:

  • Pattern Match(匹配器)具體匹配那一個規則,由它來完成
  • Agenda(議程)
  • Execution Engine(執行引擎)

Drools規則引擎概念

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

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

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

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

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

四、Drools 基礎語法

規則文件構成

drl是Drools Rule Language的縮寫

一套完整的規則文件內容構成如下:

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

?規則體語法結構

一個規則通常包含三個部分:屬性部分(attribute)、條件部分(LHS)和結果部分(RHS)

語法結構體:

rule "ruleName"attributeswhenLHS thenRHS end

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

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

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

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

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

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

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

規則注釋

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

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

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

Pattern模式匹配

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

語法:

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

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

入門案例中:

package rules;import com.zzg.model.Order;// 100 元以下不加分 rule "score_1" when$order:Order(amount<100); then$order.setScore(0);System.out.println("觸發100元以下,不加積分"); end

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

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

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

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

綁定變量既可以用在對象上,也可以用在對象的屬性上。入門案例如下:

// 100-500 元, 加100積分 rule "score_2" when$order:Order($fieldAmount:amount > 100 && amount <= 500); thenSystem.out.println("$fieldAmount=" + $fieldAmount);$order.setScore(100);System.out.println("觸發100-500 元, 加100積分"); end

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

規則比較操作符

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

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

操作步驟?

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

package com.zzg.model;import java.util.List;public class ComparisonEntity implements java.io.Serializable {/*** 名字集合*/private String names;/*** 字符串集合*/private List<String> list;@Overridepublic String toString() {return "ComparisonEntity{" +"names='" + names + '\'' +", list=" + 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下創建規則文件comparison.drl

package rulesimport com.zzg.model.ComparisonEntity;/*用于測試Drools提供的比較操作符 *///測試比較操作符contains rule "rule_comparison_contains"whenComparisonEntity(names contains "張三")ComparisonEntity(list contains names)thenSystem.out.println("規則rule_comparison_contains觸發"); end//測試比較操作符not contains rule "rule_comparison_notContains"whenComparisonEntity(names not contains "張三")ComparisonEntity(list not contains names)thenSystem.out.println("規則rule_comparison_notContains觸發"); end//測試比較操作符memberOf rule "rule_comparison_memberOf"whenComparisonEntity(names memberOf list)thenSystem.out.println("規則rule_comparison_memberOf觸發"); end//測試比較操作符not memberOf rule "rule_comparison_notMemberOf"whenComparisonEntity(names not memberOf list)thenSystem.out.println("規則rule_comparison_notMemberOf觸發"); end//測試比較操作符matches rule "rule_comparison_matches"whenComparisonEntity(names matches "張.*")thenSystem.out.println("規則rule_comparison_matches觸發"); end//測試比較操作符not matches rule "rule_comparison_notMatches"whenComparisonEntity(names not matches "張.*")thenSystem.out.println("規則rule_comparison_notMatches觸發"); end

第三步:編寫單元測試

@Testpublic void test2() {// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步KieContainer kieContainer = kieServices.getKieClasspathContainer();// 第三步KieSession kieSession = kieContainer.newKieSession();// 業務對象ComparisonEntity comparisonEntity = new ComparisonEntity();comparisonEntity.setNames("張三");List<String> list = new ArrayList<>();list.add("張三");list.add("李四");comparisonEntity.setList(list);// 第四步kieSession.insert(comparisonEntity);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();}

效果截圖:

09:52:42.457 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES 規則rule_comparison_contains觸發 規則rule_comparison_memberOf觸發 規則rule_comparison_matches觸發 09:52:42.488 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING 09:52:42.488 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE 09:52:42.488 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

執行指定規則?

????????在調用規則代碼時,滿足條件的規則都會被執行。那么如果我們只想執行其中的某個規則如何實現呢?

????????Drools給我們提供的方式是通過規則過濾器來實現執行指定規則。對于規則文件不用做任何修改,只需要修改Java代碼即可,如下:

//通過規則過濾器實現只執行指定規則 kieSession.fireAllRules(new kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule 名稱"));

關鍵字

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

示例:

rule true //不可以

rule "true" 可以

?五、Drools 規則屬性 attributes

前面我們已經知道了規則體的構成如下:

rule "ruleName"attributeswhenLHSthenRHS end

本章節就是針對規則體的attributes屬性部分進行講解。Drools中提供的屬性如下表(部分屬性):

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

enabled屬性?

enabled屬性對應的取值為true和false,默認值為true。

用于指定當前規則是否啟用,如果設置的值為false則當前規則無論是否匹配成功都不會觸發

第一步:創建實體類,用于測試屬性attributes

package com.zzg.model;public class AttributesEnabledEntity implements java.io.Serializable {private int num;@Overridepublic String toString() {return "AttributesEnabledEntity{" +"num=" + num +'}';}public int getNum() {return num;}public void setNum(int num) {this.num = num;} }

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

package rules;import com.zzg.model.AttributesEnabledEntity;/*用于測試Drools 屬性:enabled *///測試enabled rule "rule_attributes_enabled"enabled falsewhenAttributesEnabledEntity(num > 10)thenSystem.out.println("規則rule_attributes_enabled觸發"); end

第三步:編寫單元測試

@Testpublic void test4() {// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步KieContainer kieContainer = kieServices.getKieClasspathContainer();// 第三步KieSession kieSession = kieContainer.newKieSession();// 業務對象AttributesEnabledEntity enabledEntity = new AttributesEnabledEntity();enabledEntity.setNum(11);// 第四步kieSession.insert(enabledEntity);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();}

dialect屬性

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

注:mvel是一種基于java語法的表達式語言。

雖然mvel吸收了大量的java語法,但作為一個表達式語言,還是有著很多重要的不同之處,以達到更高的效率,比如:mvel像正則表達式一樣,有直接支持集合、數組和字符串匹配的操作符。

除了表達式語言外,mvel還提供了用來配置和構造字符串的模板語言。

mvel2.x表達式包含以下部分的內容:屬性表達式,布爾表達式,方法調用,變量賦值,函數定義

salience屬性?

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

attributes-rules.drl文件添加如下內容:

/*用于測試Drools 屬性:salience */rule "rule_attributes_salience_1"salience 10whenAttributesEnabledEntity(flag == true)thenSystem.out.println("規則 rule_attributes_salience_1 觸發"); endrule "rule_attributes_salience_2"salience 20whenAttributesEnabledEntity(flag == true)thenSystem.out.println("規則 rule_attributes_salience_2 觸發"); endrule "rule_attributes_salience_3"salience 1whenAttributesEnabledEntity(flag == true)thenSystem.out.println("規則 rule_attributes_salience_3 觸發"); end

AttributesEnabledEntity 類新增boolean 類型(flag字段)

private boolean flag;

效果截圖:

10:39:16.506 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES 規則 rule_attributes_salience_2 觸發 規則 rule_attributes_salience_1 觸發 規則 rule_attributes_salience_3 觸發

no-loop屬性

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

attributes-rules.drl文件添加如下內容:

/*用于測試Drools 屬性:no-loop */rule "rule_attributes_noloop"//no-loop truewhen$attributesNoLoopEntity:AttributesEnabledEntity(num > 1)thenupdate($attributesNoLoopEntity)System.out.println("規則 rule_attributes_noloop 觸發"); end

第二步:編寫單元測試

@Testpublic void test4() {// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步KieContainer kieContainer = kieServices.getKieClasspathContainer();// 第三步KieSession kieSession = kieContainer.newKieSession();// 業務對象AttributesEnabledEntity enabledEntity = new AttributesEnabledEntity();enabledEntity.setNum(11);enabledEntity.setFlag(true);// 第四步kieSession.insert(enabledEntity);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();}

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

?lock-on-active屬性

lock-on-active這個屬性,可以限制當前規則只會被執行一次,包括當前規則的重復執行不是本身觸發的。取值類型為Boolean,默認值為false。測試步驟如下:

attributes-rules.drl文件添加如下內容:

/*用于測試Drools 屬性:lock-on-active */rule "rule_attributes_lock_on_active_1"no-loop truewhen$attributesLockOnActiveEntity:AttributesEnabledEntity(num > 1)thenupdate($attributesLockOnActiveEntity)System.out.println("規則 rule_attributes_lock_on_active_1 觸發"); endrule "rule_attributes_lock_on_active_2"no-loop truelock-on-active truewhen$attributesLockOnActiveEntity:AttributesEnabledEntity(num > 1)thenupdate($attributesLockOnActiveEntity)System.out.println("規則 rule_attributes_lock_on_active_2 觸發"); end

編寫單元測試:

@Testpublic void test4() {// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步KieContainer kieContainer = kieServices.getKieClasspathContainer();// 第三步KieSession kieSession = kieContainer.newKieSession();// 業務對象AttributesEnabledEntity enabledEntity = new AttributesEnabledEntity();enabledEntity.setNum(11);enabledEntity.setFlag(true);// 第四步kieSession.insert(enabledEntity);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();}

????????no-loop的作用是限制因為modify等更新操作導致規則重復執行,但是有一個限定條件,是當前規則中進行更新導致當前規則重復執行。而不是防止其他規則更新相同的fact對象,導致當前規則更新,lock-on-active可以看作是no-loop的加強版,不僅能限制自己的更新,還能限制別人的更新造成的死循環。

activation-group屬性

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

第一步:編寫規則文件

package rules import com.zzg.model.AttributesActivationGroupEntity/*用于測試Drools 屬性: activation-group */rule "rule_attributes_activation_group_1"activation-group "customGroup"when$attributesActivationGroupEntity:AttributesActivationGroupEntity(num > 1)thenSystem.out.println("規則 rule_attributes_activation_group_1 觸發"); endrule "rule_attributes_activation_group_2"activation-group "customGroup"when$attributesActivationGroupEntity:AttributesActivationGroupEntity(num > 1)thenSystem.out.println("規則 rule_attributes_activation_group_2 觸發"); end

編寫單元測試:

// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步KieContainer kieContainer = kieServices.getKieClasspathContainer();// 第三步KieSession kieSession = kieContainer.newKieSession(); // 業務對象 AttributesActivationGroupEntity attributesActivationGroupEntity = new AttributesActivationGroupEntity();attributesActivationGroupEntity.setNum(20);kieSession.insert(attributesActivationGroupEntity);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();

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

agenda-group屬性

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

第一步:編寫規則文件

package rules import com.zzg.model.AttributesAgendaGroupEntity/*用于測試Drools 屬性: agenda-group */rule "rule_attributes_agenda_group_1"agenda-group "customAgendaGroup1"when$attributesAgendaGroupEntity:AttributesAgendaGroupEntity(num > 1)thenSystem.out.println("規則 rule_attributes_agenda_group_1 觸發"); endrule "rule_attributes_agenda_group_2"agenda-group "customAgendaGroup1"when$attributesAgendaGroupEntity:AttributesAgendaGroupEntity(num > 1)thenSystem.out.println("規則 rule_attributes_agenda_group_2 觸發"); endrule "rule_attributes_activation_group_3"agenda-group "customAgendaGroup2"when$attributesAgendaGroupEntity:AttributesAgendaGroupEntity(num > 1)thenSystem.out.println("規則 rule_attributes_activation_group_3 觸發"); endrule "rule_attributes_agenda_group_4"agenda-group "customAgendaGroup2"when$attributesAgendaGroupEntity:AttributesAgendaGroupEntity(num > 1)thenSystem.out.println("規則 rule_attributes_agenda_group_4 觸發"); end

編寫單元測試:

// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 AttributesAgendaGroupEntity attributesAgendaGroupEntity = new AttributesAgendaGroupEntity();attributesAgendaGroupEntity.setNum(20);kieSession.insert(attributesAgendaGroupEntity);kieSession.getAgenda().getAgendaGroup("customAgendaGroup2").setFocus();// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();

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

auto-focus屬性

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

第一步:編寫規則文件

package rules import com.zzg.model.AttributesAutoFocusEntity/*用于測試Drools 屬性: auto-focus */rule "rule_attributes_auto_focus_1"agenda-group "customAgendaGroup1"when$attributesAutoFocusEntity:AttributesAutoFocusEntity(num > 1)thenSystem.out.println("規則 rule_attributes_auto_focus_1 觸發"); endrule "rule_attributes_auto_focus_2"agenda-group "customAgendaGroup1"when$attributesAutoFocusEntity:AttributesAutoFocusEntity(num > 1)thenSystem.out.println("規則 rule_attributes_auto_focus_2 觸發"); endrule "rule_attributes_auto_focus_3"agenda-group "customAgendaGroup2" // auto-focus truewhen$attributesAutoFocusEntity:AttributesAutoFocusEntity(num > 1)thenSystem.out.println("規則 rule_attributes_auto_focus_3 觸發"); endrule "rule_attributes_auto_focus_4"agenda-group "customAgendaGroup2"when$attributesAutoFocusEntity:AttributesAutoFocusEntity(num > 1)thenSystem.out.println("規則 rule_attributes_auto_focus_4 觸發"); end

編寫單元測試

// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 AttributesAutoFocusEntity attributesAutoFocusEntity = new AttributesAutoFocusEntity();attributesAutoFocusEntity.setNum(20);kieSession.insert(attributesAutoFocusEntity);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();

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

注意:同一個組,只要有個設置auto-focus true 其他的設置不設置都無所謂啦。都會起作用的。

timer屬性

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

方式一:timer (int:??)

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

方式二:timer(cron:?)

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

第一步:編寫規則文件

package rules import com.zzg.model.AttributesTimerEntity/*用于測試Drools 屬性: timer */rule "rule_attributes_timer_1"timer(5s 2s)when$attributesTimerEntity:AttributesTimerEntity(num > 1)thenSystem.out.println("規則 rule_attributes_timer_1 觸發"); endrule "rule_attributes_timer_2"timer(cron:0/1 * * * * ?)when$attributesTimerEntity:AttributesTimerEntity(num > 1)thenSystem.out.println("規則 rule_attributes_timer_2 觸發"); end

編寫單元測試:

// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 AttributesTimerEntity attributesTimerEntity = new AttributesTimerEntity();attributesTimerEntity.setNum(20);kieSession.insert(attributesTimerEntity);kieSession.fireUntilHalt();Thread.sleep(10000);kieSession.halt(); // 關閉kieSession.dispose();

注意:如果規則中有用到了timer屬性,匹配規則需要調用kieSession.fireUntilHalt();這里涉及一個規則引擎的執行模式和線程問題,關于具體細節,我們后續討論。

date-effective屬性

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

第一步:編寫規則文件

package rules import com.zzg.model.AttributesDateEffectiveEntity/*用于測試Drools 屬性: date-effective */rule "rule_attributes_date_effective" // date-effective "20-七月-2021"date-effective "2021-02-20"when$attributesDateEffectiveEntity:AttributesDateEffectiveEntity(num > 1)thenSystem.out.println("規則 rule_attributes_date_effective 觸發"); end

編寫單元測試

// 第一步 KieServices kieServices = KieServices.Factory.get(); // 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 AttributesDateEffectiveEntity attributesDateEffectiveEntity = new AttributesDateEffectiveEntity();attributesDateEffectiveEntity.setNum(20);kieSession.insert(attributesDateEffectiveEntity); // 第五步:執行規則引擎 kieSession.fireAllRules(); // 第六步:關閉session kieSession.dispose();

注意:需要在VM參數上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,在生產環境所在規則引擎的JVM設置中,也需要設置此參數,以保證開發和生產的一致性。

date-expires屬性

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

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

package rules import com.zzg.model.AttributesDateExpiresEntity/*用于測試Drools 屬性: date-expires */rule "rule_attributes_date_expires"date-expires "2021-06-20"when$attributesDateExpiresEntity:AttributesDateExpiresEntity(num > 1)thenSystem.out.println("規則 rule_attributes_date_expires 觸發"); end

編寫單元測試

// 第一步 KieServices kieServices = KieServices.Factory.get(); // 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 AttributesDateExpiresEntity attributesDateExpiresEntity = new AttributesDateExpiresEntity();attributesDateExpiresEntity.setNum(20);kieSession.insert(attributesDateExpiresEntity);// 第五步:執行規則引擎kieSession.fireAllRules();// 第六步:關閉sessionkieSession.dispose();

注意:需要在VM參數上加上日期格式:-Ddrools.dateformat=yyyy-MM-dd,在生產環境所在規則引擎的JVM設置中,也需要設置此參數,以保證開發和生產的一致性。

六、Drools高級語法

我們已經知道了一套完整的規則文件內容構成如下:

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

?global全局變量

global關鍵字用于在規則文件中定義全局變量,它可以讓應用程序的對象在規則文件中能夠被訪問。可以用來為規則文件提供數據或服務。

語法結構為:global 對象類型 對象名稱

在使用global定義的全局變量時有兩點需要注意:

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

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

第一步:編寫規則文件

package rules import com.zzg.model.GlobalEntity/*用于測試Drools 全局變量 : global */global java.lang.Integer globalCount global java.util.List globalListrule "rule_global_1"when$globalEntity:GlobalEntity(num > 1)thenSystem.out.println("規則 rule_global_1 開始...");globalCount++ ;globalList.add("張三");globalList.add("李四");System.out.println(globalCount);System.out.println(globalList);System.out.println("規則 rule_global_1 結束..."); endrule "rule_global_2"when$globalEntity:GlobalEntity(num > 1)thenSystem.out.println("規則 rule_global_2 開始...");System.out.println(globalCount);System.out.println(globalList);System.out.println("規則 rule_global_2 結束..."); end

編寫單元測試

// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.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();// 第六步:關閉sessionkieSession.dispose();

query查詢

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

語法結構如下:

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

編寫規則文件

package rules import com.zzg.model.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

編寫單元測試

// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.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(queryEntity);}for (QueryResultsRow queryResultsRow : results2) {QueryEntity queryEntity = (QueryEntity) (queryResultsRow.get("$queryEntity"));System.out.println(queryEntity);} // 第五步:執行規則引擎 kieSession.fireAllRules(); // 第六步:關閉session kieSession.dispose();

?function函數

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

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

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

編寫規則文件/resources/rules/function.drl

package rules import com.zzg.model.FunctionEntity/*用于測試Drools 方法: function *///定義一個 假發 方法 function Integer add(Integer num){return num+10; }rule "function"when$functionEntity:FunctionEntity(num>20)thenInteger result = add($functionEntity.getNum());System.out.println(result); end

編寫單元測試

// 第一步 KieServices kieServices = KieServices.Factory.get(); // 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 FunctionEntity functionEntity = new FunctionEntity(); functionEntity.setNum(30);kieSession.insert(functionEntity);// 第五步:執行規則引擎 kieSession.fireAllRules(); // 第六步:關閉session kieSession.dispose();

條件-LHS加強

前面我們已經知道了在規則體中的LHS部分是介于when和then之間的部分,主要用于模式匹配,只有匹配結果為true時,才會觸發RHS部分的執行。本章節我們會針對LHS部分學習幾個新的用法。

復合值限制in/not in

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

語法結構如下:

Object(field in (比較值1,比較值2...))

編寫規則文件

package rules import com.zzg.model.LhsInEntity/*用于測試Drools LHS: in not in */rule "lhs_in"when$lhsInEntity:LhsInEntity(name in ("張三","李四","王五"))thenSystem.out.println("規則 lhs_in 觸發"); endrule "lhs_not_in"when$lhsInEntity:LhsInEntity(name not in ("張三","李四","王五"))thenSystem.out.println("規則 lhs_not_in 觸發"); end

條件元素eval

eval用于規則體的LHS部分,并返回一個Boolean類型的值。

語法結構如下:

eval(表達式)

編寫規則文件

package rules import com.zzg.model.LhsEvalEntity/*用于測試Drools LHS: in not in */rule "lhs_eval"when$lhsInEntity:LhsEvalEntity(age > 10) and eval(2>1)thenSystem.out.println("規則 lhs_eval 觸發"); end

條件元素not

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

語法結構如下:

not Object(可選屬性約束)

編寫規則文件

package rules import com.zzg.model.LhsNotEntity/*用于測試Drools LHS: not */rule "lhs_not"whennot $lhsNotEntity:LhsNotEntity(age > 10)thenSystem.out.println("規則 lhs_not 觸發"); end

條件元素exists

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

語法結構如下:

exists Object(可選屬性約束)

編寫規則文件

package rules import com.zzg.model.LhsEvalEntity/*用于測試Drools LHS: exists */rule "lhs_exists"whenexists $lhsInEntity:LhsEvalEntity(age > 10)thenSystem.out.println("規則 lhs_eval 觸發"); end

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

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

規則繼承

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

結果-RHS

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

insert方法

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

編寫規則文件

package rules import com.zzg.model.RhsInsertEntity/*用于測試Drools RHS: insert */rule "rhs_insert_1"when$rhsInsertEntity:RhsInsertEntity(age <= 10)thenRhsInsertEntity rhsInsertEntity = new RhsInsertEntity();rhsInsertEntity.setAge(15);insert(rhsInsertEntity);System.out.println("規則 rhs_insert_1 觸發"); endrule "rhs_insert_2"when$rhsInsertEntity:RhsInsertEntity(age <=20 && age>10)thenRhsInsertEntity rhsInsertEntity = new RhsInsertEntity();rhsInsertEntity.setAge(25);insert(rhsInsertEntity);System.out.println("規則 rhs_insert_2 觸發"); endrule "rhs_insert_3"when$rhsInsertEntity:RhsInsertEntity(age > 20 )thenSystem.out.println("規則 rhs_insert_3 觸發"); end

編寫單元測試

// 第一步 KieServices kieServices = KieServices.Factory.get(); // 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 RhsInsertEntity rhsInsertEntity = new RhsInsertEntity(); rhsInsertEntity.setAge(5);kieSession.insert(rhsInsertEntity);// 第五步:執行規則引擎 kieSession.fireAllRules(); // 第六步:關閉session kieSession.dispose();

通過控制臺輸出可以發現,3個規則都觸發了,這是因為首先進行規則匹配時只有第一個規則可以匹配成功,但是在第一個規則中向工作內存中插入了一個數據導致重新進行規則匹配,此時第二個規則可以匹配成功。在第二個規則中同樣向工作內存中插入了一個數據導致重新進行規則匹配,那么第三個規則就出發了。

update方法

update方法的作用是更新工作內存中的數據,并讓相關的規則重新匹配。?(要避免死循環)

編寫規則文件

package rules import com.zzg.model.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 觸發"); endrule "rhs_update_2"when$rhsUpdateEntity:RhsUpdateEntity(age <=20 && age>10)then$rhsUpdateEntity.setAge(25);update($rhsUpdateEntity);System.out.println("規則 rhs_update_2 觸發"); endrule "rhs_update_3"when$rhsUpdateEntity:RhsUpdateEntity(age > 20 )thenSystem.out.println("規則 rhs_update_3 觸發"); end

編寫單元測試

// 第一步 KieServices kieServices = KieServices.Factory.get(); // 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 RhsUpdateEntity rhsUpdateEntity = new RhsUpdateEntity(); rhsUpdateEntity.setAge(5);kieSession.insert(rhsUpdateEntity);// 第五步:執行規則引擎 kieSession.fireAllRules(); // 第六步:關閉session kieSession.dispose();

通過控制臺的輸出可以看到規則文件中定義的三個規則都觸發了。

在更新數據時需要注意防止發生死循環。

modify方法

modify方法的作用跟update一樣,是更新工作內存中的數據,并讓相關的規則重新匹配。只不過語法略有區別?(要避免死循環)

編寫規則文件

package rules import com.zzg.model.RhsModifyEntity/*用于測試Drools RHS: modify */rule "rhs_modify_1"when$rhsModifyEntity:RhsModifyEntity(age <= 10)thenmodify($rhsModifyEntity){setAge(15)}System.out.println("規則 rhs_modify_1 觸發"); endrule "rhs_modify_2"when$rhsModifyEntity:RhsModifyEntity(age <=20 && age>10)thenmodify($rhsModifyEntity){setAge(25)}System.out.println("規則 rhs_modify_2 觸發"); endrule "rhs_modify_3"when$rhsModifyEntity:RhsModifyEntity(age > 20 )thenSystem.out.println("規則 rhs_modify_3 觸發"); end

編寫單元測試

// 第一步 KieServices kieServices = KieServices.Factory.get(); // 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 RhsModifyEntity rhsModifyEntity = new RhsModifyEntity(); rhsModifyEntity.setAge(5);kieSession.insert(rhsModifyEntity);// 第五步:執行規則引擎 kieSession.fireAllRules(); // 第六步:關閉session kieSession.dispose();

通過控制臺的輸出可以看到規則文件中定義的三個規則都觸發了。

在更新數據時需要注意防止發生死循環。

retract/delete方法

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

編寫規則文件

package rules import com.zzg.model.RhsRetractEntity/*用于測試Drools RHS: retract */rule "rhs_retract_1"when$rhsRetractEntity:RhsRetractEntity(age <= 10)then // retract($rhsRetractEntity);System.out.println("規則 rhs_retract_1 觸發"); endrule "rhs_retract_2"when$rhsRetractEntity:RhsRetractEntity(age <= 10)thenSystem.out.println("規則 rhs_retract_2 觸發"); end

編寫單元測試

// 第一步 KieServices kieServices = KieServices.Factory.get(); // 第二步 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 第三步 KieSession kieSession = kieContainer.newKieSession(); // 業務對象 RhsRetractEntity rhsRetractEntity = new RhsRetractEntity(); rhsRetractEntity.setAge(5);kieSession.insert(rhsRetractEntity); // 第五步:執行規則引擎 kieSession.fireAllRules(); // 第六步:關閉session kieSession.dispose();

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

RHS加強

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

在RHS部分Drools為我們提供了一個內置對象,名稱就是drools。本小節我們來介紹幾個drools對象提供的方法。

halt

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

編寫規則文件

package rules import com.zzg.model.RhsHaftEntity/*用于測試Drools RHS: haft */rule "rhs_haft_1"when$rhsHaftEntity:RhsHaftEntity(age <= 10)thendrools.halt();System.out.println("規則 rhs_haft_1 觸發"); endrule "rhs_haft_2"when$rhsHaftEntity:RhsHaftEntity(age <= 20)thenSystem.out.println("規則 rhs_haft_2 觸發"); end

getWorkingMemory

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

rule "rhs_get_working_memory_1"when$rhsDroolsMethodsEntity:RhsDroolsMethodsEntity(age <= 10)thenSystem.out.println(drools.getWorkingMemory());System.out.println("規則 rhs_get_working_memory_1 觸發"); end

getRule

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

rule "rhs_rule_2"when$rhsDroolsMethodsEntity:RhsDroolsMethodsEntity(age <=20)thenSystem.out.println(drools.getRule());System.out.println("規則 rhs_rule_2 觸發"); end

規則文件編碼規范

我們在進行drl類型的規則文件編寫時盡量遵循如下規范:

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

七、WorkBench

?WorkBench簡介

WorkBench是KIE組件中的元素,也稱為KIE-WB,是Drools-WB與JBPM-WB的結合體。它是一個可視化的規則編輯器。WorkBench其實就是一個war包。

WorkBench經過幾次版本迭代,已經不提供tomcat啟動的war包,綜合考慮,本課程仍然采用 tomcat版本作為演示。

環境:

  • apache-tomcat-9.0.29
  • kie-drools-wb-7.6.0.Final-tomcat8 下載地址:Drools - Download

說明:

準備jar包:需要放到tomcat lib中,否則啟動失敗

具體安裝步驟:

配置 Tomcat

1.修改tomcat-user.xml,添加用戶

<?xml version="1.0" encoding="UTF-8"?> <tomcat-users xmlns="http://tomcat.apache.org/xml"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"version="1.0"><!--定義admin角色--><role rolename="admin"/><!--定義一個用戶,用戶名為kie,密碼為kie,對應的角色為admin角色--><user username="kie-web" password="kie-web123" roles="admin"/><user username="admin" password="admin" roles="manager-gui,manager-script,manager-jmx,manager-status"/> </tomcat-users>

2.修改server.xml

<Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="true"><!-- SingleSignOn valve, share authentication between web applicationsDocumentation at: /docs/config/valve.html --><!--<Valve className="org.apache.catalina.authenticator.SingleSignOn" />--><!-- Access log processes all example.Documentation at: /docs/config/valve.htmlNote: The pattern used is equivalent to using pattern="common" --><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"prefix="localhost_access_log" suffix=".txt"pattern="%h %l %u %t &quot;%r&quot; %s %b" /><Valve className="org.kie.integration.tomcat.JACCValve"/></Host>

3.復制jar到tomcat根目錄的lib下面:

kie-tomcat-integration-7.10.0.Final.jar javax.security.jacc-api-1.5.jar slf4j-api-1.7.25.jar

4.復制 kie-drools-wb-7.6.0.Final-tomcat8.war 到tomcat webapp下面并修改成kie-web.war

啟動服務器

啟動tomcat

訪問http://localhost:8080/kie-web,可以看到WorkBench的登錄頁面。使用前面創建的kie-web/kie-web123登錄

登錄成功后進入系統首頁:

WorkBench使用?

創建空間、項目

首頁中點擊 project,創建空間

?

我們創建一個 ityml 的工作空間。點擊 Save,保存。

?點擊工作空間當中的 ityml,進入空間

點擊Add Project添加項目

成功后,我們可以看見下圖

?左上角的導航條,可以在空間和project之間切換

創建數據對象和drl文件

切換到pro1項目內,點擊 Create New Assert

選中數據對象:

?輸入Order,點擊確定,成功后跳轉如下頁面

?

Order相當于我們代碼中的實體類,在左側 Project Explorer視圖中,可以看見項目結構

接下來添加字段,點擊添加字段按鈕:

?ID 位置,輸入java bean的字段,標簽是備注信息,類型選擇對應的字段類型,保存,點擊創建,關閉彈窗,點擊創建并繼續,可以繼續創建。

點擊右上角的保存,至此,一個數據對象我們就創建完成,可以在源代碼中查看代碼內容。

接下來我們創建一個drl文件,創建過程跟創建bean類似,drl文件內容如下

package com.ityml.pro1;rule "rule_1"when$order:Order(age > 10)thenSystem.out.print("rule run..."); end

保存之后,點擊導航條回到項目主頁

設置KieBase+KieSession

項目首頁點擊Settings

選擇知識庫跟會話

?

彈出窗口,輸入Kiebase名稱即可,我們以kb1為例

?同理,我們補充完軟件包信息,添加只是會話,即kiesession

?操作完成后,不要忘記保存,此時,我們可在Project Explorer視圖中,resource/META-INF/kmodule.xml中看見如下信息

<kmodule xmlns="http://www.drools.org/xsd/kmodule" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><kbase name="kb1" default="false" eventProcessingMode="stream" equalsBehavior="identity" packages="com.ityml.pro1"><ksession name="ks1" type="stateful" default="true" clockType="realtime"/></kbase> </kmodule>

導航回到項目首頁,進行編譯發布

發布成功后,我們可以在maven倉庫中看到對應的jar

?

也可以訪問:http://localhost:8080/kie-web/maven2/com/ityml/pro1/1.0.0/pro1-1.0.0.jar?驗證是否發布成功.

代碼使用?

@Testpublic void test() throws Exception{//通過此URL可以訪問到maven倉庫中的jar包//URL地址構成:http://ip地址:Tomcat端口號/WorkBench工程名/maven2/坐標/版本號/xxx.jarString url = "http://localhost:8080/kie-web/maven2/com/ityml/pro1/1.0.0/pro1-1.0.0.jar";KieServices kieServices = KieServices.Factory.get();UrlResource resource = (UrlResource) kieServices.getResources().newUrlResource(url);//認證resource.setUsername("kie-web");resource.setPassword("kie-web123");resource.setBasicAuthentication("enabled");KieRepository repository = kieServices.getRepository();//通過輸入流讀取maven倉庫中的jar包數據,包裝成KieModule模塊添加到倉庫中KieModule kieModule = repository.addKieModule(kieServices.getResources().newInputStreamResource(resource.getInputStream()));KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());KieSession session = kieContainer.newKieSession();Order order = new Order();order.setName("張三");order.setAge(30);session.insert(order);session.fireAllRules();session.dispose();}

本文參考資料:

Drools規則引擎?

總結

以上是生活随笔為你收集整理的Drools 规则引擎一文读懂的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

久草在线免费播放 | 丁香综合激情 | 奇米四色影狠狠爱7777 | 色综合久久久久综合 | 成人黄色小说网 | 91麻豆精品国产91久久久使用方法 | 国产成人一区二区三区在线观看 | 狠狠色综合网站久久久久久久 | 日韩免费一区二区三区 | 三级在线国产 | 国产精品黄色影片导航在线观看 | 激情文学综合丁香 | 国产高清免费 | 免费视频三区 | 日韩精品一区二区三区中文字幕 | 一区二区av | 国产精品国产精品 | 久草免费在线观看视频 | 中文字幕 成人 | 精品免费| 在线国产日韩 | 国产精品一区二区三区四区在线观看 | 亚洲天堂网在线播放 | 午夜视频一区二区三区 | 韩日精品在线观看 | 国产一级淫片在线观看 | 久久婷婷五月综合色丁香 | 国产精品久久久久免费观看 | 日韩av中文在线观看 | 国产99免费 | 日韩精选在线 | 亚洲精品视频免费在线观看 | 99精品亚洲 | 日日夜夜人人天天 | 中文字幕日韩无 | 国产小视频国产精品 | 国产九九九九九 | 亚洲精品在线一区二区三区 | 亚洲精品视频 | 色精品视频 | 狠狠狠狠狠狠 | 在线免费视频你懂的 | 婷婷色狠狠| 99久久精品日本一区二区免费 | 右手影院亚洲欧美 | 97免费公开视频 | 国产成人精品国内自产拍免费看 | 成人在线电影观看 | 国产日韩精品在线 | 天堂av在线网 | 九九热久久免费视频 | 久久久久这里只有精品 | 天天干国产 | 麻豆91精品视频 | 免费看十八岁美女 | 日韩三级中文字幕 | 超碰国产人人 | 国产福利av | 日韩伦理片一区二区三区 | 天天天干 | 美女网站黄在线观看 | 国产亚洲在 | 人人干天天干 | 三级av免费看 | 一区电影| 久草av在线播放 | 视频在线99re | 午夜资源站 | 国产午夜精品理论片在线 | 欧美日韩午夜爽爽 | 久草视频在线资源站 | 日本黄色大片免费 | 国内精品亚洲 | 免费日韩一级片 | 精品一区二三区 | 国产精品丝袜久久久久久久不卡 | 国产一线二线三线性视频 | www.久久视频 | 91麻豆网站 | 天天综合网 天天综合色 | 国产成人性色生活片 | 99精品在线播放 | 成年人免费在线观看网站 | 日韩精品久久中文字幕 | 在线日韩 | 久久久久免费 | 人人玩人人爽 | 麻豆久久一区二区 | 国产五十路毛片 | 国产精品av一区二区 | 国产 一区二区三区 在线 | 婷婷在线视频观看 | 激情狠狠干| www免费看| 国产中文字幕久久 | 91av视频观看 | 这里只有精品视频在线 | 欧美午夜剧场 | 一区二区欧美日韩 | 日韩欧美国产视频 | 操操操干干干 | 国产成人精品久久久久蜜臀 | 国产一二区在线观看 | 在线视频精品播放 | 午夜黄色| 欧美日韩一区二区视频在线观看 | 免费网址在线播放 | 国产丝袜在线 | 欧美日韩国产欧美 | 88av网站| 四虎在线观看 | 欧美国产高清 | 婷婷激情综合网 | 欧洲在线免费视频 | 色婷婷www | 操一草| 91在线你懂的 | 久久欧美精品 | 成人午夜电影在线观看 | 97**国产露脸精品国产 | 天天射天天干天天爽 | 在线观看日韩 | 韩国精品在线观看 | 精品电影一区二区 | 西西www4444大胆在线 | 国产美女视频免费观看的网站 | 五月综合网站 | 亚洲一级黄色大片 | 亚洲精品久久激情国产片 | 久久理论电影 | 午夜免费久久看 | 丁香六月婷婷激情 | 国产精品九九久久99视频 | 丁香资源影视免费观看 | 精品国产综合区久久久久久 | 91激情| 激情久久久久 | 亚洲精品午夜久久久久久久久久久 | 久久综合久久综合这里只有精品 | 精品国产欧美一区二区 | 88av视频| 国产精品欧美久久久久无广告 | 久热爱| 狠狠躁夜夜躁人人爽超碰97香蕉 | 久久精品欧美一区二区三区麻豆 | 激情偷乱人伦小说视频在线观看 | 免费观看9x视频网站在线观看 | 久久免费福利 | 美女黄濒 | 欧美最新大片在线看 | 久久久综合精品 | 国产亚洲一区二区在线观看 | 欧美一区二区三区在线观看 | 成人午夜电影在线播放 | 看片网站黄| 欧美精品久久久久久 | 成人宗合网 | 欧美亚洲xxx| 久久免费看av | 操操日日 | 久久 精品一区 | 久久综合九色99 | 夜夜夜 | 日韩免费在线观看视频 | 2022久久国产露脸精品国产 | 精品欧美乱码久久久久久 | 999电影免费在线观看2020 | 国内精品在线看 | 亚洲精品99久久久久中文字幕 | 网址你懂的在线观看 | 久久亚洲免费 | 毛片激情永久免费 | 狠狠狠色丁香综合久久天下网 | 色视频网站免费观看 | 欧美日韩综合在线观看 | www.色婷婷.com| 成人午夜电影久久影院 | 色婷婷综合视频在线观看 | 日韩在线视频网 | 精品电影一区二区 | 国产资源在线播放 | 日日干天天射 | 国产精品不卡在线 | 成人在线观看av | 久久国产视频网 | 天天干天天天天 | 久草视频在线资源站 | 日本深夜福利视频 | 精品视频网站 | 日韩亚洲在线观看 | 日日摸日日添夜夜爽97 | 亚洲一级黄色 | 美女视频黄是免费的 | 国产在线一线 | 日躁夜躁狠狠躁2001 | 97超碰在线免费观看 | 欧美日本三级 | 五月婷av| 成年人视频免费在线 | 国产亚洲激情视频在线 | 一级性生活片 | 日韩欧美视频在线播放 | 99久久影院| 国产综合香蕉五月婷在线 | 色综合久久久 | 天天色影院| 天天操夜操视频 | 久草免费色站 | 亚洲精品国产成人 | 毛片网站在线看 | 成人免费中文字幕 | 日韩av片无码一区二区不卡电影 | 麻豆视频成人 | 欧美日韩精品在线一区二区 | 精品自拍网 | 综合色在线 | 五月婷婷色丁香 | 久久综合欧美精品亚洲一区 | bbbbb女女女女女bbbbb国产 | 91 中文字幕| 在线观看免费国产小视频 | 久久这里有精品 | 黄色不卡av | 免费合欢视频成人app | ,午夜性刺激免费看视频 | 一级欧美日韩 | 国产91对白在线播 | 99热精品在线 | 亚洲精品国产第一综合99久久 | 亚洲午夜久久久综合37日本 | 中文字幕在线看 | 精品在线免费视频 | 日韩一区二区三区在线看 | 黄在线免费观看 | 久久激五月天综合精品 | 公与妇乱理三级xxx 在线观看视频在线观看 | 波多野结衣在线观看一区二区三区 | 国产专区第一页 | 亚洲精品小视频 | 黄色大片日本免费大片 | 欧美激情视频一区二区三区免费 | 亚洲国产精品一区二区尤物区 | 国产视频亚洲视频 | 99精品热视频只有精品10 | 久草视频在线免费播放 | av电影亚洲 | 日本高清久久久 | 韩国av电影在线观看 | 在线探花| 99久久er热在这里只有精品66 | 色婷丁香 | 久久精品国产99国产 | 最新国产在线 | 婷婷色在线资源 | 国产精品不卡在线播放 | 色综合久久中文综合久久牛 | 精品久久精品 | 久久人人爽人人片 | 久久精品人人做人人综合老师 | 日本一区二区三区免费观看 | 在线免费观看av网站 | 久久综合婷婷国产二区高清 | 欧美不卡在线 | 日韩天堂网 | 青青草国产在线 | av解说在线观看 | 激情综合网五月 | 天堂入口网站 | 久久精品久久久久久久 | 久久国产精品99国产精 | 粉嫩av一区二区三区四区在线观看 | 丁香花在线观看视频在线 | 日韩一级网站 | 国产97在线播放 | 久久精品亚洲 | 黄视频网站大全 | 毛片网在线播放 | 国产女人免费看a级丨片 | 在线免费av网| 六月丁香婷婷在线 | 激情综合五月 | 亚洲乱码久久 | 五月婷婷综合在线观看 | 91九色porn在线资源 | 久久久久免费精品视频 | 国产免费成人av | 精品国产一区二区三区久久 | 国产在线观看黄 | 亚洲精品免费观看视频 | 日韩在线视频网址 | 国产精品久久久久免费观看 | 久久综合欧美精品亚洲一区 | 天堂av中文字幕 | 在线观看av免费观看 | 一区二区三区在线观看 | 91久久久久久久 | 99在线观看免费视频精品观看 | 久久精品123 | 中文字幕精品视频 | 国产美女精品视频免费观看 | 深爱激情五月网 | 五月婷婷激情网 | 亚洲国产免费看 | 久久精品99国产精品 | 精品国产电影 | 在线观看爱爱视频 | 97在线精品视频 | 国产精品久久久久aaaa | av大全在线播放 | 五月婷婷丁香六月 | 亚洲综合在线五月 | 天天摸天天操天天爽 | 国内精品视频免费 | 99中文字幕视频 | 国产精品一区二区三区在线免费观看 | 中文字幕一区二区三区视频 | 成人久久免费视频 | 国产 在线 日韩 | 天天操月月操 | 又湿又紧又大又爽a视频国产 | 亚洲激情在线观看 | 久久手机免费视频 | 99久久精品久久久久久动态片 | 顶级欧美色妇4khd | 久久在线一区 | 国产人免费人成免费视频 | a天堂免费| 国产精品久久久久久久久久了 | 久久精品这里热有精品 | 在线观看国产www | 国产精品久久一 | av观看网站 | 91丨九色丨国产在线 | 亚洲精品免费在线观看视频 | 久久久久久久久久免费 | av片中文字幕 | 色综合a| 亚洲精品免费观看视频 | 国产在线国偷精品产拍 | 亚洲精品xxxx | 天堂av在线 | 美女av电影 | 精品国产精品国产偷麻豆 | 日韩一区二区三区免费电影 | 免费观看国产精品视频 | 国产午夜精品一区二区三区在线观看 | 成人动态视频 | 国产视频一区在线播放 | 欧美日韩国产在线 | 亚洲日本激情 | 中文字幕一区二区三区在线视频 | 伊人永久 | 亚洲欧洲精品一区 | 一级淫片在线观看 | 天天色天天射天天干 | 欧美日韩精品在线播放 | 日本高清久久久 | 婷婷在线免费视频 | 日本天天操 | 亚洲一区欧美激情 | 国产精品2020 | 色亚洲网| 欧美一区日韩一区 | 蜜臀av免费一区二区三区 | 成人av一区二区兰花在线播放 | 丁香电影小说免费视频观看 | 国产精品 欧美 日韩 | 国内精品在线观看视频 | 国产二区免费视频 | 黄色www在线观看 | 视频1区2区| 国产 日韩 欧美 自拍 | 天天艹日日干 | av片中文字幕| 欧美污在线观看 | 久久视频免费在线观看 | 黄色影院在线免费观看 | 日本久久电影 | 国产精品麻豆91 | 欧美巨大| 免费看成人片 | 久久视频免费看 | 伊人影院在线观看 | 天天干天天想 | 亚洲国产wwwccc36天堂 | 美女网站在线看 | 免费在线播放黄色 | 日韩欧美精品在线视频 | 男女免费视频观看 | 综合网久久 | 欧美一区,二区 | 黄色成人av| 国产一级片直播 | 91激情视频在线 | 国内精自线一二区永久 | 久久论理 | 久日视频 | 狠狠干成人 | 五月激情婷婷丁香 | 中文网丁香综合网 | 一区二区三区高清在线观看 | 人人爽人人插 | 99精品在线观看视频 | 国产午夜精品一区二区三区欧美 | 2023av| 久久国产精品99久久久久久老狼 | 一区二区三区中文字幕在线观看 | www.夜色.com| 国产一级电影 | 国产在线观看一区 | 亚洲精品乱码久久久久久9色 | 黄色国产高清 | 欧美a级一区二区 | 亚洲女欲精品久久久久久久18 | 免费看片在线观看 | 伊人久久国产精品 | 日韩一二三区不卡 | 亚洲九九九在线观看 | 国产区av在线| 国产日产高清dvd碟片 | 国产一区二区在线视频观看 | 成人av电影免费在线观看 | 亚洲aⅴ在线 | 99久久精品一区二区成人 | 亚洲精品视频在线观看免费视频 | 国产精品毛片 | 欧美午夜剧场 | 中文字幕精品视频 | 国产资源免费 | 99视频免费在线观看 | 免费看污的网站 | 久久精品综合一区 | a久久免费视频 | www国产精品com | 成人毛片一区二区三区 | 亚洲成人在线免费 | 99精品国产一区二区三区麻豆 | 91桃色在线播放 | 五月天婷亚洲天综合网精品偷 | 97国产情侣爱久久免费观看 | 天天综合网天天综合色 | 五月天色丁香 | 日本在线观看一区二区三区 | www.国产精品 | 国产一二区在线观看 | 日韩中文字幕免费视频 | 国产区欧美 | 九七在线视频 | 久久精品亚洲精品国产欧美 | 5月丁香婷婷综合 | 国产99久久精品一区二区300 | 天天激情天天干 | 天天舔夜夜操 | 在线视频麻豆 | 欧美一级性 | 国产精品久久久久久久久久免费看 | 久久久精品国产一区二区 | 国产在线免费观看 | 久久久久国产免费免费 | 婷婷色六月天 | 草樱av| 亚洲不卡在线 | 色综合久久久久综合 | 中文字幕在线视频国产 | 亚洲天堂网在线视频观看 | 久久天天拍 | 亚洲欧洲一级 | 啪啪动态视频 | 国产精品成人一区二区三区吃奶 | 亚洲精品乱码久久久久 | 精品久久久久久久久久久久 | 成人av地址 | 黄色免费视频在线观看 | 456成人精品影院 | 国产精品18久久久久久不卡孕妇 | 久久国产精品一国产精品 | 亚洲春色奇米影视 | 色偷偷97 | 天天干天天操天天射 | 日韩午夜精品福利 | 午夜国产福利在线 | 黄色精品一区二区 | 天天碰天天操 | 91麻豆精品国产自产在线游戏 | 伊人在线视频 | 99免费精品| 人人干在线观看 | 欧美日韩1区| 在线播放 亚洲 | 色婷婷狠狠五月综合天色拍 | 精品国产美女 | 国产日韩欧美精品在线观看 | 日本中文不卡 | 欧美性脚交 | 午夜 在线| 久久精品国产成人精品 | 日本精品久久 | 天天想夜夜操 | 黄色毛片电影 | 美女精品久久久 | 欧美日韩免费一区二区三区 | 99热在线看| av一级久久 | 丁香在线观看完整电影视频 | 996久久国产精品线观看 | 毛片网站免费在线观看 | 久久精品小视频 | 97超碰在线免费 | 97超碰人人澡 | 亚洲a成人v | 狠狠干婷婷色 | 久久综合综合久久综合 | 国产精品女主播一区二区三区 | 亚洲高清在线观看视频 | 国产精品入口久久 | 欧美色图亚洲图片 | 99久久er热在这里只有精品15 | 久久不射电影院 | 久久精品站 | 国产精品国产三级在线专区 | 超碰97国产精品人人cao | 国产中文字幕网 | 99热在线网站 | 久久97超碰 | 国产精品2区 | 久久在草 | 日韩精品久久久久久久电影99爱 | 黄色成人免费电影 | 日韩电影一区二区三区在线观看 | 99爱爱| 992tv在线 | 日韩黄在线观看 | 2021久久 | 中日韩在线视频 | 亚洲激情六月 | 日日操日日干 | 欧美一二三专区 | 操操操人人人 | 久久天天躁狠狠躁亚洲综合公司 | 国产精品久久久久久超碰 | 国产在线观看中文字幕 | 波多野结衣在线视频免费观看 | 国产精品美女久久久 | 成人黄色免费在线观看 | 亚洲一级性 | 亚洲天天在线日亚洲洲精 | 国产高清久久久久 | 91精品国产福利在线观看 | 深夜男人影院 | 国产精品中文字幕在线播放 | 96看片 | 久热av在线| 99久久久久久久久 | www免费视频com | 日本中文一区二区 | 日韩三级免费 | 国产乱对白刺激视频在线观看女王 | 欧美精品一区二区蜜臀亚洲 | 天天伊人狠狠 | 97热久久免费频精品99 | 国产精品久久99精品毛片三a | 超碰免费公开 | 精品一二三四视频 | 久草免费新视频 | 国产精品免费久久 | 91chinesexxx | 亚洲码国产日韩欧美高潮在线播放 | av无限看| 狠狠天天 | 成人免费网站视频 | 亚洲欧美视频在线播放 | 婷婷久久网 | 久久看片网站 | 午夜电影av | 亚洲午夜剧场 | 国产中文字幕免费 | 91在线看免费 | 国产第一二区 | 最新免费av在线 | 超碰激情在线 | 久久精品国产免费 | 99热国产在线观看 | 爱爱av网 | 日韩网站免费观看 | 亚洲精品欧美成人 | 久9在线 | .国产精品成人自产拍在线观看6 | 国产精品成人自拍 | 久久国产精品色av免费看 | 国产丝袜一区二区三区 | 久草在线网址 | 91亚洲精品在线 | 婷婷伊人综合 | 日韩欧美精品在线 | 日韩av手机在线看 | 96香蕉视频| 四虎国产精品免费观看视频优播 | 999久久久欧美日韩黑人 | 国产裸体bbb视频 | 亚洲精品小视频 | 999亚洲国产996395 | 9在线观看免费高清完整版 玖玖爱免费视频 | 成人免费在线观看入口 | 成年人免费看的视频 | 久久嗨 | 久久综合影音 | 在线电影av | 久久99亚洲精品久久久久 | 在线之家官网 | 国产视频999 | 国产无套精品久久久久久 | 五月天色丁香 | 人人人爽 | 日韩视频免费观看高清 | 国产69精品久久久久久 | 国产玖玖在线 | 久久久久久久久久久久久影院 | 天天草天天干天天射 | 色综合www| 一区中文字幕电影 | 久色伊人 | 色婷婷播放 | 福利久久久 | 久久久久国产精品视频 | 91免费观看视频网站 | 日韩三级成人 | 亚洲综合在| 91天堂素人约啪 | 韩国av免费在线 | 天天爽天天爽天天爽 | 亚洲国产成人精品在线观看 | 91在线免费观看网站 | 日本h在线播放 | 国产人成一区二区三区影院 | 亚洲不卡123 | 麻豆视传媒官网免费观看 | 成人av一区二区在线观看 | 成人av av在线 | 国产精品久久久久久久妇 | 五月婷婷影院 | 狠狠狠色丁香婷婷综合激情 | 国产一区在线视频 | 精品福利在线视频 | 国产伦精品一区二区三区… | 欧美日韩不卡一区二区三区 | 五月婷婷.com | 日韩激情三级 | 在线观看免费av片 | 亚洲视频精品 | 99视频免费看 | 国产在线观看免费观看 | 丝袜美腿在线视频 | 日批网站免费观看 | 丁香婷婷综合激情五月色 | 91精品秘密在线观看 | 久草在线视频中文 | av在线播放快速免费阴 | av电影免费在线播放 | 91麻豆精品国产自产 | 美女激情影院 | 91在线九色 | 欧美日韩精品网站 | 精品国产伦一区二区三区观看方式 | 亚洲欧美观看 | 美女av免费看 | 黄色在线免费观看网址 | 亚洲视频在线看 | 亚洲综合爱 | 日韩一区视频在线 | 欧美日韩另类在线 | 毛片一级免费一级 | 国产激情电影综合在线看 | 国产精品网红直播 | 精品一区二区视频 | 午夜婷婷在线播放 | 久久国产视频网站 | 精品久久久久久一区二区里番 | 亚洲人精品午夜 | 精品主播网红福利资源观看 | 丁香五月亚洲综合在线 | 菠萝菠萝蜜在线播放 | 色资源网免费观看视频 | 亚洲人在线视频 | 国产xxxxx在线观看 | 久久免费中文视频 | 手机av电影在线观看 | 精品一区二区6 | 国产91精品在线播放 | 麻豆成人在线观看 | 天天色图 | 香蕉日日 | 成人免费中文字幕 | 国产精品久久久久影院 | 成年人在线免费看视频 | 亚洲激情校园春色 | 国产一级在线观看 | 日韩电影中文字幕 | 久草免费在线 | 日韩成人邪恶影片 | 婷婷视频导航 | 狠狠躁天天躁综合网 | 一区二区三区免费网站 | 色资源网免费观看视频 | 免费av网站在线看 | 天天干天天天天 | 成人av手机在线 | 日韩欧美电影网 | 97国产小视频 | 91热| 这里只有精品视频在线观看 | 伊人午夜 | 日韩av一区二区三区在线观看 | 激情av五月婷婷 | 婷婷久久一区二区三区 | 高清精品久久 | 日韩中文字幕在线看 | 不卡视频一区二区三区 | 免费在线中文字幕 | 日韩精品在线视频 | 日韩一区正在播放 | 中文字幕日韩av | 一区二区中文字幕在线播放 | 夜夜操天天 | 狠狠色丁香婷婷综合最新地址 | 国产成人av | 成年免费在线视频 | japanesefreesexvideo高潮 | 91探花系列在线播放 | 四虎在线视频免费观看 | 国产露脸91国语对白 | 91亚洲精品乱码久久久久久蜜桃 | 日韩色一区二区三区 | 日韩影视在线观看 | 欧美色久| 天天干,天天射,天天操,天天摸 | 97视频一区 | 欧美日一级片 | 亚洲激情精品 | 欧美极度另类性三渗透 | 精品91视频| 久久国产乱 | 中文字幕第一页在线 | 久日视频| 欧美乱淫视频 | 婷婷综合亚洲 | 69精品| 午夜久久网站 | 国产精品av电影 | 日韩国产精品久久久久久亚洲 | 高清国产午夜精品久久久久久 | 国产亚洲精品福利 | 玖玖国产精品视频 | 免费亚洲婷婷 | 尤物九九久久国产精品的分类 | 国产黄色资源 | 日韩电影在线观看一区二区 | 精品在线视频一区 | 国产福利精品在线观看 | 香蕉视频网站在线观看 | 夜夜夜夜操 | 成人av在线观| 免费在线观看av | 久久久久国产精品免费免费搜索 | 在线国产一区二区 | 欧美国产精品一区二区 | 国产精品美女999 | 在线观看网站你懂的 | 国产成人一级电影 | 欧美在线视频二区 | 久久免费的精品国产v∧ | 中文字幕激情 | 精品久久久久久久久久久院品网 | 国产中年夫妇高潮精品视频 | av在线电影网站 | 国产精品完整版 | 99久久精品国产一区二区成人 | 中文在线a在线 | 99久久影院 | 亚洲伊人天堂 | 亚洲精品久久激情国产片 | 91亚洲狠狠婷婷综合久久久 | 97人人模人人爽人人少妇 | 在线欧美小视频 | 国产69精品久久久久久久久久 | 午夜影视一区 | 丁香花在线观看免费完整版视频 | 久久久久免费网站 | 99综合电影在线视频 | 精品 激情| 精品99在线 | 欧美9999 | 亚洲人人网 | 成年人免费观看在线视频 | 久久久久久久国产精品 | 在线看片日韩 | 中文字幕一区二区三区四区在线视频 | 亚洲夜夜综合 | 欧美大荫蒂xxx | 久久男人影院 | 奇米网777| 综合中文字幕 | 国产精品高潮呻吟久久av无 | 久久夜夜爽 | 国产日韩三级 | 色九九视频 | 丁香影院在线 | 国产精品a成v人在线播放 | 成+人+色综合 | а中文在线天堂 | 久久久久成 | 美女网色 | 久久免费视频国产 | 麻豆手机在线 | 九热精品 | 91福利在线导航 | 久久免费视频在线观看 | 国产打女人屁股调教97 | 久久精品视频在线观看免费 | 69久久久 | 狠狠狠色丁香婷婷综合激情 | 91av视频网 | 久久超级碰 | 国产中文字幕在线观看 | 91热在线 | 9i看片成人免费看片 | 天天躁天天躁天天躁婷 | a爱爱视频 | 欧美性色黄 | 国产一区二区免费在线观看 | 婷婷伊人综合 | 久久精品美女视频网站 | 成人av电影在线观看 | 热久久国产 | 中文字幕欲求不满 | 成人免费网站在线观看 | 热久久精品在线 | 日韩一二三 | 激情综合网婷婷 | 免费在线观看不卡av | 99视频网址| 亚洲美女视频在线 | 欧美日韩不卡在线视频 | 中文字幕在线观看1 | 99国产精品一区二区 | 亚洲精品视频网站在线观看 | 99热最新在线 | 精品国产中文字幕 | 97电影院在线观看 | 精品一区免费 | 毛片精品免费在线观看 | 午夜国产在线观看 | 国产精品一区二区免费视频 | 日韩精品视频一二三 | 欧美成a人片在线观看久 | 久草精品在线观看 | 亚洲闷骚少妇在线观看网站 | 白丝av在线| 深爱激情亚洲 | 天天狠狠 | 久久精品视频4 | 黄色av一区二区三区 | 免费国产ww| 波多野结衣在线播放一区 | 国产精品久久久久久av | 国产精品第一视频 | 久久精品一区二区三区国产主播 | 亚洲区精品 | 五月婷婷久久丁香 | 三级在线视频观看 | av高清不卡| 中文字幕刺激在线 | 成在线播放 | 亚洲精品在线观 | 日韩av午夜| 免费一级特黄录像 | 日本中文字幕久久 | 人人超碰97| 久久福利电影 | 99视频这里只有 | 手机看片久久 | 国产手机av在线 | 中文国产在线观看 | 国产精品久久久电影 | 五月综合激情网 | 激情影院在线观看 | 国产男女爽爽爽免费视频 | 中文字幕国产视频 | 69av在线播放 | 日本中文一级片 | 国产高清在线免费 | 99精品区| 波多野结衣在线观看一区二区三区 | 日本最新一区二区三区 | 黄色视屏在线免费观看 | 国内精品久久久久影院男同志 | 97精品国产97久久久久久 | 国产福利av在线 | 91.精品高清在线观看 | 狠狠色丁香婷婷综合橹88 | 美女视频黄免费的久久 | 麻豆影视在线观看 | 国产午夜精品免费一区二区三区视频 | 91在线视频在线观看 | 狠狠色综合欧美激情 | 国产网站色 | 国产最新91 | 色狠狠一区二区 | 日韩欧美在线综合网 | 天天色天天上天天操 | 一区二区欧美日韩 | 精品久久久久久久 | 国产亚洲观看 | 一区二区免费不卡在线 | 成年人精品 | 国产成人一区二区精品非洲 | 久久亚洲婷婷 | 中文字幕欧美三区 | 黄色成品视频 | 亚洲欧洲精品一区二区精品久久久 | 日韩激情免费视频 | 日韩成人中文字幕 | 黄色一级在线视频 | 久久夜色精品亚洲噜噜国4 午夜视频在线观看欧美 | 五月婷亚洲 | 91成人亚洲| 国产日韩精品在线 | 亚洲天天综合网 | 天天操网址 | 亚洲男女精品 | www.干| 狠狠躁天天躁 | 日韩免费不卡av | 国产精品 视频 | av一区二区三区在线播放 | 精品国产乱码久久久久久天美 | 美女久久网站 | 在线观看亚洲免费视频 | 久久视频国产精品免费视频在线 | 国产精品毛片一区二区三区 | 久久精品国产亚洲精品 | 国产精品久久久久久久久岛 | 中文字幕在线播放av | 久久福利影视 | 久久精品免视看 | 色中文字幕在线观看 | 久久精品国产成人精品 | 激情丁香 | 日韩欧美国产激情在线播放 | 精品1区2区3区 | 超碰日韩在线 | 视频在线观看91 | 在线国产99| 日韩av影视在线观看 | 国产精品专区h在线观看 | 欧美日韩国产亚洲乱码字幕 | 久久视频在线观看免费 | 日本高清久久久 | 又湿又紧又大又爽a视频国产 | www.五月婷婷.com | 中文字幕 国产视频 | 2019中文 | 色综合天天在线 | 欧洲亚洲激情 | www日日 | 国产又黄又爽又猛视频日本 | 国产一级做a爱片久久毛片a | 99久久精品无码一区二区毛片 | 久久官网| 久久不射电影网 | 精品久久久久免费极品大片 | 亚州精品天堂中文字幕 | 国产在线观看免费 | 最近高清中文字幕 | 天天操天天干天天爱 | 亚洲精品高清一区二区三区四区 | 日韩综合一区二区三区 | 国产精品综合av一区二区国产馆 | 国产在线精品视频 | 久久久精品网站 | 一区二区三区四区五区在线 | 色网免费观看 | 日韩精品首页 | 一区二区精品在线视频 | 国模视频一区二区三区 | 久久久久久久久久久久久影院 | 国产精品成人自产拍在线观看 | 久久伊人精品一区二区三区 | 欧美日韩二区在线 | 亚洲国产成人精品电影在线观看 | 国产精品视频免费观看 | 成人a大片 | 免费99视频 | 狠狠干网址 | 成人午夜精品久久久久久久3d | 久久综合九色综合97婷婷女人 | 日韩黄色免费看 | 国产色中涩 | 久久免费成人精品视频 |