探索Drools:史上最全面的使用指南

Drools概述

什么是规则引擎

规则引擎,全称为业务规则管理系统,英文名为BRMS(即Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模板编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。

需要注意的的规则引擎并不是一个具体的技术框架,而是指的一类系统,即业务规则管理系统。目前市面上具体的规则引擎产品有:drools、VisualRules、iLog等。

规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出平台。

使用规则引擎的优势

  1. 业务规则与系统代码分离,实现业务规则的集中管理
  2. 在不重启服务的情况下可随时对业务规则进行扩展和维护
  3. 可以动态修改业务规则,从而快速响应需求变更
  4. 规则引擎是相对独立的,只关心业务规则,使得业务分析人员参与编辑、维护系统的业务规则
  5. 减少了硬编码业务规则的成本和风险
  6. 使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得简单

规则引擎应用场景

对于业务规则会频繁变动的系统比较适合使用规则引擎,例如:

  1. 风险控制系统-风险评估、风险贷款
  2. 征信验证
  3. 促销平台系统-满减、打折等

Drools介绍

drools是一款由JBoss组织提供的基于java语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(如存放在数据库中),使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效。

drools官网:Drools - Drools - Business Rules Management System (Java™, Open Source)

drools中文网:Drools中文网 | 基于java的功能强大的开源规则引擎

drools源码下载地址:GitHub - kiegroup/drools: This repository is a fork of apache/incubator-kie-drools. Please use upstream repository for development.

Drools入门案例

电商平台促销积分活动

活动规则是根据用户购买订单的金额给用户送相应的积分,购买的越多送的越多,用户可以使用积分来兑换相应的商品。

用户购买的金额和对应赠送积分规则如下:

序号

赠送积分

规则

1

0

100元以下的商品

2

100

100元-500元的商品

3

500

500元-1000元的商品

4

1000

1000以上的商品

传统实现代码(伪代码)
@Test
public void scoreTest(){
    int money = 666;
    int score = 0;
    //100元-500元的商品积100
    if(money >= 100 && money <500){
        score = 100;
    }
    //500元-1000元的商品积500
    if(money >= 500 && money <1000){
        score = 500;
    }
    //1000以上的商品积1000
    if(money >= 1000 ){
        score = 100;
    }
    System.out.println(score);
}
Drools实现代码

第一步:创建Maven工程并导入drools相关Maven依赖

<!-- drools规则引擎 -->
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-compiler</artifactId>
  <version>7.10.0.Final</version>
</dependency>

第二步:根据drools要求在指定路径创建/resources/META-INF/kmodule.xml配置文件

<?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>

第三步:创建实体类Order

package com.qz.entity;

import lombok.Data;

@Data
public class Order {

    //订单金额
    private int money;

    //积分
    private int score;

}

第四步:创建规则文件/resources/rules/score-rules.drl文件

package rules;
import com.qz.entity.Order;


//100元以下,不加分
rule "score_1"
    when
        $order:Order(money < 100);
    then
        $order.setScore(0);
        System.out.println("触发规则:100元以下,不加分");
end

//100-500,积100分
rule "score_2"
    when
        $order:Order(money >= 100 && money <500);
    then
        $order.setScore(100);
        System.out.println("触发规则:100-500,积100分");
end

//500-1000,积500分
rule "score_3"
    when
        $order:Order(money >= 500 && money <1000);
    then
        $order.setScore(500);
        System.out.println("触发规则:500-1000,积500分");
end

//1000以上,积1000分
rule "score_4"
    when
        $order:Order(money >= 1000);
    then
        $order.setScore(1000);
        System.out.println("触发规则:1000以上,积1000分");
end

drools API开发步骤如下:

第五步:编写单元测试

@Test
public void scoreTest(){
    KieServices kieServices = KieServices.Factory.get();
    //获取Kie容器
    KieContainer kieContainer = kieServices.newKieClasspathContainer();
    //获取Kie的会话session,通过session和规则引擎交互
    KieSession kieSession = kieContainer.newKieSession();

    //事实对象
    Order order = new Order();
    order.setMoney(1111);

    kieSession.insert(order);
    //激活执行规则,drools会自动去匹配
    /*kieSession.fireAllRules();*/
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            if(match.getRule().getName().contains("score_")){
                return true;
            }
            return false;
        }
    });

    //关闭
    kieSession.dispose();
    System.out.println("积分:"+order.getScore());
}

