Spring Boot + URule 規則引擎,可視化配置太爽了!

来源:https://www.cnblogs.com/javastack/archive/2023/05/26/17435230.html
-Advertisement-
Play Games

作者:知了一笑\ 來源:juejin.cn/post/7210194936276680759 ## 一、背景 前段時間,在做項目重構的時候,遇到很多地方需要做很多的條件判斷。當然可以用很多的if-else判斷去解決,但是當時也不清楚怎麼回事,就想玩點別的。於是乎,就去調研了規則引擎。 當然,市面上有 ...


作者:知了一笑
來源:juejin.cn/post/7210194936276680759

一、背景

前段時間,在做項目重構的時候,遇到很多地方需要做很多的條件判斷。當然可以用很多的if-else判斷去解決,但是當時也不清楚怎麼回事,就想玩點別的。於是乎,就去調研了規則引擎。

當然,市面上有很多成熟的規則引擎,功能很多,性能很好。但是,就是想玩點不一樣的(大家做技術選型別這樣,這個是反面教材)。最終一款URule的規則引擎吸引了我,主要還是採用瀏覽器可直接配置,不需要過多安裝,可視化規則也做的不錯。經過一系列調研,後面就把它接入了項目中,順便記錄下調研的結果。

二、介紹

規則引擎其實是一種組件,它可以嵌入到程式當中。將程式複雜的判斷規則從業務代碼中剝離出來,使得程式只需要關心自己的業務,而不需要去進行複雜的邏輯判斷;簡單的理解是規則接受一組輸入的數據,通過預定好的規則配置,再輸出一組結果。

當然,市面上有很多成熟的規則引擎,如:Drools、Aviator、EasyRules等等。但是URule,它可以運行在Windows、Linux、Unix等各種類型的操作系統之上,採用純瀏覽器的編輯模式,不需要安裝工具,直接在瀏覽器上編輯規則和測試規則。

當然這款規則引擎有開源和pro版本的區別,至於pro版是啥,懂的都懂,下麵放個表格,瞭解下具體的區別

特性 PRO版 開源版
嚮導式決策集
腳本式決策集
決策樹
決策流
決策表
交叉決策表
複雜評分卡
文件名、項目名重構
參數名、變數常量名重構
Excel決策表導入
規則集模版保存與載入
中文項目名和文件名支持
伺服器推送知識包到客戶端功能的支持
知識包優化與壓縮的支持
客戶端伺服器模式下大知識包的推拉支持
規則集中執行組的支持
規則流中所有節點嚮導式條件與動作配置的支持
迴圈規則多迴圈單元支持
迴圈規則中無條件執行的支持
導入項目自動重命名功能
規則樹構建優化
對象查找索引支持
規則樹中短路計算的支持
規則條件冗餘計算緩存支持
基於方案的批量場景測試功能
知識包調用監控
更為完善的文件讀寫許可權控制
知識包版本控制
SpringBean及Java類的熱部署
技術支持

三、安裝使用

實際使用時,有四種使用URule Pro的方式,分別是嵌入式模式、本地模式、分散式計算模式以及獨立服務模式。

但是我們這裡不考慮URule Pro,咱自己整個開源版,在開源版集成springboot的基礎上做一個二次開發,搜了一圈,其實就有解決方案。

大致的項目模塊如下:

Spring Boot 基礎就不介紹了,推薦看這個實戰項目:

https://github.com/javastacks/spring-boot-best-practice

自己創建個空資料庫,只需要在edas-rule-server服務中修改下資料庫的配置,然後啟動服務即可。第一次啟動完成,資料庫中會創建表。

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/urule-data?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=mysql

上面說過,它是純用瀏覽器進行編輯,配置規則的,只需要打開瀏覽器,輸入地址:http://localhost:8090/urule/frame,看到這個界面,就說明啟動成功了。

四、基礎概念

3.1整體介紹

先說下URule它的構成部分,主要是兩部分:1、設計器部分 2、規則執行引擎。設計器部分主要是庫文件和規則文件構成。下麵看下整體的結構圖

3.2庫文件

如上圖介紹的,庫文件有4種,包括變數庫,參數庫,常量庫和動作庫。其實類似於Java開發的系統中的實體對象,枚舉,常量以及方法。

上面說過,規則都是可視化配置的。在配置規則的過程中,就需要引入各種已經定義好的庫文件,再結合業務需求,從而配置出符合業務場景的業務規則,所以哪裡都有庫文件的身影。

