• Springboot整合规则引擎


    Springboot整合Drools 规则引擎

    1.添加maven 依赖坐标,并创建springboot项目

    <!-- drools规则引擎 -->
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>7.6.0.Final</version>
    </dependency>
    
    <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-api</artifactId>
        <version>7.6.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-core</artifactId>
        <version>7.6.0.Final</version>
    </dependency>
    
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-decisiontables</artifactId>
        <version>7.6.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-templates</artifactId>
        <version>7.6.0.Final</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.建立相应代码结构

    1,创建实体类
    @Data
    public class Person {
        private String names;
    
        private List<String> list;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.在resources文件夹下创建META-INF 文件夹 和rules规则文件夹

    META-INF下文件内容
    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
    
        <!--
            name:指定kbase的名称,可以任意,但是需要唯一
            packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
            default:指定当前kbase是否为默认 
    
        -->
        <kbase name="myKbase1" packages="rules" default="true">
            <!--
                name:指定ksession的名称,可以任意,但需要唯一
                default:指定当前session是否为默认
            -->
            <ksession name="ksession-rule" default="true"/>
        </kbase>
    </kmodule>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    Rules文件内容
    package people;
    import com.drools.demo.domain.Person
    import com.drools.demo.service.DemoService
    dialect "java"  #指定java语言
    global DemoService demoService #设置全局变量
    /**
     * 当前规则用于测试drools提供的操作运算符
        activation-group 同组只能又一个执行
        salience执行等级 salience 4 数值越大等级越高
     */
    
    // 测试比较操作符contains #规则名称 全局唯一
    rule "rule_comparison_contains"
        when
            Person(names contains "王小白")
        then
            demoService.test();
    
    end
    
    // 测试比较操作符contains
    rule "rule_comparison_not_contains"
        when
            Person(names not contains "王小白") and
            Person(list not contains names)
        then
            System.out.println("规则:rule_comparison_not_contains触发了...");
    end
    
    // 测试比较操作符memberOf
    rule "rule_comparison_memberOf"
        when
            Person(names memberOf list)
        then
            System.out.println("规则:rule_comparison_memberOf触发了...");
    
    end
    
    // 测试比较操作符not memberOf
    rule "rule_comparison_not_memberOf"
        when
            Person(names not memberOf list)
        then
            System.out.println("规则:rule_comparison_not_memberOf触发了...");
    end
    
    // 测试比较操作符matches
    rule "rule_comparison_matches"
        when
            Person(names matches "王.*") // 正则表达式
        then
            System.out.println("规则:rule_comparison_matches触发了...");
    end
    
    // 测试比较操作符not matches
    rule "rule_comparison_not_matches"
        when
            Person(names not matches "王.*") // 正则表达式
        then
            System.out.println("规则:rule_comparison_not_matches触发了...");
    
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    4.代码测试

    @RestController
    public class TestDemoController {
        @Resource
        private DemoService demoService;
        @GetMapping("one")
        public void test(){
            KieServices kieServices = KieServices.Factory.get();
            // 获取Kie容器对象(默认容器对象
            KieContainer kieContainer = kieServices.newKieClasspathContainer();
            // 从Kie容器对象中获取会话对象(默认session对象
            KieSession kieSession = kieContainer.newKieSession();
            kieSession.setGlobal("demoService",demoService);
            Person fact = new Person();
            String names = "王小白";
            fact.setNames(names);
            List<String> list = new ArrayList<String>();
            list.add("小黑");
            list.add("王小白");
            list.add(names);
            fact.setList(list);
            // 将order对象插入工作内存
            kieSession.insert(fact);
            // 匹配对象
            // 激活规则,由drools框架自动进行规则匹配。若匹配成功,则执行
            kieSession.fireAllRules();
            // 关闭会话
            kieSession.dispose();
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    Drools基础语法

    package:包名,package对应的不⼀定是真正的⽬录,可以任意写com.abc,同⼀个包下的drl⽂ 件可以相互访问
    import:⽤于导⼊类或者静态⽅法
    global:全局变量
    function:⾃定义函数
    query:查询
    rule end:规则体
    规则体语法结构
    ⼀个规则通常包括三个部分:属性部分(attribute) 、条件部分(LHS)和结果部分(RHS)
    rule “ruleName” //rule关键字,表示规则开始,参数为规则的唯⼀名称
    attributes //规则属性,是rule与when之间的参数,为可选项
    when //关键字,后⾯是规则的条件部分
    LHS //Left Hand Side,是规则的条件部分
    then //后⾯跟规则的结果部分
    RHS //是规则的结果或⾏为
    end

    条件部分

    LHS(Left Hand Side):是规则的条件部分的通⽤名称。它由零个或多个条件元素组成。如果LHS 为空,则它将被视为始终为true的条件元素。
    LHS部分由⼀个或者多个条件组成,条件⼜称为pattern。
    pattern的语法结构为:绑定变量名:Object(Field约束)

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

    //规则1:100元以下, 不加分
    rule “score_1”
    when
    //⼯作内存中必须存在Order这种类型的Fact对象-----类型约束
    //Fact对象的amout属性值必须⼩于等于100------属性约束
    $s : Order(amout <= 100)
    then
    $s.setScore(0);
    System.out.println("成功匹配到规则1:100元以下, 不加分 ");
    end

    如果 LHS 部分为空的话,那么引擎会⾃动添加⼀个 eval(true)的条件,由于该条件总是返回 true,所 以 LHS 为空的规则总是返回 true
    1.约束连接
    在 LHS 当中,可以包含 0~n 个条件,多个pattern之间可以采⽤“&&” (and) 、 “||”(or)和“,”(and) 来实现,也可以不写,默认连接为and
    //规则2:100元-500元 加100分
    rule “score_2”
    when
    $s : Order(amout > 100 && amout <= 500)
    then
    $s.setScore(100);
    System.out.println("成功匹配到规则2:100元-500元 加100分 ");
    end

    2.⽐较操作符
    在 Drools当中共提供了⼗⼆种类型的⽐较操作符, 分别是: >、 >=、 <、 <=、 = =、 !=、
    contains、 not contains、memberof、not memberof、matches、not matches;在这⼗⼆种类型的 ⽐较操作符当中,前六个是⽐较常⻅也是⽤的⽐较多的⽐较操作符

    示例:

    第⼀步:创建实体类,⽤于测试⽐较操作符
    package com.demo.entity; 
    import java.util.List; 
    public class Customer { 
    //客户姓名 
    private String name; 
    private List<Order> orderList;//订单集合 
    public String getName() { 
    return name; 
    } 
    public void setName(String name) { 
    this.name = name; 
    } 
    public List<Order> getOrderList() { 
    return orderList; 
    } 
    public void setOrderList(List<Order> orderList) { 
    this.orderList = orderList; 
    } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    第⼆步:在/resources/rules下创建规则⽂件customer-rules.drl

    package rules 
    import com.chenj.entity.*; 
    //测试contains规则 
    rule "rule1" 
    when 
    $order:Order(); 
    $customer:Customer(orderList contains $order); 
    then 
    System.out.println("测试contains规则触发:"+$customer.getName()); 
    end 
    //测试not contains规则 
    rule "rule2" 
    when 
    $order:Order(); 
    $customer:Customer(orderList not contains $order); 
    then 
    System.out.println("测试not contains规则触发:"+$customer.getName()); 
    end 
    //测试⽐较操作符matches 
    rule "rule3" 
    when 
    Customer(name matches "张.*") 
    then 
    System.out.println("测试⽐较操作符matches触发..."); 
    end 
    //测试⽐较操作符not matches 
    rule "rule4" 
    when 
    Customer(name not matches "张.*") 
    then 
    System.out.println("测试⽐较操作符not matches触发..."); 
    end 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    第三步:编写单元测试

    @Test 
    public void test2(){ 
    KieServices kieServices = KieServices.Factory.get(); 
    KieContainer kieContainer = 
    kieServices.getKieClasspathContainer(); 
    //会话对象,⽤于和规则引擎交互 
    KieSession kieSession = kieContainer.newKieSession(); 
    //构造订单对象,设置订单⾦额,由规则引擎计算获得的积分 
    Order order = new Order(); 
    //匹配规则:$order:Order(); 
    kieSession.insert(order); 
    Customer customer = new Customer(); 
    List<Order> orderList = new ArrayList<>(); 
    //匹配规则: $customer:Customer(orderList contains $order); 
    //orderList.add(order); 
    customer.setOrderList(orderList); 
    customer.setName("Jack"); 
    //将数据交给规则引擎,规则引擎会根据提供的数据进⾏规则匹配 
    kieSession.insert(customer); 
    //激活规则引擎,如果匹配成功则执⾏规则 
    kieSession.fireAllRules(); 
    //关闭会话 
    kieSession.dispose(); 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在 Drools 当中,在 RHS ⾥⾯,提供了⼀些对当前 Working Memory 实现快速操作的宏宏函数或对
    象, ⽐如 insert/insertLogical、 update 和 retract 就可以实现对当前 Working Memory中的 Fact
    对象进⾏新增、删除或者是修改
    1.insert
    函数insert的作⽤与我们在Java类当中调⽤StatefulKnowledgeSession对象的insert⽅法的作⽤相同,
    都是⽤来将⼀个 Fact 对象插⼊到当前的 Working Memory 当中
    需注意:⼀旦调⽤ insert 宏函数,那么 Drools 会重新与所有的规则再重新匹配⼀次, 对于没有设置
    no-loop 属性为 true 的规则,如果条件满⾜,不管其之前是否执⾏过都会再执⾏⼀次,这个特性不仅
    存在于 insert 宏函数上,后⾯介绍的 update、retract 宏函数同样具有该特性,所以在某些情况下因考
    虑不周调⽤ insert、update 或 retract 容易发⽣死循环

    //Drools提供的内置⽅法insert
    rule “rule5”
    when
    eval(true); //默认成⽴
    then
    Customer cus=new Customer();
    cus.setName(“张三”);
    insert(cus);
    System.out.println(“测试Drools提供的内置⽅法insert 触发…”);
    end
    rule “rule6”
    when
    c u s t o m e r : C u s t o m e r ( n a m e = = " 张三 " ) ; t h e n S y s t e m . o u t . p r i n t l n ( " 测试 D r o o l s 提供的内置⽅法 i n s e r t 触发 . . . " + customer:Customer(name =="张三"); then System.out.println("测试Drools提供的内置⽅法insert 触 发..."+ customer:Customer(name=="张三");thenSystem.out.println("测试Drools提供的内置insert触发..."+customer.getName());
    end

    测试:
    @Test
    public void test3(){
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieContainer =
    kieServices.getKieClasspathContainer();
    //会话对象,⽤于和规则引擎交互
    KieSession kieSession = kieContainer.newKieSession();
    //激活规则引擎,如果匹配成功则执⾏规则
    kieSession.fireAllRules();
    //关闭会话
    kieSession.dispose();
    }

    2.Update
    update函数意义与其名称⼀样, ⽤来实现对当前Working Memory当中的 Fact进⾏更新,⽤来告诉当 前的 Working Memory 该 Fact 对象已经发⽣了变化
    示例:
    rule “rule7”
    //no-loop true
    when
    $customer:Customer(name ==“李四”);
    then
    c u s t o m e r . s e t N a m e ( " 张三 " ) ; u p d a t e ( customer.setName("张三"); update( customer.setName("张三");update(customer);
    System.out.println(“测试Drools提供的内置⽅法update 触发…”);
    end
    rule “rule8”
    when
    c u s t o m e r : C u s t o m e r ( n a m e = = " 张三 " ) ; t h e n S y s t e m . o u t . p r i n t l n ( " 测试 D r o o l s 提供的内置⽅法 u p d a t e 触发 . . . " + customer:Customer(name =="张三"); then System.out.println("测试Drools提供的内置⽅法update 触 发..."+ customer:Customer(name=="张三");thenSystem.out.println("测试Drools提供的内置update触发..."+customer.getName());
    end

    测试
    @Test
    public void test3(){
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieContainer =
    kieServices.getKieClasspathContainer();
    //会话对象,⽤于和规则引擎交互
    KieSession kieSession = kieContainer.newKieSession();
    Customer customer = new Customer();
    customer.setName(“李四”);
    kieSession.insert(customer);
    //激活规则引擎,如果匹配成功则执⾏规则
    kieSession.fireAllRules();
    //关闭会话
    kieSession.dispose();
    }

    3.retract
    retract⽤来将 Working Memory 当中某个 Fact 对象从 Working Memory 当中删除
    //Drools提供的内置⽅法retract
    rule “rule9”
    when
    c u s t o m e r : C u s t o m e r ( n a m e = = " 李四 " ) ; t h e n / / r e t r a c t ( customer:Customer(name =="李四"); then //retract( customer:Customer(name=="李四");then//retract(customer);
    System.out.println(“测试Drools提供的内置⽅法retract 触发…”);
    end
    rule “rule10”
    when
    c u s t o m e r : C u s t o m e r ( ) ; t h e n S y s t e m . o u t . p r i n t l n ( " 测试 D r o o l s 提供的内置⽅法 r e t r a c t 触发 . . . " + customer:Customer(); then System.out.println("测试Drools提供的内置⽅法retract 触 发..."+ customer:Customer();thenSystem.out.println("测试Drools提供的内置retract触发..."+customer.getName());
    end

    测试
    @Test
    public void test3(){
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieContainer =
    kieServices.getKieClasspathContainer();
    //会话对象,⽤于和规则引擎交互
    KieSession kieSession = kieContainer.newKieSession();
    Customer customer = new Customer();
    customer.setName(“李四”);
    kieSession.insert(customer);
    //激活规则引擎,如果匹配成功则执⾏规则
    kieSession.fireAllRules();
    //通过规则过滤器实现只执⾏指定规则
    //kieSession.fireAllRules(new
    RuleNameEqualsAgendaFilter(“rule5”));
    //关闭会话
    kieSession.dispose();
    }

    属性部分
    Drools中提供的属性如下表:
    在这里插入图片描述

  • 相关阅读:
    树莓派交叉编译之带有wiringpi库的交叉编译,以及软硬链接的建立(面试)
    【Spark NLP】第 17 章:支持多种语言
    Spring原理:PostProcessor与AOP原理
    到底什么是“星闪”?
    JAVA--AI编程助手【代码智能补全工具】盘点,让AI提高你的编程效率
    一笑的大型连续剧之第一集
    阿里SpringCloudAlibaba实战小抄(第五版)GitHub独家首发开源
    leetcode 刷题 log day 48(打家劫舍问题
    【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计
    Springboot+Websocket+JWT实现的即时通讯模块
  • 原文地址:https://blog.csdn.net/qq_43049310/article/details/132898753