控制台结果:

通过上面的入门案例我们可以发现,使用Drools规则引擎主要工作就是编写规则文件,在规则文件中定义跟业务相关的业务规则,例如案例定义的就是购物积分规则。规则定义好后就需要调用Drools提供的API将数据提供给规则引擎进行规则模式匹配,规则引擎会执行匹配成功的规则并将计算的结果返回给我们。

使用规则引擎时业务规则可以做到动态管理。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计等。这样就可以做到在不重启服务的情况下调整业务规则。

Drools基础语法

规则文件构成

在使用Drools时非常重要的一个工作就是编写规则文件,通常规则文件的后缀为.drl

drl是Drools Rule Language的缩写,在规则文件中编写具体的规则内容

规则文件内容构成如下:

关键字

描述

package

包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用

import

用于导入类或者静态方法

global

全局变量

function

自定义函数

query

查询

rule end

规则体

规则提语法构成

规则体是规则文件内容中的重要组成部分,是进行业务规则判断、处理业务结果的部分

规则体语法结构如下:

rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end

rule:关键字,表示规则开始,参数为规则的唯一名称

attributes:规则属性,是rule与when之间的参数,为可选性

when:关键字,后面跟规则的条件部分

LHS:是规则的条件部分的通用名称。它由零个或多个条件元素组成。如果LHS为空,则它将被视为始终为true的 条件元素

RHS:是规则的后果或行动部分的他通用名称

注释

在drl形式的规则文件中使用注释和Java类中使用注释一致,分为单行注释和多行注释

单行注释用“//”进行标记,多行注释用“/*”开始,“*/”结束

//单行注释
/*
   多行注释
*/
rule "test"
    when
    then
        System.out.println("测试注释");
end

Pattern模式匹配

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

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

rule "score_2"
    when
        $order:Order(money >= 100 && money <500);
    then
        $order.setScore(100);
        System.out.println("触发规则:100-500,积100分");
end

以上条件必须同时满足当前规则才有可能被激活

比较操作符

Drools提供了十二种比较操作符,其中前六种是比较常用的

符号

说明

1

>

大于

2

<

小于

3

>=

大于等于

4

<=

小于等于

5

==

等于

6

!=

不等于

7

contains

检查⼀个Fact对象的某个属性值是否包含⼀个指定的对象值

8

not contains

检查⼀个Fact对象的某个属性值是否不包含⼀个指定的对象值

9

memberOf

判断⼀个Fact对象的某个属性是否在⼀个或多个集合中,如果是字符串判断的标准就变为:该字符串是否包含Fact对象的字段内容了。当然这个过程并不会神奇的转换成数组什么的,仅仅类似于Java中String提供的contains方法的比较

10

not memberOf

判断⼀个Fact对象的某个属性是否不在⼀个或多个集合中

11

matches

判断⼀个Fact对象的属性是否与提供的标准的Java正则表达式进⾏匹配

12

not matches

判断⼀个Fact对象的属性是否不与提供的标准的Java正则表达式进⾏匹配

contains操作符:

@Test
public void contains() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("测试");
    kieSession.insert(customer);
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            String type = "comparison_operator_contains";
            if(match.getRule().getName().contains(type)){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}
rule "comparison_operator_contains"
    when
        Customer(name contains "测试") or
        Customer(orderList contains name)
    then
     System.out.println("触发规则:Customer中包含测试");
end

not contains操作符:

@Test
public void notContains() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("测试");
    kieSession.insert(customer);
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            String type = "comparison_operator_not_contains";
            if(match.getRule().getName().contains(type)){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}
rule "comparison_operator_not_contains"
    when
         $customer:Customer($customer.getName() not contains "测试")
    then
     System.out.println("触发规则:Customer中不包含测试");
end

memberOf操作符:

@Test
public void memberOf() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("测试");
    List<String> list = new ArrayList<>();
    list.add("测试");
    customer.setOrderList(list);
    kieSession.insert(customer);
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            String type = "comparison_operator_member_of";
            if(match.getRule().getName().contains(type)){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}
rule "comparison_operator_member_of"
    when
        Customer(name memberOf orderList)
    then
        System.out.println("触发规则:comparison_operator_member_of");
end

not memberOf操作符:

@Test
public void notMemberOf() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("测试");
    List<String> list = new ArrayList<>();
    customer.setOrderList(list);
    kieSession.insert(customer);
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            String type = "comparison_operator_not_member_of";
            if(match.getRule().getName().contains(type)){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}
rule "comparison_operator_not_member_of"
    when
        Customer(name not memberOf orderList)
    then
        System.out.println("触发规则:comparison_operator_not_member_of");
end

matches操作符:

@Test
public void matches() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("测试");
    kieSession.insert(customer);
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            if(match.getRule().getName().contains("comparison_operator_matches")){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}
rule "comparison_operator_matches"
    when
        $customer:Customer(name matches "测.*")
    then
        System.out.println("触发规则:匹配到测开头的客户;"+$customer.getName());
end

not matches操作符:

@Test
public void motMatches() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("张三");
    kieSession.insert(customer);
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            if(match.getRule().getName().contains("comparison_operator_not_matches")){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}
rule "comparison_operator_not_matches"
    when
        $customer:Customer(name not matches "测.*")
    then
        System.out.println("触发规则:匹配到不是测开头的客户;"+$customer.getName());
end

执行指定规则

Drools还提供了多种方法来实现指定规则运行

  1. 重写AgendaFilter拦截,可以在内部通过代码实现指定规则运行,返回true代表运行,false代表不允许
@Test
public void specifyRule() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("张三");
    kieSession.insert(customer);
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            if(match.getRule().getName().contains("comparison_operator_not_matches")){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}

  1. 通过RuleNameEndsWithAgendaFilter方法实现指定以某个字符串结尾的规则
@Test
public void specifyRule() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("张三");
    kieSession.insert(customer);
    kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("matches"));
    //关闭
    kieSession.dispose();
}
rule "comparison_operator_matches"
    when
        //$customer:Customer(name matches "测.*")
    then
        System.out.println("触发规则:匹配到测开头的客户;");
end

rule "comparison_operator_not_matches"
    when
        //$customer:Customer(name not matches "测.*")
    then
        System.out.println("触发规则:匹配到不是测开头的客户;");
end

  1. 通过RuleNameEqualsAgendaFilter指定某个规则运行
@Test
public void specifyRule() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("张三");
    kieSession.insert(customer);
    kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("comparison_operator_not_matches"));
    //关闭
    kieSession.dispose();
}

  1. 通过RuleNameStartsWithAgendaFilter指定某个字符串开头的规则
@Test
public void specifyRule() {
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("测试");
    kieSession.insert(customer);
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("comparison_operator_"));
    //关闭
    kieSession.dispose();
}

  1. 通过RuleNameSerializationAgendaFilter根据序列化规则名称运行
  2. 通过RuleNameMatchesAgendaFilter根据正则运行

关键字

Drools中的关键字分为:Hard keywords和Soft keywords

硬关键字是我们在规则文件中定义包名或者规则名时明确不能使用的,否则程序会报错。软关键字虽然可以使用,但是不建议使用。如果关键字设置为字符串程序会不会报错的,但不建议使用

Hard keywords:true false null then when等规则体的名称

Soft keywords:lock-on-active date-effective date-expires no-loop auto-focus activation-group agenda-group ruleflow-group entry-point duration package import dialect salience enabled attributes rule extend when then template query declare function global eval not in or and exists forall accumulate collect from action reverse result end over init

Drools内置方法

规则文件中的右手边(RHS)主要用于通过插入、删除或修改工作内存中的事实数据,以实现对规则引擎的控制。Drools提供了一系列方法,用于操作工作内存中的数据。在数据操作完成后,规则引擎会重新匹配相关规则,之前未成功匹配的规则可能因我们的数据修改而成功匹配。

update方法

更新工作内存的数据,并让相关的规则重新匹配

@Test
public void updateTest(){
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("李四");
    kieSession.insert(customer);
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new AgendaFilter() {
        @Override
        public boolean accept(Match match) {
            if(match.getRule().getName().contains("update_")){
                return true;
            }
            return false;
        }
    });
    //关闭
    kieSession.dispose();
}
rule "update_1"
    when
        $customer:Customer(name == "李四");
    then
        System.out.println("触发规则:通过drl修改客户信息,修改前:"+$customer.getName());
        $customer.setName("王五");
        update($customer);
        System.out.println("触发规则:通过drl修改客户信息,修改后:"+$customer.getName());
end

rule "update_2"
    when
        $customer:Customer(name ==  "王五")
    then
        System.out.println("触发规则:匹配到王五的客户;"+$customer.getName());
end
insert方法

插入数据到工作内存中,并让相关的规则重新匹配

@Test
public void insertTest(){
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("insert_"));
    //关闭
    kieSession.dispose();
}
rule "insert_1"
    when
        eval(true)
    then
        Customer customer = new Customer();
        customer.setName("张三");
        insert(customer);
        System.out.println("触发规则:通过drl设置客户信息");
end

rule "insert_2"
    when
        $customer:Customer(name ==  "张三")
    then
        System.out.println("触发规则:匹配到张三的客户;"+$customer.getName());
end
retract方法

删除工作内存中的数据,并让相关的规则重新匹配

@Test
public void retract(){
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("retract_"));
    //关闭
    kieSession.dispose();
}
rule "retract_1"
    when
    then
        Customer customer = new Customer();
        customer.setName("张三");
        insert(customer);
        System.out.println("触发规则retract_1:通过drl设置客户信息");
end


rule "retract_2"
    when
        $customer:Customer($customer.getName() == "张三")
    then
        retract($customer)
        System.out.println("触发规则retract_2:删除客户信息。"+$customer.getName());
end

rule "retract_3"
    when
        $customer:Customer($customer.getName() == "张三")
    then
        System.out.println("触发规则retract_3:找到客户信息。");
end

规则属性

规则体如下,规则熟悉主要是声明在attributes位置

rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end

部分常用属性如下:

属性名

说明

salience

指定规则执行优先级

dialect

指定规则使用的语言类型,取值为Java和mvel

enabled

指定规则是否启用

date-effective

指定规则生效时间

date-expires

指定规则失效时间

activation-group

激活分组,具有相同分组名称的规则只能有一个规则触发

agenda-group

议程分组,只有获取焦点的组中的规则才有可能触发

timer

定时器,指定规则触发的时间

auto-focus

自动获取焦点,一般结合agenda-group一起使用

no-loop

防止死循环

enabled属性

enabled属性对应的值为true和false,如果没有声明就默认true

用于指定当前规则是否启用,如果设置的false则无论当前规则是否满足要求都不会执行

rule "enabled_1"
    enabled false
    when
    then
        System.out.println("触发规则:enabled_1");
end
//规则是否可用
@Test
public void enabledTest(){
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("enabled_"));
    //关闭
    kieSession.dispose();
}
dialect属性

dialect用于指定规则使用的语言类型,取值为Java和mvel。默认值为Java

salience属性

salience属性用于指定规则执行优先级。数值越大越先执行。如果不设置则默认从上往下的顺序执行

//规则执行优先级
@Test
public void salienceTest(){
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("salience_"));
    //关闭
    kieSession.dispose();
}
rule "salience_1"
    //salience 1
    when
    then
        System.out.println("触发规则:salience_1");
end

rule "salience_2"
    //salience 2
    when
    then
        System.out.println("触发规则:salience_2");
end

salience属性设置前执行结果:

salience属性设置后执行结果:

no-loop属性

no-loop属性用于只让规则执行异常,防止死循环。规则通过update函数修改了对象数据时,会使当前规则再次被激活从而导致死循环。值类型为Boolean,默认值为false

//只让规则执行一次
@Test
public void noLoopTest(){
    KieSession kieSession = getKieSession();
    Customer customer = new Customer();
    customer.setName("李四");
    kieSession.insert(customer);
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("no_loop_"));
    //关闭
    kieSession.dispose();
}
rule "no_loop_1"
    no-loop true
    when
        $cutomer:Customer(name == "李四")
    then
        update($cutomer)
        System.out.println("触发规则:no_loop_1");
end

no-loop属性设置前结果:

no-loop属性设置后结果:

activation-group属性

activation-group属性用于激活分组,相同分组名的规则只有一个规则被触发

//分组执行
@Test
public void activationGroupTest(){
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("activation_group_"));
    //关闭
    kieSession.dispose();
}
rule "activation_group_1"
    activation-group "activation_group_test"
    when
    then
        System.out.println("触发规则:activation_group_1");
end

rule "activation_group_2"
    activation-group "activation_group_test"
    when
    then
        System.out.println("触发规则:activation_group_2");
end

auto-focus属性

auto-focus属性用于自动获取焦点,类型未Boolean,默认值为false。一般结合activation-group属性使用,当一个分组未获取焦点时,可以通过auto-focus属性控制

@Test
public void activationGroupTest(){
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("activation_group_"));
    //关闭
    kieSession.dispose();
}
rule "activation_group_1"
    activation-group "activation_group_test"
    auto-focus true
    when
    then
        System.out.println("触发规则:activation_group_1");
end

rule "activation_group_2"
    activation-group "activation_group_test"
    auto-focus true
    when
    then
        System.out.println("触发规则:activation_group_2");
end
timer属性

timer属性用于指定时间执行方法,也叫定时器。可以通过两种方式实现:

方法一:timer(5s 2s) //第一个参数表示几面后执行,第二个参数表示每隔几秒执行一次,第二个参数可选

//定时任务
@Test
public void timerTest() throws InterruptedException {
KieSession kieSession = getKieSession();

new Thread(new Runnable() {
    @Override
    public void run() {
        kieSession.fireUntilHalt(new RuleNameEqualsAgendaFilter("timer_1"));
    }
}).start();
Thread.sleep(10000);
//关闭
kieSession.dispose();
}
rule "timer_1"
    timer(5s 2s) //5秒后触发,每隔2秒触发一次
    when
    then
        System.out.println("触发规则:timer_1。触发时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
end

方法二:timer(cron:0/1 * * * * ?) //此方法使用cron表达式来指定规则执行的时间

//定时任务
@Test
public void timerTest() throws InterruptedException {
KieSession kieSession = getKieSession();

new Thread(new Runnable() {
    @Override
    public void run() {
        kieSession.fireUntilHalt(new RuleNameEqualsAgendaFilter("timer_2"));
    }
}).start();
Thread.sleep(10000);
//关闭
kieSession.dispose();
}
rule "timer_2"
    timer(cron:0/1 * * * * ?) //每隔一秒执行一次
    when
    then
        System.out.println("触发规则:timer_2。触发时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
end

date-effective属性

date-effective属性用于指定规则的生效时间,系统时间大于等于设置的时间规则才可能出发。默认日期格式为:dd-MMMM-yyyyy。用于可以自定义日期格式

//当前时间大于等于date_effective
@Test
public void dateEffectiveTest(){
    System.setProperty("drools.dateformat","yyyy-MM-dd");
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("date_effective_"));
    //关闭
    kieSession.dispose();
}
rule "date_effective_1"
    date-effective "2024-03-01"
    when
    then
        System.out.println("触发规则:当前时间小于等于date-effective");
end

date-expires属性

date-expires属性用于指定规则的失效时间,系统时间小于设置的日期规则才有可能出发。默认日期格式为:dd-MMMM-yyyyy。用于可以自定义日期格式

//当前时间大于等于date_expires
@Test
public void dateExpiresTest(){
    System.setProperty("drools.dateformat","yyyy-MM-dd");
    KieSession kieSession = getKieSession();
    //激活所有规则并执行,drools会自动去匹配
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("date_expires_"));
    //关闭
    kieSession.dispose();
}
rule "date_expires_1"
    date-expires  "2024-03-18"
    when
    then
        System.out.println("触发规则:当前时间大于等于date-effective");
end

Drools高级语法

关键字

描述

package

包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用

import

用于导入类或者静态方法

global

全局变量

function

自定义函数

query

查询

rule end

规则体

global全局变量

global关键字用于规则文件中定义全局变量。 可以用来为规则文件提供数据

语法结构:global 对象类型 对象名称

tips:如果对象类型为包装类型,在一个规则文件改变了global值,那么只在当前规则有效,其他规则中的global不受影响。如果对象类型为集合类型或JavaBean时,在一个规则文件改变了global值,对Java代码和所有规则都有效

包装类型示例:

@Test
public void globalTest() {
    KieSession kieSession = getKieSession();
    kieSession.setGlobal("num",1);
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("global_"));
    //关闭
    kieSession.dispose();
}
package rules;
import com.qz.entity.*;
global java.lang.Integer num;//定义一个包装类型的全局变量

rule "global_1"
    when

    then
        num += 10;
        System.out.println("触发规则:global_1");
        System.out.println("num全局变量的值为:"+num);
end

rule "global_2"
    when

    then
        System.out.println("触发规则:global_2");
        System.out.println("num全局变量的值为:"+num);
end

其他类型示例:

@Test
public void globalTest() {
    KieSession kieSession = getKieSession();
    kieSession.setGlobal("num",1);
    kieSession.setGlobal("dataList",new ArrayList());
    kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("global_"));
    //关闭
    kieSession.dispose();
}
package rules;
import com.qz.entity.*;
global java.lang.Integer num;//定义一个包装类型的全局变量
global java.util.List dataList;//定义一个集合类型的全局变量

rule "global_1"
    when
    then
        num += 10;
        System.out.println("触发规则:global_1");
        System.out.println("num全局变量的值为:"+num);
        dataList.add("测试");
        System.out.println("dataList全局变量为:"+dataList.get(0));
end

rule "global_2"
    when
    then
        System.out.println("触发规则:global_2");
        System.out.println("num全局变量的值为:"+num);
        System.out.println("dataList全局变量为:"+dataList.get(0));
end

query查询

query查询提供了查询工作内存中符合约束条件对象的方法

@Test
public void queryTest() {
    KieSession kieSession = getKieSession();
    Order order = new Order();
    order.setMoney(10);
    kieSession.insert(order);
    //对应工作文件的名称
    QueryResults query1 = kieSession.getQueryResults("query_1");
    int size = query1.size();
    System.out.println("符合条件的数量:"+size);
    //返回对象
    for (QueryResultsRow queryResultsRow : query1) {
        Order order2 = (Order)queryResultsRow.get("$order");
        System.out.println(order2);
    }
    //关闭
    kieSession.dispose();
}
package rules;
import com.qz.entity.Order;

//工作内存中查找符合条件的对象
query "query_1"
    $order:Order(money == "10")
end

带有条件的query:

@Test
public void queryTest() {
    KieSession kieSession = getKieSession();
    Order order = new Order();
    order.setMoney(10);
    order.setScore(100);
    kieSession.insert(order);
    //对应工作文件的名称
    QueryResults query1 = kieSession.getQueryResults("query_2",100);
    int size = query1.size();
    System.out.println("符合条件的数量:"+size);
    //返回对象
    for (QueryResultsRow queryResultsRow : query1) {
        Order order2 = (Order)queryResultsRow.get("$order");
        System.out.println(order2);
    }
    //关闭
    kieSession.dispose();
}
//工作内存中查找符合条件的对象。带有参数
query "query_2"(int nScore)
    $order:Order(money == "10" && score == nScore)
end

function函数

function关键字用于在规则文件中定义函数,跟Java类中的方法一样。好处是可以将业务逻辑集中放置在一起

语法结构:

function 返回值类型 函数名(可选参数){
    //逻辑代码
}

示例代码:

@Test
public void functionTest() {
    KieSession kieSession = getKieSession();
    Order order = new Order();
    order.setMoney(100);
    kieSession.insert(order);
    kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("function_1"));
    //关闭
    kieSession.dispose();
}
package rules;
import com.qz.entity.Order;

//函数
function String test(int money){
    return "测试金额为:"+money;
}

//规则中调用上面的函数
rule "function_1"
    when
        $O:Order(money == 100)
    then
        //调用函数
        String result = test($O.getMoney());
        System.out.println("返回结果"+result);
end

未完待续..........................................

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值