3.2.1變數庫文件

在業務開發中,我們會創建很多Getter和Setter的Java類,比如PO、VO、BO、DTO、POJO等等,其實這些類new對象後主要起到的作用就是數據的載體,用來傳輸數據。

在URule中,變數庫就是用來映射這些對象,然後可以在規則中使用,最終完成業務和規則的互動。最後上一張圖,用來創建變數庫

對了,上面廢話了這麼多可視化配置,這才是第一次展示配置界面,慚愧慚愧。

上圖一目瞭然,在“庫”這個菜單底下右鍵,然後點擊添加變數庫即可,最後定義自己喜歡的變數庫名,當然名字只支持中文或者英文,其他字元不可用。

創建完變數庫後,就可以對變數庫進行編輯,可以認為就是給POJO添加屬性

也不彎彎繞繞講什麼術語,就個人理解。圖左邊是創建類,其中名稱是它的別名,配置規則用它代替這個類。圖右邊是類的屬性,我這裡隨便寫了幾個,估計看了懂得都懂。

最後在業務系統中創建對應的類,註意全限定名和配置變數庫的類路徑一致。

package com.cicada;

import com.bstek.urule.model.Label;
import lombok.Data;

/**
 * @author 往事如風
 * @version 1.0
 * @date 2023/3/3 15:38
 * @description
 */
@Data
public class Stu {

    @Label("姓名")
    private String name;

    @Label("年齡")
    private int age;

    @Label("班級")
    private String classes;
}

最後說下這個@Label註解,這個是由URule提供的註解,主要是描述欄位的屬性,跟變數庫的標題一欄一致就行。聽官方介紹可以通過這個註解,實現POJO屬性和變數庫屬性映射。就是POJO寫好,然後對應規則的變數庫就不需要重新寫,可以直接生成。反正就有這個功能,這裡就直接一筆帶過了。

3.2.2常量庫文件

說到常量庫,這個就可以認為是我們Java系統中的常量,枚舉。比如性別,要定義枚舉吧;比如對接的機構,也可以定義一個枚舉吧。

當然,類似於變數庫,常量庫也可以實現和系統中的枚舉相互映射,這樣做的好處可以避免我們手動輸入,防止輸入錯誤。創建常量庫也比較簡單,直接在“庫”這個菜單下右鍵,“添加常量庫”。

創建好常量庫文件後,也會出現如下頁面:

3.2.3參數庫文件

參數庫,就是URule規則中的臨時變數,變數的類型和數量不固定。可以認為類似於Map,實際上存儲參數庫的也就是個Map。

同樣的套路,直接在“庫”這個菜單下右鍵,“添加參數庫”。

可以看到,參數庫已經少了左邊分類這一項,直接添加參數,選擇類型就是乾,相對簡單了很多。“名稱”這列我這裡用了英文,就是Map中的key,而“標題”這列就是在配置規則時候顯示用的,中文看著比較直觀。

當然還需要註意的點是,定義的名稱要保證唯一,因為Map中的key是唯一的,不然就會存在覆蓋的情況。

3.2.4動作庫文件

動作庫可以對配置在spring中的bean方法進行映射,然後可以在規則中直接調用這批方法。慣用套路,還是在“庫”菜單下右鍵,點擊“添加動作庫”。

然後我在系統中添加了一個類Action,然後在類上標記@Component註解,將該類交給spring的bean容器管理。該類中添加一些方法,在方法上標記@ExposeAction註解,該註解是URule定義的,說明被標記的方法都會被動作庫讀取到。

package com.bstek.urule.cicada;

import com.bstek.urule.action.ActionId;
import com.bstek.urule.model.ExposeAction;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 往事如風
 * @version 1.0
 * @date 2023/3/10 13:59
 * @description
 */
@Component("action")
public class Action {

    @ActionId("Hello")
    public String hello(){
        return "hello";
    }

    @ExposeAction(value="方法1")
    public boolean evalTest(String username){
        if(username==null){
            return false;
        }else if(username.equals("張三")){
            return true;
        }
        return false;
    }

    @ExposeAction(value="測試Int")
    public int testInt(int a,int b){
        return a+b;
    }

    @ExposeAction(value="列印內容")
    public void printContent(String username, Date birthday){
        SimpleDateFormat sd=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if(birthday!=null){
            System.out.println(username+"今年已經"+sd.format(birthday)+"歲了!");
        }else{
            System.out.println("Hello "+username+"");
        }
    }

