天天看點

Drools:不逗你,直接上幹貨,實戰分享:動态規則模闆

今天放福利幹貨, 由于接觸到了遇到了很多關于比對條件判斷的業務場景和需求,很多人可能不假思索的就直接幹if-else,可能對代碼有點追求的上了層次幹政策模式,噼噼啪啪絞盡腦汁設計了一啪優雅牛逼的代碼接口和實作,其實做過風控系統的同學們應該對規則引擎都不陌生,可以執行百度,規則引擎有好多,傳統的我曾經用過的和感覺最容易上手的當屬drools了,今天就幹他,分享一下

Drools:不逗你,直接上幹貨,實戰分享:動态規則模闆

直接開幹

普通規則寫法

先來常常鮮,堆疊式的規則寫法,将所有的判斷條件全部寫一個規則,重複累贅

package rules;
import com.example.drools.Fd.domain.TradeRecord
import java.math.BigDecimal
import org.slf4j.LoggerFactory
global  org.slf4j.Logger logger

rule "Between3And12"
    when
      trd:TradeRecord(getFqNum() >=3 && getFqNum() < 12)
    then
      trd.setFee(new BigDecimal("0.05").multiply(trd.getAmount()));
      logger = LoggerFactory.getLogger("Drools-Between3And12");
      logger.info("命中費率規則 :12期以上24期以内");
end

rule "Between12And24"
    when
      trd:TradeRecord(getFqNum() >= 12 && getFqNum() < 24)
    then
      trd.setFee(new BigDecimal("0.25").multiply(trd.getAmount()));
      logger = LoggerFactory.getLogger("Drools-Between12And24");
      logger.info("命中費率規則 :12期以上24期以内");
end
           

今天來個進階的,首先編寫一段規則模闆,對我又在用模闆方式

Drools:不逗你,直接上幹貨,實戰分享:動态規則模闆

模闆腳本:

這是一個根據交易分期數來比對對應的期數費率區間,其實延伸開來,例如價格區間優化折扣、等這種帶區間的需求都可以這樣去實作,動态,易于維護,邏輯簡單清晰易懂

package rules;
dialect "java"
import java.math.BigDecimal
import  com.example.drools.Fd.domain.TradeRecord
import org.slf4j.LoggerFactory
global  com.example.drools.Fd.domain.Fenqi fqs
global org.slf4j.Logger logger

rule "BetweenMinAndMax"
    when
      trd:TradeRecord(getFqNum() >= fqs.getMin() && getFqNum() < fqs.getMax())
    then
      trd.setFee(new BigDecimal(fqs.getRadio()).multiply(trd.getAmount()));
      logger = LoggerFactory.getLogger("Drools-BetweenMinAndMax");
      logger.info("命中費率規則 : {} 期以上(包含),{} 期以内",fqs.getMin(),fqs.getMax());
end           

規則擷取參數

  • 可以使用global關鍵字将java參數定義成一個全局變量參數,在整個規則中都能使用到
  • 使用 session.setGlobal("fqs",fenqishu) 傳遞全局參數
  • 傳參,使用session.insert(tradeRecord),規則中就像java代碼一樣絲滑

java執行代碼:

簡單模拟

  • 一筆交易事實,100元的交易分了6期
  • 3期到12期之間執行的費率是0.25%
  • 命中規則,并之間計算分期費用,規則結果傳回費用結果
public void getOutRuleFiles() throws IOException {
        KieServices kieServices = KieServices.Factory.get();
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        File[] ruleFiles = Paths.get("d://temp/rules//").toFile().listFiles();
        for (File file : ruleFiles) {
            kieFileSystem.write(ResourceFactory.newFileResource(file));
        }
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
        KieContainer kContainer = kieServices.newKieContainer(kieBuilder.getKieModule().getReleaseId());
        KieBase kieBase = kContainer.getKieBase();
        KieSession session = kieBase.newKieSession();
        //交易事實
        TradeRecord tradeRecord = new TradeRecord();
                    tradeRecord.setAmount(new BigDecimal(100));
                    tradeRecord.setFqNum(6);
                    tradeRecord.setMerchantName("删古");
        session.insert(tradeRecord);
       //條件事實
        Fenqi fenqishu = new Fenqi();
                fenqishu.setMax(12);
                fenqishu.setMin(3);
                fenqishu.setRadio(0.25);
        session.setGlobal("fqs",fenqishu);
        session.fireAllRules();
        session.dispose();
        System.out.println("命中規則計費結果:"+tradeRecord.getFee());
    }           

工程結構:spring-boot

pom依賴

Drools:不逗你,直接上幹貨,實戰分享:動态規則模闆

總結

其實drools不是什麼新技術,很老的東西了,但是網上很多用法是直接将規則寫到工程本身的/main/resources/目錄下,試想一下,如果這樣就不太友善了,如果規則随時需要變動,那不是要重新打包嗎,是以結合實踐,把規則拿出來放在指定外部目錄中是非常有必要的,就幾行代碼就能解決多少if判斷,将規則做成API,也能實作解耦,技術不複雜,思路和解決方案更重要,希望對路過的朋友有所幫助。