URule Pro整個產(chǎn)品由兩部分構(gòu)成:一個是設(shè)計器部分;另一個是規(guī)則執(zhí)行引擎部分。設(shè)計器部分主要是由庫文件設(shè)計器以及具體的規(guī)則文件設(shè)計器兩部分構(gòu)成。
庫文件設(shè)計器包括變量庫設(shè)計器、參數(shù)庫設(shè)計器、常量庫設(shè)計器以及動作庫設(shè)計器四個部分,通過這些庫文件設(shè)計器,可以將業(yè)務(wù)系統(tǒng)中使用的實體對象、枚舉值、常量以及需要在規(guī)則中調(diào)用的Java方法映射到引擎中備用。
規(guī)則文件設(shè)計器主要包括規(guī)則集、決策表、交叉決策表(決策矩陣)、決策樹、評分卡、復(fù)雜評分卡、規(guī)則流等八種類型的業(yè)務(wù)規(guī)則設(shè)計工具,這些設(shè)計器全部是以可視化圖形方式提供,使用者只需要通過鼠標點擊或拖拽的方式即可完成業(yè)務(wù)規(guī)則的定義。通過在這些規(guī)則設(shè)計器中引入各種類型的已定義好的庫文件,就可以和業(yè)務(wù)系統(tǒng)結(jié)合起來,從而設(shè)計出符合需求的業(yè)務(wù)規(guī)則。
這里我們首先來了解一下URule Pro當中提供的庫文件,學(xué)習(xí)其配置及使用方法。
在業(yè)務(wù)系統(tǒng)開發(fā)過程中,會用到大量包含Getter和Setter方法的簡單的Java對象,它們被稱之為POJO(Plain Ordinary Java Object),或BOM(Business Object Model)對象,這些對象在開發(fā)中作為數(shù)據(jù)的載體,負責數(shù)據(jù)的傳遞。在URule Pro當中,變量庫就是用來映射這些POJO對象,從而使得我們可以在具體的規(guī)則文件中使用它們,從而完成規(guī)則與業(yè)務(wù)數(shù)據(jù)的交互。
打開URule Pro的操作控制臺,創(chuàng)建一個項目,在項目的“庫”的節(jié)點上點擊右鍵,在彈出的菜單中選擇“添加變量庫”就可以創(chuàng)建變量庫文件,如下圖所示:
果你創(chuàng)建的項目中資源節(jié)點下沒有“庫”節(jié)點,那是因為你修改了項目知識庫內(nèi)容的展示方式,點擊左上角,在彈出的菜單中選擇“分類展示”,這樣就可以看到“庫”節(jié)點。
在URule Pro當中,通過這個功能可以修改項目知識庫內(nèi)容的展示方式,選擇“分類展示”,就可以看到上圖所示效果,將項目中的庫文件、決策集文件、決策表文件、評分卡文件、決策流文件分類存放展示;如果選擇“集中展示”,那么就不會對這些文件進行分類,統(tǒng)一放在資源節(jié)點下。
需要注意的是,在“分類展示”模式下,如果創(chuàng)建有目錄,那么這個目錄會出現(xiàn)在所有的分類下,同樣如果在某個分類下刪除某個目錄,那么這個目錄也將會從所有的分類中刪除,創(chuàng)建目錄也是一樣。在“集中展示”模式下,因為不進行分類,所以目錄就不存在這種現(xiàn)象,這點需要注意。
在添加文件或目錄時,目錄或文件名只能使用英文或中文,不支持其它非法字符。
創(chuàng)建好變量庫文件后,可以看到系統(tǒng)會用變量庫編輯器自動打開這個文件。在這個編輯器中,首先需要添加變量的分類,然后再添加具體的變量字段。對應(yīng)到Java實體對象,就是要添加對應(yīng)的實體對象信息,再添加這個實體對象所擁有的屬性信息。如下圖所示:
添加一個分類,輸入名稱,這個名稱是對當前分類的描述,會在規(guī)則中直接引用顯示,所以一般我們會使用中文描述來作為名稱,類路徑,就是這個分類對應(yīng)的實體類的完整路徑,比如上圖中的“com.bstek.entity.Customer”。
變量的類路徑是規(guī)則引擎在執(zhí)行過程中查找對應(yīng)對象的唯一標識,所以在定義時一定要讓其與實際業(yè)務(wù)中對應(yīng)的POJO對象的完整類路徑一致,否則在運行時將會出現(xiàn)找不到類的情況,或者使得規(guī)則在計算時不會出現(xiàn)我們期望的結(jié)果。
這時,變量的分類就定義好了,如果當前定義的類路徑對應(yīng)的類在當前應(yīng)用中存在的話,那么我們可以點擊“操作列“中的第一個按鈕,這樣系統(tǒng)就會通過Java的反射功能生成當前類對應(yī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("名稱")
private String name;
@Label("年齡")
private int age;
@Label("出生日期")
private Date birthday;
@Label("等級")
private int level;
@Label("手機號")
private String mobile;
@Label("性別")
private boolean gender;
@Label("是否有車")
private boolean car;
@Label("婚否")
private boolean married;
@Label("是否有房")
private boolean house;
//省略上述所有屬性對應(yīng)的getter與setter方法......
}
在這個類當中,可以看到每個屬性都有一個名為Label的annotation,它是一個由URule Pro提供的用來描述字段屬性的annotation,這里描述的值,在生成變量時會自動寫到變量的“標題”當中,這里的標題將會在規(guī)則中直接引用,讓標題有意義,對于規(guī)則的清晰表達很有價值。
如果這個類在當前所在的項目當中,所以可以直接通過反射生成所有的屬性,生成后的效果如下:
可以看到上圖中Label這個annotation對應(yīng)的描述寫入到變量的“標題”當中。
在URule的服務(wù)器客戶端模式下,我們的規(guī)則都是在服務(wù)器上定義的,這就有可能定義變量的時候變量分類對應(yīng)的實體類在服務(wù)器上不存在,而只在客戶端上存在,這種情況下就不能通過反射來生成對應(yīng)的字段,這時我們可以在有這個實體類的客戶端應(yīng)用中通過URule Pro中提供的com.bstek.urule.ClassUtils來生成目標實體類的xml描述文件,然后在到服務(wù)器上,點擊變量分類“操作列”上中間那個上傳圖標將這個xml描述文件上傳,同樣可以生成對應(yīng)的字段信息。使用ClassUtils類生成描述文件的代碼如下所示:
public static void main(String[] args) {
File file=new File("d:/customer.xml");
ClassUtils.classToXml(Customer.class, file);
}
運行這個main方法,就會在D盤下生成一個customer.xml的實體類描述文件,再上傳這個文件即可。
在定義變量庫文件時,對應(yīng)的實體類不一定真實存在。在仿真測試中,在運行規(guī)則時,如果發(fā)現(xiàn)對應(yīng)的實體類不在當前JVM的classpath中時,引擎會使用一個名為GeneralEntity的類來代替這目標實現(xiàn)類運行。所以在URule Pro的客戶端服務(wù)器模式下,服務(wù)器上定義變量庫時,對應(yīng)的實體類一般都不在服務(wù)器上,而位于調(diào)用規(guī)則運行的客戶端上,但對于服務(wù)器上規(guī)則定義與測試是沒有影響的。
這到里,變量庫文件就定義好了,可以根據(jù)需要在一個文件中添加多個變量分類,相應(yīng)對應(yīng)到多個POJO類。
變量定義好了之后,會被其它類型的規(guī)則文件引用,如果后期變量需要需要修改,在設(shè)計界面中提供了變更名的重構(gòu)功能。在上面的操作中我們可以看到,無論是變量的分類名稱,還是具體的變量名在其操作列上都有一個圖標,點擊該圖標就可以對當前行的變量名進行修改,這樣就可以同步修改所有引用當前變量的規(guī)則文件,從而完成了變量名的重構(gòu)。
在后面介紹的常量、參數(shù)、動作庫文件中,對于它們的名稱的修改,同樣提供重構(gòu)功能的支持,這里不再贅述。
在業(yè)務(wù)系統(tǒng)開發(fā)過程中,常常會用到一個枚舉數(shù)據(jù),比如用戶的性別、學(xué)歷等,在URule Pro當中,通過定義常量庫文件,可以將系統(tǒng)中使用的這些枚舉數(shù)據(jù)映射到規(guī)則中使用,這樣就可以避免規(guī)則定義過程中枚舉數(shù)據(jù)手工輸入存在錯誤的可能性。
選中我們的項目,在“庫”節(jié)點上右鍵,創(chuàng)建一個常量庫文件,如下圖所示:
與變量庫文件類似,常量也是由分類和具體的常量值構(gòu)成,比如性別有男女之分,那么這里的“性別”就屬性分類,“男”、“女”就屬性具體的常量值。在常量的分類中,“名稱”一般定義具體的分類名,“標題”是一段描述(比如“性別”是標題,“gender”是名稱),同樣這個標題也會出現(xiàn)在規(guī)則引用當中;加好分類后就可以添加這個分類下具體的常量值,常量值也有名稱和標題之分,名稱是具體的常量值,標題則是描述,比如“男”是標題,"true"是名稱,同樣“女”是標題,“false”是名稱,如下圖所示:
同樣,在一個變量庫文件中可以根據(jù)需要添加多個變量分類。
常量定義時,其名稱值可使用Spring中加載的properties文件值,具體使用方法是將要引用的properties的key值用${...}包裹,這樣在具體規(guī)則運行時會動態(tài)查找這個包裹的屬性值作為具體的常量,如:${app.title}表示取spring中properties文件的名為app.title的屬性值。利用這一功能,可實現(xiàn)測試環(huán)境與生產(chǎn)環(huán)境的動態(tài)切換。
從2.1.9版本開始,常量庫文件在定義時支持從一個具體的Java枚舉類中直接導(dǎo)入,方法是點擊圖標,在彈出的窗口中輸入完整的枚舉類路徑即可實現(xiàn)將枚舉類里的枚舉值導(dǎo)入到當前常量分類之下。
在通過枚舉類導(dǎo)入具體常量時,如果枚舉類中未定義getLabel方法,那么導(dǎo)入的枚舉信息則只采用其name屬性,如果定義了getLabel方法,那么導(dǎo)入后的枚舉信息則包含name和label,包含getLabel方法的枚舉類示例如下所示:
public enum TestEnum {
aaa("張三"),bbb("李四");
private String label;
private TestEnum(String label) {
this.label=label;
}
public String getLabel() {
return label;
}
}
在規(guī)則的條件判斷與計算過程當中,難免會用到一些臨時的變量來存儲值,這些臨時變量數(shù)量和類型都可能是不固定的,對于這種類型的臨時變量,URule Pro以參數(shù)的形式提供,通過參數(shù)庫就可以定義這些在規(guī)則中要使用到的臨時變量。
在“庫”節(jié)點上右鍵創(chuàng)建一個參數(shù)庫文件,從參數(shù)庫文件編輯器來看,參數(shù)因為沒有了分類,配置要為簡單許多,如下圖所示:
參數(shù)庫在運行時實際上是存儲在HashMap當中,這里的“名稱”的值將作為Map的key,“標題”則用在規(guī)則中顯示使用,定義參數(shù)庫時要保證“名稱”屬性的唯一性,因為它是Map的key值;同時如果一個規(guī)則文件里引入多個參數(shù)庫文件,那么每個參數(shù)庫文件里定義的參數(shù)的名稱值也要唯一,否則就會存在相互覆蓋的情況。
在URule Pro當中,對于參數(shù)庫中定義的值,規(guī)則運行時,如果外部沒有對這些參數(shù)進行初始化,那么引擎會自動為部分沒有初始化的參數(shù)進行初始化。下表中介紹了URule Pro中會自動初始化的數(shù)據(jù)類型自動初始化后的值。
數(shù)據(jù)類型 | 初始化值 |
---|---|
Integer | 0 |
Double | 0 |
Float | 0 |
Boolean | false |
List | new ArrayList() |
Set | new HashSet() |
Map | new HashMap() |
動作庫文件的作用是對配置在spring中的bean方法進行映射,使得我們可以直接在規(guī)則當中調(diào)用這些方法。同樣在項目的“庫”節(jié)點下創(chuàng)建一個動作庫文件,可以看到動作庫文件內(nèi)容有三列,分別是動作名稱,bean的id定義列,方法名定義列,以及方法對應(yīng)的參數(shù)定義列,如下圖所示:
為了演示這里定義方法的具體操作,下面是一個名為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("helloKey")
public String hello(String username){
System.out.println("hello "+username);
return "hello"+username;
}
@ExposeAction("方法1")
public boolean evalTest(String username){
if(username==null){
return false;
}else if(username.equals("張三")){
return true;
}
return false;
}
@ExposeAction("測試Int")
public int testInt(int a,int b){
return a+b;
}
public int testInteger(Integer a,int b){
return a+b*10;
}
@ExposeAction("打印內(nèi)容")
public void printContent(String username,Date birthday){
SimpleDateFormat sd=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if(birthday!=null){
System.out.println(username+"今年已經(jīng)"+sd.format(birthday)+"歲了!");
}else{
System.out.println("Hello "+username+"");
}
}
@ExposeAction("打印Member")
public void printUser(Member m){
System.out.println("Hello "+m.getUsername()+", has house:"+m.isHouse());
}
}
在這個MethodTest類中,我們對需要在動作庫中引用的方法上都添加了一個名為ExposeAction的annotation,這就表示這個方法可以暴露給規(guī)則引用,反之如果不加這個annotation,那么這個方法就不能在規(guī)則中引用。同樣我們也看到對于需要在動作庫中引用的方法是不需要實現(xiàn)任何接口的,方法簽名也是任意的,只需要在方法上添加ExposeAction這個annotation即可,接下來,我們需要將這個類配置到spring中,讓其成為一個標準的bean,spring中的配置如下:
<bean id="methodTest" class="rete.test.MethodTest"></bean>
定義動作庫的Bean時,一定不要忘記給Bean定義一個Id,這樣才能保證規(guī)則在任何地方運行都不會出錯,這點很關(guān)鍵。
回到動作庫文件編輯器,點擊“添加Bean”按鈕,添加一條Bean定義信息,將"Bean Id"屬性值改為我們這里的“methodTest”,點擊當前行“操作列”中第一個圖標選擇這個bean中的方法,以實現(xiàn)bean方法的映射,如下圖所示:
所有添加了ExposeAction的annotation的方法都出同在這個列表中,我們可以根據(jù)選擇添加即可,可以看到添加的方法會自動將這個方法所需要的參數(shù)加載進去,添加成功后,為了在規(guī)則中更好的可讀性,我們可以修改“動作名稱”、“方法名稱”以及“參數(shù)名稱”。
可以看到,所有的庫文件除了可以保存外,還提供了一個名為“保存為版本”的按鈕,通過這個按鈕,可以將當前文件內(nèi)容保存為一個新的版本,這樣在規(guī)則中就可以引用特定版本,特定版本的庫文件不會被修改。實際上在URule Pro中所有的文件都可以保存為新版本。
“查看引用”按鈕,就是用來查看當前庫文件被哪些規(guī)則文件使用了,會有個列表顯示出來,方便我們后續(xù)維護。
在動作庫定義的時候需要注意,如果我們規(guī)則運行方式采用的是客戶端服務(wù)器模式(參見第16小節(jié)內(nèi)容介紹),那么必須要保證調(diào)用知識包的客戶端Spring環(huán)境里有這個Bean,且Bean的Id要與動作庫定義時的Id保證一至,否則調(diào)用會出現(xiàn)錯誤。
變量庫、參數(shù)庫、動作庫、常量庫這些庫文件定義好后,就可以在各種類型的規(guī)則文件中導(dǎo)入并使用它們,一旦某個庫文件在規(guī)則中被使用,我們就不能再隨便修改這些已定義好的庫文件的名稱、值或數(shù)據(jù)類型,如果因為業(yè)務(wù)調(diào)整需要必須要進行修改,那么可以通過這些變量、常量、參數(shù)、動作定義的操作列上的重構(gòu)圖標來對它們進行修改,這樣可以保證引用文件同步更新;如果不采用重構(gòu)功能而直接修改的話,那么引用的其它類型的規(guī)則文件就會出現(xiàn)打開報錯的情況。
更多建議: