最近作財務相關的積分規則,因爲這個功能之後涉及到方方面面,因此想盡量作的可維護,可擴展,平臺其餘人調用起來更加方便,聯想到財務相關的功能會更多的規則配置,在這裏打算用drools規則引擎來實現。
規則引擎提及來比較簡單,當你的功能有不少未知條件須要判斷或須要遵循不少業務規則時,就能夠採用。
首先看看規則文件大大體樣子,
java
rule "testDrools" when ...各類條件 then ...執行業務 end
看起來比較像if else,可是切忌,咱們應該用一個業務人員的視角而不是一個程序員的視角來看規則文件,不然你會進入不少誤區。
當多個工做對象進入規則引擎時,它能夠根據多個條件同時判斷,而且執行不一樣的業務代碼。
下面有個場景,看看如何把規則引擎應用其中。
假如如今有兩組數據對象,分別是現金流數據和帳戶數據,咱們須要根據某個帳戶在某段時間內的現金流動情況來給帳戶計算餘額。
首先新建現金流對象,帳戶對象,時間查詢對象,分別以下(省去getter setter)程序員
public class CashFlow { private Date date; private double amount; private String type; private long accountNo; } public class Account { private long accountNo; private double blance; } public class AccountPeriod { private Date start; private Date end; }
咱們的目的是根據傳入的AccountPeriod對象和一系列CashFlow,Account對象來自動計算出每一個Account對象的blance。
規則文件應該以下編寫:session
package org.drools.examples.cashflow import org.drools.myTest.cashflow.Account; import org.drools.myTest.cashflow.AccountPeriod; import org.drools.myTest.cashflow.CashFlow; rule "CREDIT" when $ap:AccountPeriod() $acc:Account($accountNo:accountNo) CashFlow(type=="CREDIT",accountNo==$accountNo,date>=$ap.start && <=$ap.end,$amount:amount) then $acc.setBlance($acc.getBlance()+$amount); System.out.println("借入"); end rule "DEBITS" when $ap:AccountPeriod() $acc:Account($accountNo:accountNo) CashFlow(type=="DEBIT",accountNo==$accountNo,date>=$ap.start && <=$ap.end,$amount:amount) then $acc.setBlance($acc.getBlance()-$amount); System.out.println("借出"); end
drl規則文件引入包的語句和java相似,重點在下面。
首先建立規則,名爲「CREDIT」,when裏面是條件,冒號是賦值,以便下文使用,"==" ">=" "<="等符號的使用都和java相似。因此這個條件的意思是:
當傳入的對象裏面有AccountPeriod(並賦值到$ap),而且存在帳戶信息(並把accountNo賦值到$accountNo),而且存在現金流信息(並符合各屬性的值的匹配),那麼執行餘額的增長。
規則DEBITS的邏輯差很少。
編寫引擎的編譯及部署代碼,以下函數
// KnowledgeBuilder用來在業務代碼中收集已經編寫好的規則,而後對這些規則文件進行編譯,最終產生 // 一批編譯好的規則包(KnowledgePackage)給其餘的應用程序使用 final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory .newKnowledgeBuilder(); // 解析而且編譯規則文件 kbuilder.add(ResourceFactory.newClassPathResource("cashflow.drl", CashFlowTestMain.class), ResourceType.DRL); // 打出錯誤 if (kbuilder.hasErrors()) { System.out.println(kbuilder.getErrors().toString()); throw new RuntimeException("Unable to compile \"cashflow.drl\"."); } // 獲得編譯後的包 final Collection<KnowledgePackage> pkgs = kbuilder .getKnowledgePackages(); // 部署到一個知識庫 // KnowledgeBase是用來收集應用當中知識定義的知識庫對象,在一個KnowledgeBase當中,能夠包含普通的規則(rule) // 規則流(rule flow),函數定義(function),用戶自定義對象(type model), final KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(pkgs);
規則引擎至關於一個容器,咱們須要經過一個管道跟這個容器連起來,這個管道就是會話,新建一個有狀態的會話:測試
//開啓有狀態會話 final StatefulKnowledgeSession ksession = kbase .newStatefulKnowledgeSession();
ksession 對象的insert方法能夠把對象放入工做區(容器),讓規則引擎來處理。下面新建幾條測試數據:ui
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); /** ******************第一條記錄************************* */ CashFlow cf0 = new CashFlow(); String time0 = "2010-01-12"; cf0.setDate(sdf.parse(time0)); cf0.setAmount(100); cf0.setType("CREDIT"); cf0.setAccountNo(1); ksession.insert(cf0); CashFlow cf1 = new CashFlow(); String time1 = "2010-02-02"; cf1.setDate(sdf.parse(time1)); cf1.setAmount(200); cf1.setType("DEBIT"); cf1.setAccountNo(1); ksession.insert(cf1); CashFlow cf2 = new CashFlow(); String time2 = "2010-05-18"; cf2.setDate(sdf.parse(time2)); cf2.setAmount(50); cf2.setType("CREDIT"); cf2.setAccountNo(1); ksession.insert(cf2); CashFlow cf3 = new CashFlow(); String time3 = "2010-03-18"; cf3.setDate(sdf.parse(time3)); cf3.setAmount(75); cf3.setType("CREDIT"); cf3.setAccountNo(1); ksession.insert(cf3); Account acc = new Account(); acc.setAccountNo(1); acc.setBlance(0); ksession.insert(acc); /** ******************第二條記錄************************* */ CashFlow cf0_else = new CashFlow(); String time0_else = "2010-01-12"; cf0_else.setDate(sdf.parse(time0_else)); cf0_else.setAmount(150); cf0_else.setType("CREDIT"); cf0_else.setAccountNo(2); ksession.insert(cf0_else); CashFlow cf1_else = new CashFlow(); String time1_else = "2010-02-02"; cf1_else.setDate(sdf.parse(time1_else)); cf1_else.setAmount(500); cf1_else.setType("DEBIT"); cf1_else.setAccountNo(2); ksession.insert(cf1_else); CashFlow cf2_else = new CashFlow(); String time2_else = "2010-05-18"; cf2_else.setDate(sdf.parse(time2_else)); cf2_else.setAmount(50); cf2_else.setType("CREDIT"); cf2_else.setAccountNo(2); ksession.insert(cf2_else); CashFlow cf3_else = new CashFlow(); String time3_else = "2010-03-18"; cf3_else.setDate(sdf.parse(time3_else)); cf3_else.setAmount(75); cf3_else.setType("CREDIT"); cf3_else.setAccountNo(2); ksession.insert(cf3_else); Account acc_else = new Account(); acc_else.setAccountNo(2); acc_else.setBlance(0); ksession.insert(acc_else); /* 查詢條件 */ AccountPeriod ap = new AccountPeriod(); String start = "2009-05-06"; String end = "2012-02-25"; ap.setStart(sdf.parse(start)); ap.setEnd(sdf.parse(end)); ksession.insert(ap); // 觸發全部規則執行 ksession.fireAllRules(); // 必定要釋放 ksession.dispose();
至此,規則已所有啓動,爲了測試,打印這兩個帳戶的餘額信息:code
System.out.println(acc.getAccountNo() + " : " + acc.getBlance()); System.out.println(acc_else.getAccountNo() + " : " + acc_else.getBlance());
借出 借入 借入 借入 借出 借入 借入 借入 1 : 25.0 2 : -225.0
By 阿飛哥 轉載請說明
orm