3.庫文(wén)件介紹

概述

URule Pro整個産(chǎn)品由兩部分(fēn)構成:一個是設計器部分(fēn);另一個是規則執行引擎部分(fēn)。設計器部分(fēn)主要是由庫文(wén)件設計器以及具(jù)體(tǐ)的規則文(wén)件設計器兩部分(fēn)構成。

庫文(wén)件設計器包括變量庫設計器、參數庫設計器、常量庫設計器以及動作(zuò)庫設計器四個部分(fēn),通過這些庫文(wén)件設計器,可(kě)以将業務(wù)系統中(zhōng)使用(yòng)的實體(tǐ)對象、枚舉值、常量以及需要在規則中(zhōng)調用(yòng)的Java方法映射到引擎中(zhōng)備用(yòng)。

規則文(wén)件設計器主要包括規則集、決策表、交叉決策表(決策矩陣)、決策樹、評分(fēn)卡、複雜評分(fēn)卡、規則流等八種類型的業務(wù)規則設計工(gōng)具(jù),這些設計器全部是以可(kě)視化图形方式提供,使用(yòng)者隻需要通過鼠标點擊或拖拽的方式即可(kě)完成業務(wù)規則的定義。通過在這些規則設計器中(zhōng)引入各種類型的已定義好的庫文(wén)件,就可(kě)以和業務(wù)系統結合起來,從而設計出符合需求的業務(wù)規則。

這裏我們首先來了解一下URule Pro當中(zhōng)提供的庫文(wén)件,學(xué)習其配置及使用(yòng)方法。

庫文(wén)件設計器中(zhōng),對于新(xīn)增數據,在沒保存之前,是可(kě)以直接點擊單元格進行編輯的,一旦對數據進行了保存,如果需要對保存後的數據進行編輯,那麽隻能(néng)點擊數據所在行中(zhōng)操作(zuò)列上的“編輯”按鈕實現。

之所以這樣設計,是因為(wèi)庫文(wén)件會被其它規則文(wén)件引用(yòng)使用(yòng),一旦文(wén)件保存後,就存在被其它文(wén)件引用(yòng)使用(yòng)的可(kě)能(néng)性,這樣的話,引用(yòng)數據如果允許直接修改就會導緻引用(yòng)數據與庫文(wén)件中(zhōng)定義數據不一緻的情況, 所以需要通過操作(zuò)列上的“編輯”按鈕才能(néng)實現對已保存的數據進行編輯。

這裏的“編輯”操作(zuò)保存時,實際上會嘗試取到所有(yǒu)引用(yòng)當前庫文(wén)件當前數據的規則文(wén)件,然後同步修改成最新(xīn)的值。

變量庫文(wén)件

在業務(wù)系統開發過程中(zhōng),會用(yòng)到大量包含Getter和Setter方法的簡單的Java對象,它們被稱之為(wèi)POJO(Plain Ordinary Java Object),或BOM(Business Object Model)對象,這些對象在開發中(zhōng)作(zuò)為(wèi)數據的載體(tǐ),負責數據的傳遞。在URule Pro當中(zhōng),變量庫就是用(yòng)來映射這些POJO對象,從而使得我們可(kě)以在具(jù)體(tǐ)的規則文(wén)件中(zhōng)使用(yòng)它們,從而完成規則與業務(wù)數據的交互。

打開URule Pro的操作(zuò)控制台,創建一個項目,在項目的“庫”的節點上點擊右鍵,在彈出的菜單中(zhōng)選擇“添加變量庫”就可(kě)以創建變量庫文(wén)件,如下图所示:

果你創建的項目中(zhōng)資源節點下沒有(yǒu)“庫”節點,那是因為(wèi)你修改了項目知識庫内容的展示方式,點擊左上角,在彈出的菜單中(zhōng)選擇“分(fēn)類展示”,這樣就可(kě)以看到“庫”節點。

在URule Pro當中(zhōng),通過這個功能(néng)可(kě)以修改項目知識庫内容的展示方式,選擇“分(fēn)類展示”,就可(kě)以看到上图所示效果,将項目中(zhōng)的庫文(wén)件、決策集文(wén)件、決策表文(wén)件、評分(fēn)卡文(wén)件、決策流文(wén)件分(fēn)類存放展示;如果選擇“集中(zhōng)展示”,那麽就不會對這些文(wén)件進行分(fēn)類,統一放在資源節點下。

需要注意的是,在“分(fēn)類展示”模式下,如果創建有(yǒu)目錄,那麽這個目錄會出現在所有(yǒu)的分(fēn)類下,同樣如果在某個分(fēn)類下删除某個目錄,那麽這個目錄也将會從所有(yǒu)的分(fēn)類中(zhōng)删除,創建目錄也是一樣。在“集中(zhōng)展示”模式下,因為(wèi)不進行分(fēn)類,所以目錄就不存在這種現象,這點需要注意。

在添加文(wén)件或目錄時,目錄或文(wén)件名(míng)隻能(néng)使用(yòng)英文(wén)或中(zhōng)文(wén),不支持其它非法字符。

創建好變量庫文(wén)件後,可(kě)以看到系統會用(yòng)變量庫編輯器自動打開這個文(wén)件。在這個編輯器中(zhōng),首先需要添加變量的分(fēn)類,然後再添加具(jù)體(tǐ)的變量字段。對應到Java實體(tǐ)對象,就是要添加對應的實體(tǐ)對象信息,再添加這個實體(tǐ)對象所擁有(yǒu)的屬性信息。如下图所示:

添加一個分(fēn)類,輸入名(míng)稱,這個名(míng)稱是對當前分(fēn)類的描述,會在規則中(zhōng)直接引用(yòng)顯示,所以一般我們會使用(yòng)中(zhōng)文(wén)描述來作(zuò)為(wèi)名(míng)稱,類路徑,就是這個分(fēn)類對應的實體(tǐ)類的完整路徑,比如上图中(zhōng)的“com.bstek.entity.Customer”。

變量的類路徑是規則引擎在執行過程中(zhōng)查找對應對象的唯一标識,所以在定義時一定要讓其與實際業務(wù)中(zhōng)對應的POJO對象的完整類路徑一緻,否則在運行時将會出現找不到類的情況,或者使得規則在計算時不會出現我們期望的結果。

這時,變量的分(fēn)類就定義好了,如果當前定義的類路徑對應的類在當前應用(yòng)中(zhōng)存在的話,那麽我們可(kě)以點擊“操作(zuò)列“中(zhōng)的第一個按鈕,這樣系統就會通過Java的反射功能(néng)生成當前類對應的所有(yǒu)字段信息。上图中(zhōng)com.bstek.entity.Customer類源碼如下所示:

package com.bstek.entity;
import java.util.Date;
import com.bstek.urule.model.Label;
/**
 * @author Jacky.gao
 * @since 2016年9月29日
 */
public class Customer {
    @Label("名(míng)稱")
    private String name;
    @Label("年齡")
    private int age;
    @Label("出生日期")
    private Date birthday;
    @Label("等級")
    private int level;
    @Label("手機号")
    private String mobile;
    @Label("性别")
    private boolean gender;
    @Label("是否有(yǒu)車(chē)")
    private boolean car;
    @Label("婚否")
    private boolean married;
    @Label("是否有(yǒu)房")
    private boolean house;
    //省略上述所有(yǒu)屬性對應的getter與setter方法......
}

在這個類當中(zhōng),可(kě)以看到每個屬性都有(yǒu)一個名(míng)為(wèi)Label的annotation,它是一個由URule Pro提供的用(yòng)來描述字段屬性的annotation,這裏描述的值,在生成變量時會自動寫到變量的“标題”當中(zhōng),這裏的标題将會在規則中(zhōng)直接引用(yòng),讓标題有(yǒu)意義,對于規則的清晰表達很(hěn)有(yǒu)價值。

如果這個類在當前所在的項目當中(zhōng),所以可(kě)以直接通過反射生成所有(yǒu)的屬性,生成後的效果如下:

可(kě)以看到上图中(zhōng)Label這個annotation對應的描述寫入到變量的“标題”當中(zhōng)。

在URule的服務(wù)器客戶端模式下,我們的規則都是在服務(wù)器上定義的,這就有(yǒu)可(kě)能(néng)定義變量的時候變量分(fēn)類對應的實體(tǐ)類在服務(wù)器上不存在,而隻在客戶端上存在,這種情況下就不能(néng)通過反射來生成對應的字段,這時我們可(kě)以在有(yǒu)這個實體(tǐ)類的客戶端應用(yòng)中(zhōng)通過URule Pro中(zhōng)提供的com.bstek.urule.ClassUtils來生成目标實體(tǐ)類的xml描述文(wén)件,然後在到服務(wù)器上,點擊變量分(fēn)類“操作(zuò)列”上中(zhōng)間那個上傳图标将這個xml描述文(wén)件上傳,同樣可(kě)以生成對應的字段信息。使用(yòng)ClassUtils類生成描述文(wén)件的代碼如下所示:

public static void main(String[] args) {
    File file=new File("d:/customer.xml");
    ClassUtils.classToXml(Customer.class, file);
}

運行這個main方法,就會在D盤下生成一個customer.xml的實體(tǐ)類描述文(wén)件,再上傳這個文(wén)件即可(kě)。

在定義變量庫文(wén)件時,對應的實體(tǐ)類不一定真實存在。在仿真測試中(zhōng),在運行規則時,如果發現對應的實體(tǐ)類不在當前JVM的classpath中(zhōng)時,引擎會使用(yòng)一個名(míng)為(wèi)GeneralEntity的類來代替這目标實現類運行。所以在URule Pro的客戶端服務(wù)器模式下,服務(wù)器上定義變量庫時,對應的實體(tǐ)類一般都不在服務(wù)器上,而位于調用(yòng)規則運行的客戶端上,但對于服務(wù)器上規則定義與測試是沒有(yǒu)影響的。

這到裏,變量庫文(wén)件就定義好了,可(kě)以根據需要在一個文(wén)件中(zhōng)添加多(duō)個變量分(fēn)類,相應對應到多(duō)個POJO類。

變量定義好了之後,會被其它類型的規則文(wén)件引用(yòng),如果後期變量需要需要修改,在設計界面中(zhōng)提供了變更名(míng)的重構功能(néng)。在上面的操作(zuò)中(zhōng)我們可(kě)以看到,無論是變量的分(fēn)類名(míng)稱,還是具(jù)體(tǐ)的變量名(míng)在其操作(zuò)列上都有(yǒu)一個图标,點擊該图标就可(kě)以對當前行的變量名(míng)進行修改,這樣就可(kě)以同步修改所有(yǒu)引用(yòng)當前變量的規則文(wén)件,從而完成了變量名(míng)的重構。

在後面介紹的常量、參數、動作(zuò)庫文(wén)件中(zhōng),對于它們的名(míng)稱的修改,同樣提供重構功能(néng)的支持,這裏不再贅述。

常量庫文(wén)件

在業務(wù)系統開發過程中(zhōng),常常會用(yòng)到一個枚舉數據,比如用(yòng)戶的性别、學(xué)曆等,在URule Pro當中(zhōng),通過定義常量庫文(wén)件,可(kě)以将系統中(zhōng)使用(yòng)的這些枚舉數據映射到規則中(zhōng)使用(yòng),這樣就可(kě)以避免規則定義過程中(zhōng)枚舉數據手工(gōng)輸入存在錯誤的可(kě)能(néng)性。

選中(zhōng)我們的項目,在“庫”節點上右鍵,創建一個常量庫文(wén)件,如下图所示:

與變量庫文(wén)件類似,常量也是由分(fēn)類和具(jù)體(tǐ)的常量值構成,比如性别有(yǒu)男女之分(fēn),那麽這裏的“性别”就屬性分(fēn)類,“男”、“女”就屬性具(jù)體(tǐ)的常量值。在常量的分(fēn)類中(zhōng),“名(míng)稱”一般定義具(jù)體(tǐ)的分(fēn)類名(míng),“标題”是一段描述(比如“性别”是标題,“gender”是名(míng)稱),同樣這個标題也會出現在規則引用(yòng)當中(zhōng);加好分(fēn)類後就可(kě)以添加這個分(fēn)類下具(jù)體(tǐ)的常量值,常量值也有(yǒu)名(míng)稱和标題之分(fēn),名(míng)稱是具(jù)體(tǐ)的常量值,标題則是描述,比如“男”是标題,"true"是名(míng)稱,同樣“女”是标題,“false”是名(míng)稱,如下图所示:

同樣,在一個變量庫文(wén)件中(zhōng)可(kě)以根據需要添加多(duō)個變量分(fēn)類。

常量定義時,其名(míng)稱值可(kě)使用(yòng)Spring中(zhōng)加載的properties文(wén)件值,具(jù)體(tǐ)使用(yòng)方法是将要引用(yòng)的properties的key值用(yòng)${...}包裹,這樣在具(jù)體(tǐ)規則運行時會動态查找這個包裹的屬性值作(zuò)為(wèi)具(jù)體(tǐ)的常量,如:${app.title}表示取spring中(zhōng)properties文(wén)件的名(míng)為(wèi)app.title的屬性值。利用(yòng)這一功能(néng),可(kě)實現測試環境與生産(chǎn)環境的動态切換。

從2.1.9版本開始,常量庫文(wén)件在定義時支持從一個具(jù)體(tǐ)的Java枚舉類中(zhōng)直接導入,方法是點擊图标,在彈出的窗口中(zhōng)輸入完整的枚舉類路徑即可(kě)實現将枚舉類裏的枚舉值導入到當前常量分(fēn)類之下。

在通過枚舉類導入具(jù)體(tǐ)常量時,如果枚舉類中(zhōng)未定義getLabel方法,那麽導入的枚舉信息則隻采用(yòng)其name屬性,如果定義了getLabel方法,那麽導入後的枚舉信息則包含name和label,包含getLabel方法的枚舉類示例如下所示:

public enum TestEnum {
    aaa("張三"),bbb("李四");
    private String label;
    private TestEnum(String label) {
        this.label=label;
    }
    public String getLabel() {
        return label;
    }
}

參數庫文(wén)件

在規則的條件判斷與計算過程當中(zhōng),難免會用(yòng)到一些臨時的變量來存儲值,這些臨時變量數量和類型都可(kě)能(néng)是不固定的,對于這種類型的臨時變量,URule Pro以參數的形式提供,通過參數庫就可(kě)以定義這些在規則中(zhōng)要使用(yòng)到的臨時變量。

在“庫”節點上右鍵創建一個參數庫文(wén)件,從參數庫文(wén)件編輯器來看,參數因為(wèi)沒有(yǒu)了分(fēn)類,配置要為(wèi)簡單許多(duō),如下图所示:

參數庫在運行時實際上是存儲在HashMap當中(zhōng),這裏的“名(míng)稱”的值将作(zuò)為(wèi)Map的key,“标題”則用(yòng)在規則中(zhōng)顯示使用(yòng),定義參數庫時要保證“名(míng)稱”屬性的唯一性,因為(wèi)它是Map的key值; 同時如果一個規則文(wén)件裏引入多(duō)個參數庫文(wén)件,那麽每個參數庫文(wén)件裏定義的參數的名(míng)稱值也要唯一,否則就會存在相互覆蓋的情況。

在URule Pro當中(zhōng),對于參數庫中(zhōng)定義的值,規則運行時,如果外部沒有(yǒu)對這些參數進行初始化,那麽引擎會自動為(wèi)部分(fēn)沒有(yǒu)初始化的參數進行初始化。下表中(zhōng)介紹了URule Pro中(zhōng)會自動初始化的數據類型自動初始化後的值。

數據類型 初始化值
Integer 0
Double 0
Float 0
Boolean false
List new ArrayList()
Set new HashSet()
Map new HashMap()

如果我們當前項目中(zhōng)已定義好若幹個變量庫文(wén)件,且文(wén)件中(zhōng)都定義了相應的變量對象,那麽在打開參數庫文(wén)件,添加參數時,我們會發現參數的數據類型除了固定的13種數據類型外, 還有(yǒu)當前項目中(zhōng)所有(yǒu)變量庫文(wén)件裏定義的變量分(fēn)類值;如果在定義參數時數據類型選擇為(wèi)某個變量的分(fēn)類名(míng),那麽在使用(yòng)這個參數時,除了可(kě)以選擇參數自身,還能(néng)選擇參數對應的變量下的具(jù)體(tǐ)屬性值,如下图所示:

因為(wèi)參數的數據類型可(kě)以指定為(wèi)某個變量類型,所以在設計一些複雜規則的時候就顯得特别有(yǒu)意義,比如我們可(kě)以通過這種方式創建一個新(xīn)的變量對象實例, 然後賦值給某個是這個變量數據類型的參數,然後再通過這個參數給這個新(xīn)的對象實例的屬性進行逐個賦值等。

動作(zuò)庫文(wén)件

動作(zuò)庫文(wén)件的作(zuò)用(yòng)是對配置在spring中(zhōng)的bean方法進行映射,使得我們可(kě)以直接在規則當中(zhōng)調用(yòng)這些方法。同樣在項目的“庫”節點下創建一個動作(zuò)庫文(wén)件,可(kě)以看到動作(zuò)庫文(wén)件内容有(yǒu)三列,分(fēn)别是動作(zuò)名(míng)稱,bean的id定義列,方法名(míng)定義列,以及方法對應的參數定義列,如下图所示:

為(wèi)了演示這裏定義方法的具(jù)體(tǐ)操作(zuò),下面是一個名(míng)為(wèi)MethodTest的類源碼:

package rete.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.bstek.urule.action.ActionId;
import com.bstek.urule.model.ExposeAction;
/**
 * @author Jacky.gao
 * @since 2015年1月14日
 */
public class MethodTest {
    @ActionId("Hello")
    public String hello(){
        return "hello";
    }
    @ExposeAction(value="方法1",parameters={"用(yòng)戶名(míng)"})
    public boolean evalTest(String username){
        if(username==null){
            return false;
        }else if(username.equals("張三")){
            return true;
        }
        return false;
    }

    @ExposeAction(value="測試Int",parameters={"數字1","數字2"})
    public int testInt(int a,int b){
        return a+b;
    }
    public int testInteger(Integer a,int b){
        return a+b*10;
    }

    @ExposeAction(value="打印内容",parameters={"用(yòng)戶名(míng)","出生日期"})
    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="打印Member",parameters={"Member對象"})
    public void printUser(Member m){
        System.out.println("Hello "+m.getUsername()+", has house:"+m.isHouse());
    }
}

在這個MethodTest類中(zhōng),我們對需要在動作(zuò)庫中(zhōng)引用(yòng)的方法上都添加了一個名(míng)為(wèi)ExposeAction的annotation,這就表示這個方法可(kě)以暴露給規則引用(yòng),反之如果不加這個annotation,那麽這個方法就不能(néng)在定義動作(zuò)時直接引用(yòng)。 同樣我們也看到對于需要在動作(zuò)庫中(zhōng)引用(yòng)的方法是不需要實現任何接口的,方法簽名(míng)也是任意的,隻需要在方法上添加ExposeAction這個annotation即可(kě),接下來,我們需要将這個類配置到spring中(zhōng),讓其成為(wèi)一個标準的bean,spring中(zhōng)的配置如下:

<bean id="methodTest" class="rete.test.MethodTest"></bean>

定義動作(zuò)庫的Bean時,一定不要忘記給Bean定義一個Id,這樣才能(néng)保證規則在任何地方運行都不會出錯,這點很(hěn)關鍵。

回到動作(zuò)庫文(wén)件編輯器,點擊“添加Bean”按鈕,添加一條Bean定義信息,将"Bean Id"屬性值改為(wèi)我們這裏的“methodTest”,點擊當前行“操作(zuò)列”中(zhōng)第一個图标選擇這個bean中(zhōng)的方法,以實現bean方法的映射,如下图所示:

所有(yǒu)添加了ExposeAction的annotation的方法都出同在這個列表中(zhōng),我們可(kě)以根據選擇添加即可(kě),可(kě)以看到添加的方法會自動将這個方法所需要的參數加載進去,添加成功後,為(wèi)了在規則中(zhōng)更好的可(kě)讀性,我們可(kě)以修改“動作(zuò)名(míng)稱”、“方法名(míng)稱”以及“參數名(míng)稱”。

可(kě)以看到,所有(yǒu)的庫文(wén)件除了可(kě)以保存外,還提供了一個名(míng)為(wèi)“保存為(wèi)版本”的按鈕,通過這個按鈕,可(kě)以将當前文(wén)件内容保存為(wèi)一個新(xīn)的版本,這樣在規則中(zhōng)就可(kě)以引用(yòng)特定版本,特定版本的庫文(wén)件不會被修改。實際上在URule Pro中(zhōng)所有(yǒu)的文(wén)件都可(kě)以保存為(wèi)新(xīn)版本。

“查看引用(yòng)”按鈕,就是用(yòng)來查看當前庫文(wén)件被哪些規則文(wén)件使用(yòng)了,會有(yǒu)個列表顯示出來,方便我們後續維護。

在動作(zuò)庫定義的時候需要注意,如果我們規則運行方式采用(yòng)的是客戶端服務(wù)器模式(參見第16小(xiǎo)節内容介紹),那麽必須要保證調用(yòng)知識包的客戶端Spring環境裏有(yǒu)這個Bean,且Bean的Id要與動作(zuò)庫定義時的Id保證一至,否則調用(yòng)會出現錯誤。

變量庫、參數庫、動作(zuò)庫、常量庫這些庫文(wén)件定義好後,就可(kě)以在各種類型的規則文(wén)件中(zhōng)導入并使用(yòng)它們,一旦某個庫文(wén)件在規則中(zhōng)被使用(yòng),我們就不能(néng)再随便修改這些已定義好的庫文(wén)件的名(míng)稱、值或數據類型, 如果因為(wèi)業務(wù)調整需要必須要進行修改,那麽可(kě)以通過這些變量、常量、參數、動作(zuò)定義的操作(zuò)列上的修改图标來對它們進行修改,這樣可(kě)以保證引用(yòng)文(wén)件同步更新(xīn)。

results matching ""

    No results matching ""