    @ExposeAction(value="列印Stu")
    public void printUser(Stu m){
        System.out.println("Hello "+m.getName()+", is age:"+m.getAge());
    }
}

最後在動作庫頁面上添加bean,“Bean Id”一列輸入對應的spring bean的名稱,這裡輸入action。然後點擊操作列中的小手按鈕,就會彈出剛在Action類中標記了ExposeAction註解的方法。選擇一個指定的方法添加進來,最後看到方法對應的參數也會被自動載入進去。

最後,變數庫、參數庫、動作庫、常量庫這些庫文件定義好後,各種規則文件配置的時候就可以導入他們。但是一旦這些庫文件被某個規則文件使用,就不要隨意修改庫文件了。

3.3規則集

說到規則集,顧名思義,就是配置規則了。前面定義的庫文件就需要導入到規則集中去配置使用。它是使用頻率最高的一個業務規則實現方式。

規則集說的是規則的集合,由三個部分規則組成:如果、那麼、否則。

在規則集的定義的方式上,URule由嚮導式和腳本式兩種;

  • 嚮導式規則集:就是在頁面上通過滑鼠點點點,高度的可視化配置,不是開發都能懂,這也是這個規則引擎的亮點所在。
  • 腳本式規則集:聽名字就知道了,這玩意要寫腳本的。拉高配置門檻,需要懂點編碼的人來編寫。

3.3.1嚮導式規則集

還是一樣,首先新建。這次是在“決策集”菜單上右鍵,點擊“添加嚮導式決策集”,這樣就創建好一個規則集了。

在配置規則前,可以先導入前面定義好的庫文件。我這裡導入變數庫文件,頁面上點擊“變數庫”,然後選擇指定的變數庫文件即可。如圖所示;

最後,可以愉快的配置規則了,嚮導式沒什麼好講的,都是可視化界面,點點點即可。下麵是我配置的一個簡單的規則集;

可以看到由三部分組成:如果、那麼、否則;

  1. 如果:配置規則的條件;
  2. 那麼:配置滿足條件後執行的動作,一般配置變數賦值比較多
  3. 否則:配置不滿足條件執行的動作

最後,附上添加完規則後,通過代碼去執行規則;

package com.cicada;

import cn.hutool.core.bean.BeanUtil;
import com.Result;
import com.bstek.urule.Utils;
import com.bstek.urule.runtime.KnowledgePackage;
import com.bstek.urule.runtime.KnowledgeSession;
import com.bstek.urule.runtime.KnowledgeSessionFactory;
import com.bstek.urule.runtime.service.KnowledgeService;
import com.cicada.req.StuReq;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

/**
 * @author 往事如風
 * @version 1.0
 * @date 2023/3/10 16:47
 * @description
 */
@RestController
@RequestMapping("/rule")
public class RuleDataController {

    @PostMapping("/stu")
    public Result rule(@RequestBody StuReq stuReq) throws IOException {
        KnowledgeService knowledgeService = (KnowledgeService) Utils.getApplicationContext().getBean(KnowledgeService.BEAN_ID);
        KnowledgePackage knowledgePackage = knowledgeService.getKnowledge("xxx/xxx");
        KnowledgeSession knowledgeSession = KnowledgeSessionFactory.newKnowledgeSession(knowledgePackage);
        Stu stu = BeanUtil.copyProperties(stuReq, Stu.class);
        knowledgeSession.insert(stu);
        knowledgeSession.fireRules();
        return Result.success(stu.getTeacher());
    }
}

請求介面,最終參數符合配置的條件,返回“那麼”中配置的輸出結果。

3.3.2腳本式規則集

腳本式的規則集,各種原理都是和嚮導式一模一樣,無非就是拉高門檻,用寫腳本的方式去實現配置的規則。這裡不做過多的介紹了。

3.4決策表

再聊下決策表,其實它就是規則集的另一種展示形式,比較相對規則集,我更喜歡用決策表去配置規則,應為它呈現的更加直觀,更便於理解。但是本質和規則集沒啥區別。

也不展開過多的贅述,這裡我就放一張配置過的決策表;

3.5其他

當然,還有其他的概念和功能,這裡也不一一介紹了,因為上面說的已經是最常用的了,想瞭解的可以自行去瞭解。其他功能包括:交叉決策表、評分卡、複雜評分卡、決策樹、規則流;當然,其中有些是Pro版的功能。

