Drools规则动态化具体实践
业务背景
某商城平台,目前有上百家的门店,五月1号平台需要搞满减促销活动,但是每家门店的促销规则又有区别,虽然可以通过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的可视化操作,将在后续的文章中进行详细讲解。
转载自:https://juejin.cn/post/7216209996526600253