本文介绍: 假如有这么个需求网上购物需要根据不同规则计算商品折扣,比如VIP客户增加5%的折扣,购买金额超过1000元的增加10%的折扣等,而且这些规则可能随时发生变化,甚至增加新的规则。面对这个需求,你该怎么实现呢?难道是计算规则一变,就要修改业务代码,重新测试上线吗。其实我们可以通过规则引擎实现,Drools就是一个开源的业务规则引擎可以很容易地与springboot应用程序集成,那本文就用Drools来实现一下上面说的需求吧。前面类中指定drools规则的目录,现在我们目录添加

1 整合规则引擎Drools

1.1 前言

假如有这么个需求网上购物,需要根据不同的规则计算商品折扣,比如VIP客户增加5%的折扣,购买金额超过1000元的增加10%的折扣等,而且这些规则可能随时发生变化,甚至增加新的规则。面对这个需求,你该怎么实现呢?难道是计算规则一变,就要修改业务代码,重新测试上线吗。

其实我们可以通过规则引擎来实现Drools 就是一个开源的业务规则引擎,可以很容易地与 springboot 应用程序集成,那本文就用 Drools实现一下上面说的需求吧。

1.2 pom.xml

我们创建一个spring boot应用程序pom添加drools相关依赖如下

<dependency>
  &lt;groupId&gt;org.drools</groupId&gt;
  <artifactId&gt;drools-core</artifactId&gt;
  <version&gt;7.59.0.Final</version&gt;
</dependency&gt;
<dependency&gt;
  <groupId>org.drools</groupId>
  <artifactId>drools-compiler</artifactId>
  <version>7.59.0.Final</version>
</dependency>
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-decisiontables</artifactId>
  <version>7.59.0.Final</version>
</dependency>

1.3 Drools配置

创建一个名为 DroolsConfig 的配置 java 类。

@Configuration
public class DroolsConfig {
    // 制定规则文件路径
    private static final String RULES_CUSTOMER_RULES_DRL = "rules/customer-discount.drl";
    private static final KieServices kieServices = KieServices.Factory.get();

    @Bean
    public KieContainer kieContainer() {
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_CUSTOMER_RULES_DRL));
        KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
        kb.buildAll();
        KieModule kieModule = kb.getKieModule();
        KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
        return kieContainer;
    }
}

解析说明

1.4 示例Demo

1.4.1 添加业务Model

创建一个订单对象 OrderRequest这个类中字段后续回作为输入信息发送给定义的drools规则中,用来计算给定客户订单的折扣金额

@Data
public class OrderRequest {
    /**
     * 客户号
     */
    private String customerNumber;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 订单金额
     */
    private Integer amount;
    /**
     * 客户类型
     */
    private CustomerType customerType;
}

定义一个客户类型CustomerType枚举,规则引擎会根据该值计算客户订单折扣百分比如下所示

public enum CustomerType {
    LOYAL, NEW, DISSATISFIED;

    public String getValue() {
        return this.toString();
    }
}

最后,创建一个订单折扣类 OrderDiscount用来表示计算得到的最终的折扣,如下所示

@Data
public class OrderDiscount {

    /**
     * 折扣
     */
    private Integer discount = 0;
}

我们将使用上述响应对象返回计算出的折扣

1.4.2 定义drools 规则

前面DroolsConfig 类中指定 drools 规则的目录,现在我们/src/main/resources/rules 目录下添加customer-discount.drl 文件,在里面定义对应的规则。

完整的规则源码如下

import com.alvin.drools.model.OrderRequest;
import com.alvin.drools.model.CustomerType;
global com.alvin.drools.model.OrderDiscount orderDiscount;

dialect "mvel"

// 规则1: 根据年龄判断
rule "Age based discount"
    when
        // 当客户年龄在20岁以下或者50岁以上
        OrderRequest(age < 20 || age > 50)
    then
        // 则添加10%的折扣
        System.out.println("==========Adding 10% discount for Kids/ senior customer=============");
        orderDiscount.setDiscount(orderDiscount.getDiscount() + 10);
end

// 规则2: 根据客户类型的规则
rule "Customer type based discount - Loyal customer"
    when
        // 当客户类型是LOYAL
        OrderRequest(customerType.getValue == "LOYAL")
    then
        // 则增加5%的折扣
        System.out.println("==========Adding 5% discount for LOYAL customer=============");
        orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end

rule "Customer type based discount - others"
    when
    OrderRequest(customerType.getValue != "LOYAL")
then
    System.out.println("==========Adding 3% discount for NEW or DISSATISFIED customer=============");
    orderDiscount.setDiscount(orderDiscount.getDiscount() + 3);
end

rule "Amount based discount"
    when
        OrderRequest(amount > 1000L)
    then
        System.out.println("==========Adding 5% discount for amount more than 1000$=============");
    orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end

解析说明

1.4.3 添加Service

创建一个名为OrderDiscountService服务类,如下:。

@Service
public class OrderDiscountService {

    @Autowired
    private KieContainer kieContainer;

