likes
comments
collection
share

Drools规则动态化具体实践

作者站长头像
站长
· 阅读数 13

本文正在参加「金石计划」

业务背景

某商城平台,目前有上百家的门店,五月1号平台需要搞满减促销活动,但是每家门店的促销规则又有区别,虽然可以通过Drools规则引擎能够解决相关决策问题,但是我们不可能为每一个门店去创建一个规则文件,这种实现显然是不合理的,那么将如何实现呢?

解决方案

针对上述的需求,我们需要设计一张规则表,由每个门店根据业务情况创建不同促销规则,然后通过规则模板生成具体的规则文件。

具体实现

设计业务规则表

  Drools规则动态化具体实践

定义规则模板

新增规则模板文件orderdiscounttemplate.drt,具体内容如下:

template header

min

max

costMoney

package com.skywares.fw.drools;

import com.skywares.fw.drools.pojo.Order;

template "discount"

rule "calculate rule_@{row.rowNumber}"
no-loop true
when
    $order: Order(totalMoney>@{min} && totalMoney<=@{max})
then
    $order.setPayMoney($order.getTotalMoney()-@{costMoney});
    System.out.println("订单金额大于@{min}小于等于@{max}优惠");
    update($order);
end

end template

说明:实际业务模板中比这个复杂,有一定校验及业务逻辑,此处做了简化。

  • template header 定义模板开始
  • end template 定义模板结束,
  • min、max、costMoney 申明变量
  • 而row.rowNumber是drools模板默认的变量。

业务实现

public Order getOrderPayMoney(Double totalMoney,String storeCode)
    {
        String drlContent ="";
        try
        {
            ObjectDataCompiler converter = new ObjectDataCompiler();
           InputStream ins=  ResourceFactory.newClassPathResource("config/orderdiscounttemplate.drt", this.getClass()).getInputStream();
           Collection<RuleConfig> ruleConfigList =getRuleConfigist(storeCode);
           drlContent=converter.compile(ruleConfigList, ins);
           logger.info("规则模板文件内容:{}",drlContent);
        }
        catch (IOException e)
        {
            logger.error("compile rule error:",e);
        }
        
        //采用drools工具类
        KieHelper helper = new KieHelper();
        helper.addContent(drlContent, ResourceType.DRL);
        KieSession kieSession = helper.build().newKieSession();
        Order order = new Order();
        order.setTotalMoney(totalMoney);
        kieSession.insert(order);
        int allRules  =kieSession.fireAllRules();
        logger.info("成功执行{}条规则",allRules);
        kieSession.dispose();
        return order;
    }

说明:getRuleConfigist(storeCode) 此方法就是通过门店code从数据库中获取动态业务规则,都是数据库的基本查询操作,本文就不再详细讲述。

动态生成的规则文件的内容

import com.skywares.fw.drools.pojo.Order;

rule "calculate rule_6"
no-loop true
when
    $order: Order(totalMoney>5000 && totalMoney<=10000)
then
    $order.setPayMoney($order.getTotalMoney()-1000);
    System.out.println("订单金额大于5000小于等于10000无优惠");
    update($order);
end

rule "calculate rule_5"
no-loop true
when
    $order: Order(totalMoney>3000 && totalMoney<=5000)
then
    $order.setPayMoney($order.getTotalMoney()-300);
    System.out.println("订单金额大于3000小于等于5000无优惠");
    update($order);
end

rule "calculate rule_4"
no-loop true
when
    $order: Order(totalMoney>1000 && totalMoney<=3000)
then
    $order.setPayMoney($order.getTotalMoney()-100);
    System.out.println("订单金额大于1000小于等于3000无优惠");
    update($order);
end

rule "calculate rule_3"
no-loop true
when
    $order: Order(totalMoney>500 && totalMoney<=1000)
then
    $order.setPayMoney($order.getTotalMoney()-50);
    System.out.println("订单金额大于500小于等于1000无优惠");
    update($order);
end

rule "calculate rule_2"
no-loop true
when
    $order: Order(totalMoney>200 && totalMoney<=500)
then
    $order.setPayMoney($order.getTotalMoney()-30);
    System.out.println("订单金额大于200小于等于500无优惠");
    update($order);
end

rule "calculate rule_1"
no-loop true
when
    $order: Order(totalMoney>100 && totalMoney<=200)
then
    $order.setPayMoney($order.getTotalMoney()-10);
    System.out.println("订单金额大于100小于等于200无优惠");
    update($order);
end

rule "calculate rule_0"
no-loop true
when
    $order: Order(totalMoney>0 && totalMoney<=100)
then
    $order.setPayMoney($order.getTotalMoney()-0);
    System.out.println("订单金额大于0小于等于100无优惠");
    update($order);
end

相关测试

@RequestMapping("getPayMoney")
    public Order getPayMoney(@RequestParam Double totalMoney,@RequestParam String  storeCode)
    {
        Order order= orderService.getOrderPayMoney(totalMoney,storeCode);
        return order;
    }

执行结果

2023-03-30 14:39:15.611  INFO 28496 --- [nio-9090-exec-1] o.d.c.k.builder.impl.KieRepositoryImpl   : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0-SNAPSHOT]
订单金额大于5000小于等于10000无优惠
2023-03-30 14:39:15.672  INFO 28496 --- [nio-9090-exec-1] c.s.fw.drools.service.OrderServiceImpl   : 成功执行1条规则

相关扩展

业务动态添加规则

通过规则文件表的定义,设计相关的界面化操作,那么业务人员能够对业务规则进行新增、删除操作,从而实现业务规则动态化操作。

加载远程模板文件

一般的规则模板文件需要跟业务工程进行分离,所以需要远程的加载模板文件,具体实现如下:

 try
        {
            ObjectDataCompiler converter = new ObjectDataCompiler();
       InputStream ins=ResourceFactory.newUrlResource("http://localhost:8080/orderdiscounttemplate.drt").getInputStream();
           Collection<RuleConfig> ruleConfigList =getRuleConfigist();
           drlContent=converter.compile(ruleConfigList, ins);
           logger.info("规则模板文件内容:{}",drlContent);
        }
        catch (IOException e)
        {
            logger.error("compile rule error:",e);
        }

说明:ResourceFactory.newUrlResource动态加载规则模板文件。

总结

本文通过Drools规则引擎来实现具体的业务功能,如有疑问请随时反馈。关于Drools的可视化操作,将在后续的文章中进行详细讲解。