四、運用場景

最近在開發一期大版本的需求,其中就有個場景,具體如下;參與購買訂單的用戶都會有自己的一個職級,也可以說是角色。每個用戶都會有三個職位:普通用戶、會員、精英會員。

然後,每個月初都會對用戶進行一次晉升處理,普通用戶達到要求,就會晉升為會員,會員達到要求就會晉升為精英會員。

當然,普通用戶晉升會員,會員晉升精英會員,都會有不同的規則;

  1. 普通用戶->會員:3個月內幫註冊人數達到3人;3個月內自己和底下團隊的人,下單金額超過1萬;個人的訂單繼續率超過80%。
  2. 會員->精英會員:3個月內幫註冊人數達到6人;3個月內自己和底下團隊的人,下單金額超過5萬;個人的訂單繼續率超過90%。
  3. 不能跨級晉升,普通用戶最多只能到會員,達到會員了才能晉升到精英會員。

當然,這隻是做過簡化的一部分需求,我做過稍許的改動,真實的需求場景並沒有這麼簡單。

下麵,我對這個需求做一個規則的配置,這裡用一個決策表進行配置;在配置規則前,我添加一個變數庫文件和常量庫;

最後,添加一個決策表,併進行規則配置;

可以看到,表格一共五列,其中前四列是規則,最後一列是滿足規則後輸出的信息。這樣看著就很清晰,即使並不是技術人員,也可以輕鬆看懂其中的規則。

五、總結

規則引擎對於我們的系統而言可用可不用,它可以錦上添花,幫助我們剝離出業務中需要進行大量判斷的場景。但是,這種規則的剝離,需要我們開發人員對需求進行理解,在理解的基礎上進行抽象概念的具化。這,也是整個編程的必經之路

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協程要來了。。。

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!

5.《Java開發手冊(嵩山版)》最新發佈,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 具體的加密演算法可以可自行查詢其區別,這裡只是拋磚引玉,大部分加密方法基本都能通過改變傳入參數來實現。 C#相關類文檔: System.Security.Cryptography 命名空間 | Microsoft Learn Node JS相關文檔:Crypto | Node.js v16.20.0 ...
  • >我們是[袋鼠雲數棧 UED 團隊](http://ued.dtstack.cn/),致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。。 >本文作者:琉易 [liuxianyu.cn](https://link.juejin.cn/?target=h ...
  • # JavaScript 格式化金額 ## 一、[使用 `Intl.NumberFormat` 構造函數](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberForm ...
  • > 隨著人工智慧技術的不斷發展,阿裡體育等IT大廠,推出的“樂動力”、“天天跳繩”AI運動APP,讓**雲上運動會、線上運動會、健身打卡、AI體育指導**等概念空前火熱。那麼,能否將這些在APP成功應用的場景搬上小程式,分享這些概念的紅利呢?本系列文章就帶您一步一步從零開始開發一個AI運動小程式,本 ...
  • 前端構建的提速是一項比較複雜且細節的工程, 目前產品上在持續跟蹤構建慢的應用, 努力優化編譯速度, 但前端本身擁有一個比較自由的技術環境, 沒有統一的構建工具與流程, 另外語言本身的執行效率、單線程的構建也不好讓編譯機發揮其最大能力, 所以目前全局的通用優化手段還是會比較局限, 還是依賴項目自身的優... ...
  • 如果你有 *n* 個緩存伺服器,一個常見的負載均衡方式是使用以下的哈希方法: *伺服器索引 = 哈希(鍵) % N*,其中 *N* 是伺服器池的大小。 讓我們通過一個例子來說明這是如何工作的。如表5-1所示,我們有4台伺服器和8個字元串鍵及其哈希值。 ![image-2023052022160981 ...
  • # 1.初識變數 編程本質就是通過一定的規則,去操縱數據,變數作為數據的載體,在程式中經常會被用到。與變數相聯繫的還有一個名詞叫數據類型,我們可以舉一個生活中的例子,來理解**數據類型-變數-數據**三者之間的關係 ![image](https://img2023.cnblogs.com/blog/ ...
  • # 使用 Rust 構建微型游戲 -- 用於理解游戲開發 ## 一、 創建游戲 ### Agenda + 建立項目 + 實現 Game loop + 不同的游戲模式 + 添加玩家 + 添加障礙和計分 + 彙總 ### 理解 Game loop 為了讓游戲流暢、順滑的運行,需要使用 Game loop ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...