    public OrderDiscount getDiscount(OrderRequest orderRequest) {
        OrderDiscount orderDiscount = new OrderDiscount();
        // 开启会话
        KieSession kieSession = kieContainer.newKieSession();
        // 设置折扣对象
        kieSession.setGlobal("orderDiscount", orderDiscount);
        // 设置订单对象
        kieSession.insert(orderRequest);
        // 触发规则
        kieSession.fireAllRules();
        //或者  通过规则过滤器实现执行指定规则
		//kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("Age based discount"));
        // 中止会话
        kieSession.dispose();
        return orderDiscount;
    }
}

解析说明

1.4.4 添加Controller

创建一个名为OrderDiscountController 的Controller类,具体代码如下

@RestController
public class OrderDiscountController {

    @Autowired
    private OrderDiscountService orderDiscountService;

    @PostMapping("/get-discount")
    public ResponseEntity<OrderDiscount> getDiscount(@RequestBody OrderRequest orderRequest) {
        OrderDiscount discount = orderDiscountService.getDiscount(orderRequest);
        return new ResponseEntity<>(discount, HttpStatus.OK);
    }
}

1.4.5 测试

对于年龄 < 20 且金额 > 1000 的 LOYAL 客户类型,我们应该根据我们定义的规则获得 20% 的折扣。

入参{
    "customerNumber":"123456",
    "age":20,
    "amount":20000,
    "customerType":"LOYAL"
}
出参:
{
    "discount": 10
}

参考链接https://mp.weixin.qq.com/s/SfMhb34dj7DrLvMCKZv9Uw

1.5 drools规则解析

1.5.1 简介

在使用 Drools 时非常重要的一个工作就是编写规则文件,通常规则文件后缀.drldrlDrools Rule Language的缩写。在规则文件编写具体的规则内容
一套完整的规则文件内容构成如下

关键字 描述
package 包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用
import 用于导入或者静态方法
global 全局变量
function 自定义函数
query 查询
rule end 规则体

Drools支持的规则文件,除了drl形式,还有Excel文件类型的。

1.5.2 规则体语法结构

规则体是规则文件内容中的重要组成部分,是进行业务规则判断处理业务结果的部分
规则体语法结构如下:

rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end

解析说明

1.5.3 注释

drl形式的规则文件中使用注释和Java类中使用注释一致,分为单行注释和多行注释。
单行注释用//进行标记,多行注释以/开始,以/结束。如下示例

//规则rule1的注释,这是一个单行注释
rule "rule1"
    when
    then
        System.out.println("rule1触发");
end
​
/*
规则rule2的注释,
这是一个多行注释
*/
rule "rule2"
    when
    then
        System.out.println("rule2触发");
end

1.5.4 Pattern模式匹配

前面我们已经知道Drools 中的匹配器可以将 Rule Base 中的所有规则与Working Memory中的Fact对象进行模式匹配,那么我们就需要在规则体的LHS部分定义规则并进行模式匹配。LHS部分由一个或者多个条件组成,条件称为pattern

pattern的语法结构为:绑定变量名: Object(Field约束)

其中 绑定变量名可以省略,通常绑定变量名命名一般建议$ 开始。如果定义了绑定变量名,就可以在规则体的 RHS 部分使用此绑定变量名操作相应的Fact对象。Field约束部分是需要返回true或者false的0个或多个表达式

//所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        //Order为类型约束originalPrice为属性约束
        $order:Order(originalPrice < 200 &amp;&amp; originalPrice >= 100)
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200元的优惠20元");
end
//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 &amp;&amp; originalPrice >= 100)
    then
        System.out.println("$op=" + $op);
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200元的优惠20元");
end

LHS部分还可以定义多个pattern,多个pattern之间可以使用and或者or进行连接,也可以不写,默认连接为and

//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 &amp;&amp; originalPrice >= 100) and
        $customer:Customer(age > 20 &amp;&amp; gender=='male')
    then
        System.out.println("$op=" + $op);
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200元的优惠20元");
end

1.5.5 比较操作符

Drools提供的比较操作符有:>、<、>=、<=、==、!=、containsnot containsmemberOf 、not memberOf、matches 、not matches
前6个比较操作符和Java中的完全相同,下面我们重点学习后6个比较操作符

1.5.6 dialect 属性

drools 支持两种 dialectjava​​​ 和​​mvel​​

package 和 rule 都可以指定 dialect 属性.

mvel 是一种表达式语言, github主页为​ ​https://github.com/mvel/mvel​​​ , 文档主页为​ ​http://mvel.documentnode.com/​​
dools 中的 mvel dialect 可以认为是 java dialect 的超集, 也就是mvel dialect 模式下, 也支持 java dialect写法
mveljava 的主要区别

java dialect示例:

rule "java_rule"  
   enabled true
   dialect "java"
   when
       $order:Order()
   then
      System.out.println("java_rule fired");
      $order.setRealPrice($order.getOriginalPrice()*0.8) ;
end

mvel dialect示例:

rule "mvel_rule"
   enabled false
   dialect "mvel"
   when
       $order:Order()
   then
      System.out.println("mvel_rule fired");
      $order.realPrice=$order.originalPrice*0.7 ;   
end

原文地址:https://blog.csdn.net/u012060033/article/details/130598925

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_49481.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注