在前面的內(nèi)容當(dāng)中,我們介紹的URule Pro的兩種部署模式,分別是嵌入式和分布式計(jì)算模式。這里的分布式計(jì)算模式,就是把規(guī)則的計(jì)算分布到各個(gè)客戶端節(jié)點(diǎn)上,從而可以大大減輕傳統(tǒng)集中式計(jì)算時(shí)對(duì)單一服務(wù)器的壓力。
有些時(shí)候客戶端環(huán)境可能比較復(fù)雜,如采用非Java語(yǔ)言編寫(xiě)的客戶端,如Javascript、C++或C#等,或者是客戶端不希望加入U(xiǎn)Rule Pro的相關(guān)Jar包等等,但這些客戶端也需要調(diào)用規(guī)則引擎進(jìn)行業(yè)務(wù)規(guī)則的計(jì)算, 這個(gè)時(shí)候,URule Pro提供的兩種部署模式就無(wú)法滿足需求,所以這里就提供了第三種模式,也就是傳統(tǒng)的獨(dú)立服務(wù)模式。
從2.1.7版本開(kāi)始,URule Pro中提供了統(tǒng)一的Restful服務(wù)調(diào)用接口,通過(guò)在知識(shí)包上進(jìn)行簡(jiǎn)單的配置,即可實(shí)現(xiàn)將業(yè)務(wù)規(guī)則計(jì)算暴露成Restful接口,對(duì)于客戶端來(lái)說(shuō), 調(diào)用接口時(shí),只需要符合要求的JSON格式數(shù)據(jù)即可實(shí)現(xiàn)業(yè)務(wù)規(guī)則計(jì)算,同時(shí)Restful接口也會(huì)返回統(tǒng)一的JSON格式數(shù)據(jù)作為計(jì)算結(jié)果輸出。
這里需要特別強(qiáng)調(diào)的是,如果您當(dāng)前打算把URule Pro用在一個(gè)構(gòu)建于SpringBoot之上的項(xiàng)目中,那么在配置知識(shí)包的Rest服務(wù)前需要重寫(xiě)SpringBoot中的HiddenHttpMethodFilter攔截器。
SpringBoot在運(yùn)行時(shí)會(huì)自動(dòng)加入這個(gè)HiddenHttpMethodFilter攔截器,在這個(gè)攔截器里又調(diào)用了HttpServletRequest的getParameter方法,
這就導(dǎo)致后續(xù)在URule Pro中用于處理Rest服務(wù)請(qǐng)求的Servlet通過(guò)HttpServletRequest獲取到的InputStream參數(shù)值為null,從而會(huì)產(chǎn)生輸入數(shù)據(jù)為空的異常。
要解決這一問(wèn)題就需要重寫(xiě)這個(gè)HiddenHttpMethodFilter攔截器,具體大家可以打開(kāi)百度,搜索關(guān)鍵詞“SpringBoot中request.getInputStream()”,就可以看到大量關(guān)于這一問(wèn)題的討論和解決辦法,這里就不再贅述。
如果您單獨(dú)使用了SpringMVC框架,那么也會(huì)存在上面的問(wèn)題,解決方法大家同樣可以在百度中搜索關(guān)鍵詞“SpringMVC中request.getInputStream()”,就可以看到對(duì)應(yīng)的解決問(wèn)題的辦法。
打開(kāi)知識(shí)包管理頁(yè)面,選中某一具體的知識(shí)包項(xiàng)目,然后點(diǎn)擊工具欄上的“服務(wù)調(diào)用配置”按鈕,如下圖所示:
可以看到,配置窗口還是比較簡(jiǎn)單的,我們需要做的就是配置好輸入、輸出數(shù)據(jù)以及調(diào)用時(shí)是否啟用用戶名密碼驗(yàn)證即可。需要注意的是,輸入輸出數(shù)據(jù)必須要都配置好后才能保存,不能只配置輸入數(shù)據(jù)不配置輸出數(shù)據(jù),反過(guò)來(lái)也是一樣。
上圖上,我們勾選了部分輸入輸出數(shù)據(jù),點(diǎn)擊確定,再點(diǎn)擊工具欄上的“保存”按鈕將配置后的知識(shí)包進(jìn)行保存,接下來(lái),我們就可以查看針對(duì)這個(gè)知識(shí)包配置的Restful服務(wù)信息了。
再次選擇目標(biāo)知識(shí)包,點(diǎn)擊工具欄上的“服務(wù)調(diào)用配置”按鈕,在彈出的窗口中選擇下方的“查看Restful描述”按鈕,就可以看到當(dāng)前知識(shí)包已配置好的Restful服務(wù)接口的描述數(shù)據(jù),描述服務(wù)的格式為JSON,內(nèi)容如下所示:
{
"output": [
{
"name": "貸款信息",
"fields": [
{
"name": "id",
"label": "ID"
},
{
"name": "money",
"label": "貸款額度"
},
{
"name": "result",
"label": "結(jié)果"
}
]
},
{
"name": "參數(shù)",
"fields": [
{
"name": "env",
"label": "環(huán)境情況"
}
]
}
],
"input": [
{
"name": "客戶",
"fields": [
{
"name": "age",
"label": "年齡"
},
......
{
"name": "salary",
"label": "薪水"
}
]
},
{
"name": "貸款信息",
"fields": [
{
"name": "result",
"label": "結(jié)果"
},
{
"name": "money",
"label": "貸款額度"
},
{
"name": "id",
"label": "ID"
}
]
}
],
"url": "http://localhost:8081/urule-pro-test/urule/rest/我的項(xiàng)目/loantest",
"authentication": false
}
為減少內(nèi)容占用,上面的JSON中"......"代表隱去的部分?jǐn)?shù)據(jù)。
在上面的JSON格式調(diào)用描述數(shù)據(jù)當(dāng)中,“input”和“output”屬性值分別表示輸入和輸出數(shù)據(jù),“url”表示的是調(diào)用的URL;“authentication”屬性值表示的是當(dāng)前Restful服務(wù)調(diào)用是否需要用戶名密碼驗(yàn)證,這里的值是false,表示不需要驗(yàn)證。
需要注意的是,上述過(guò)程必須要保證是在配置完成保存后才能操作。
回到服務(wù)調(diào)用配置窗口,點(diǎn)擊窗口下方的“Restful服務(wù)調(diào)用測(cè)試”按鈕,就可以打開(kāi)當(dāng)前知識(shí)包的服務(wù)調(diào)用測(cè)試頁(yè)面,如下圖所示:
在測(cè)試頁(yè)面當(dāng)中,左邊為要提交的JSON格式數(shù)據(jù),這里引擎已將我們配置中定義好的輸入數(shù)據(jù)轉(zhuǎn)換成標(biāo)準(zhǔn)的JSON格式,我們只需要填充具體數(shù)據(jù)即可。
從圖中可以看出,這里的JSON格式的輸入數(shù)據(jù),與我們想象中的對(duì)象的標(biāo)準(zhǔn)JSON格式略有不同。 這里,要提交的輸入數(shù)據(jù)有兩個(gè),分別是“客戶”和“貸款信息”,所以JSON以"[ ]"包裹,表示為一個(gè)集合類型的數(shù)據(jù)(當(dāng)然,如果你配置的輸入數(shù)據(jù)對(duì)象只有一個(gè),那就直接提交一個(gè)對(duì)象就行);這里的“客戶”和“貸款信息”兩個(gè)對(duì)象,都用name屬性來(lái)標(biāo)明對(duì)象類型, 這里的name屬性用的是我們規(guī)則變量庫(kù)里定義的對(duì)象分類名,實(shí)際上,name屬性值也可以是變量庫(kù)里對(duì)象類路徑全名,無(wú)論用哪個(gè)引擎都可以正確識(shí)別;接下來(lái)就是“fields”屬性,它是一個(gè)對(duì)象類型, 里面具體的屬性用于標(biāo)明當(dāng)前對(duì)象需要的屬性名及屬性值,所有的屬性值都是一個(gè)空的字符串,實(shí)際填寫(xiě)時(shí)需要根據(jù)對(duì)應(yīng)屬性數(shù)據(jù)類型進(jìn)行具體值的填充??梢钥吹?,這里對(duì)象屬性名采用的是變量庫(kù)里具體屬性的“字段名”,而非“標(biāo)題”, 實(shí)際使用時(shí)即可以使用“字段名”,也可以使用“標(biāo)題”,引擎都能正確識(shí)別。
了解輸入的JSON數(shù)據(jù)格式后,接下來(lái)就可以填充JSON數(shù)據(jù),填充完成后,點(diǎn)擊工具欄上的“提交數(shù)據(jù)”按鈕,即可將輸入的數(shù)據(jù)提交到目標(biāo)知識(shí)包所暴露的Restful服務(wù)接口。
在上圖的輸入數(shù)據(jù)當(dāng)中,“客戶”對(duì)象有個(gè)名為“cards”屬性,這個(gè)屬性是一個(gè)List類型,如果我們不為其填充集合類型的數(shù)據(jù),采用默認(rèn)的空字符串,那么提交后會(huì)產(chǎn)生如下圖所示的JSON解析錯(cuò)誤:
所以我們要么為“cards”屬性填充一個(gè)具體的集合類型的值,要么給一個(gè)空的集合,這里我們給的是一個(gè)空的集合,提交數(shù)據(jù)后結(jié)果如下圖所示:
可以看到,計(jì)算后的輸出數(shù)據(jù)是一個(gè)標(biāo)準(zhǔn)的JSON對(duì)象格式,“duration”屬性值表示當(dāng)前業(yè)務(wù)規(guī)則計(jì)算耗時(shí),單位為毫秒(ms),這里是0,表示時(shí)間非常的短(通常第一次計(jì)算時(shí)間較慢,這由Java特性導(dǎo)致);“output”屬性值為一個(gè)集合類型, 里面有兩個(gè)對(duì)象,是我們?cè)诜?wù)調(diào)用配置中定義的兩個(gè)輸出數(shù)據(jù)對(duì)象,分別是“貸款信息”和“參數(shù)”,“貸款信息”對(duì)象是一個(gè)我們定義在變量庫(kù)里的業(yè)務(wù)對(duì)象,而“參數(shù)”則是我們定義在參數(shù)庫(kù)里的固定對(duì)象。在“貸款信息”這個(gè)對(duì)象里,通過(guò)“name”屬性值來(lái) 標(biāo)明對(duì)象名稱,與變量庫(kù)里定義的對(duì)象分類名保持一致;“class”屬性則標(biāo)明對(duì)象類全名,與變量庫(kù)里定義的對(duì)象類路徑一致;“fields”屬性值是一個(gè)對(duì)象類型,用于標(biāo)明當(dāng)前對(duì)象的具體屬性名及其值,這里的屬性名采用的是屬性的字段名, 主要是方便后續(xù)JSON數(shù)據(jù)對(duì)象化處理。
上面的測(cè)試是通過(guò)URule內(nèi)置的Restful服務(wù)測(cè)試頁(yè)面完成,實(shí)際使用時(shí)也可以用第三方測(cè)試工具實(shí)現(xiàn),比如上面的Restful服務(wù)就可以通過(guò)postman來(lái)進(jìn)行測(cè)試,如下圖所示:
如截圖所示,在postman中,輸入好請(qǐng)求的URL,我們這里是“http://localhost:8081/urule-pro-test/urule/rest/我的項(xiàng)目/loantest”,提交類型改為POST(URule Pro提供的Restful服務(wù)只接收POST類型的請(qǐng)求, 所以這個(gè)URL無(wú)法直接用瀏覽器查看),輸入要提交的數(shù)據(jù),我們這里是要提交的JSON數(shù)據(jù),數(shù)據(jù)格式與上面介紹的保持一致,點(diǎn)擊“Send”按鈕,就可以得到響應(yīng)結(jié)果。
在配置Restful服務(wù)時(shí),還可以打開(kāi)“用戶名密碼驗(yàn)證”選項(xiàng),打開(kāi)該選項(xiàng)后,我們需要輸入用戶名及密碼信息,保存后再次請(qǐng)求這個(gè)Restful服務(wù)我們就需要在請(qǐng)求的Header里加上用戶和密碼信息,否則請(qǐng)求將不被允許,在URule Pro內(nèi)置的Restful服務(wù)測(cè)試頁(yè)面里, 如果當(dāng)前Restful服務(wù)需要用戶名密碼驗(yàn)證,它會(huì)自動(dòng)加上用戶名密碼信息;而如果我們使用postman來(lái)請(qǐng)求這個(gè)Restful服務(wù),若不在Header里提供用戶名密碼信息,那么請(qǐng)求將會(huì)得到如下圖所示信息:
我們可以在請(qǐng)求的Header中添加用戶名密碼信息,Header的Key分別是Username和Password,如下圖所示:
實(shí)際應(yīng)用當(dāng)中,我們會(huì)在應(yīng)用在外層加上業(yè)務(wù)系統(tǒng)的安全管理功能,比如使用系統(tǒng)需要先進(jìn)行登錄等,這時(shí)要保證URule Pro中內(nèi)置的Restful服務(wù)可用,那么就需要讓/urule/rest這個(gè)URL可匿名訪問(wèn),這點(diǎn)非常重要。
在使用這個(gè)內(nèi)置的Restful服務(wù)過(guò)程中,如果出現(xiàn)錯(cuò)誤,比如用戶名密碼不正確或規(guī)則計(jì)算過(guò)程出現(xiàn)異常等,類似這些錯(cuò)誤信息也會(huì)以一個(gè)標(biāo)準(zhǔn)的JSON格式返回,所有的錯(cuò)誤消息(如果是異常則是異常的堆棧信息)會(huì)放在返回的JSON對(duì)象的error屬性中,
如果沒(méi)有錯(cuò)誤,則返回的JSON中就不會(huì)包含error屬性,這點(diǎn)從上面的示例中我們也已經(jīng)看到。
在上面的示例當(dāng)中,輸入數(shù)據(jù)“客戶”對(duì)象里有個(gè)名為“cards”屬性,這個(gè)屬性是一個(gè)集合類型的屬性,所以如果該屬性為空時(shí)我們需要給該屬性添加一個(gè)[]字符,表示一個(gè)空的集合屬性,如下所示:
[
{
"name": "客戶",
"fields": {
"cards": [],
"company.id": "",
"gender": "",
"company.level": "",
"degree": "",
"name": "",
"company.name": "",
"salary": "",
"married": "",
"age": ""
}
},
{
"name": "貸款信息",
"fields": {
"result": "",
"money": "",
"id": ""
}
}
]
如果我們需要填充這個(gè)集合屬性,那么需要先看看變量庫(kù)里定義的“卡”對(duì)象以及與卡對(duì)象相關(guān)的對(duì)象的結(jié)構(gòu),然后仿照上面的JSON寫(xiě)出來(lái)就好;還有種簡(jiǎn)單的方式,那就是在“服務(wù)配置”窗口中直接勾選“卡”對(duì)象以及與卡對(duì)象相關(guān)的對(duì)象,如下圖所示:
保存后再次進(jìn)入頁(yè)面,就可以看到如下圖所示的輸入數(shù)據(jù)結(jié)構(gòu):
接下來(lái),我們需要填充“cards”屬性,填充好的結(jié)構(gòu)如下圖所示:
可以看到,填充后的“cards”屬性是一個(gè)集合類型,里面由若干個(gè)“卡”對(duì)象構(gòu)成,每個(gè)卡對(duì)象有四個(gè)屬性,其中“cardDetails”也是一個(gè)集合對(duì)象,這個(gè)集合對(duì)象是由若干個(gè)“卡明細(xì)”對(duì)象組成。按照這樣的規(guī)則, 我們?cè)跇?gòu)建輸入數(shù)據(jù)時(shí)就可以把輸入數(shù)據(jù)按照業(yè)務(wù)的需要構(gòu)建的足夠復(fù)雜,可最大限度滿足業(yè)務(wù)需求。
在上面的截圖中,“客戶”對(duì)象還有“company.id”以及“company.level”兩個(gè)屬性,從命名以及變量庫(kù)里對(duì)這兩個(gè)屬性的聲名可以看出,“客戶”這個(gè)對(duì)象下還有一個(gè)名為company的子對(duì)象,“company.id”和“company.level”兩個(gè)屬性 是用來(lái)填充company子對(duì)象的id以及l(fā)evel屬性,這里我們直接輸入這兩個(gè)屬性值即可實(shí)現(xiàn)對(duì)company子對(duì)象的id以及l(fā)evel兩個(gè)屬性值的填充。
實(shí)際使用時(shí),如果company對(duì)象在變量庫(kù)中也有定義,那么上面的寫(xiě)法可直接改為下面的樣子,依次類推:
{
"name": "客戶",
"fields": {
"cards": [],
"company":{
"name":"公司",
"fields":{
"id":"bstek",
"level":12
}
},
"degree": "",
"name": "",
"company.name": "bstek",
"salary": "",
"married": "",
"age": ""
}
}
上面的寫(xiě)法中,要求我們?cè)谧兞繋?kù)里必須定義好名為“公司”的對(duì)象,否則解析的時(shí)候產(chǎn)生錯(cuò)誤,如果沒(méi)有定義,那么需要采用“company.id”、“company.level”的定義方式。
通過(guò)Restful服務(wù)對(duì)外提供規(guī)則引擎計(jì)算服務(wù),很明顯這是一種典型的集中式計(jì)算模式,如果請(qǐng)求計(jì)算量過(guò)大,性能容易出現(xiàn)問(wèn)題,這時(shí)就需要我們來(lái)配置集群來(lái)解決這種問(wèn)題。
URule Pro中提供的Restful服務(wù)默認(rèn)就支持集群,在引擎內(nèi)部,為了不頻繁訪問(wèn)知識(shí)包中的配置的Restful服務(wù)信息,所以會(huì)把知識(shí)包的配置信息緩存下來(lái),如果我們沒(méi)有采用集群,那么默認(rèn)不需要做任何修改,如果采用集群,那么需要在屬性文件里 定義“urule.resourcePackageCheckCycle”屬性值,這些屬性值的含義是每隔多久去檢查一次知識(shí)包中配置的服務(wù)信息有沒(méi)有變化(單位是秒),它的默認(rèn)值為0,表示不檢查,每次修改知識(shí)包時(shí)會(huì)自動(dòng)刷新這個(gè)緩存,所以在沒(méi)有采用集群時(shí)不用做任何修改;但采用集群后, 因?yàn)橛卸鄠€(gè)集群節(jié)點(diǎn),所以知識(shí)包在修改保存時(shí)只能刷新一個(gè)節(jié)點(diǎn)的知識(shí)包緩存信息。通過(guò)修改“urule.resourcePackageCheckCycle”屬性值,可以決定在Restful服務(wù)調(diào)用時(shí)每隔多久檢查一次知識(shí)包配置有沒(méi)有變化,如果有則刷新。
比如,定義“urule.resourcePackageCheckCycle”屬性值為100,那么表示在Restful服務(wù)被調(diào)用時(shí)將每隔100秒檢查一次知識(shí)包有沒(méi)有更新,如果有則加載到緩存。
更多建議: