天天看点

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,也能实现解耦,技术不复杂,思路和解决方案更重要,希望对路过的朋友有所帮助。