Drools规则引擎

一、Drools规则引擎

Drools官网:
https://www.drools.org/

Drools中文网:
http://www.drools.org.cn/

bilibili学习视频:
https://www.bilibili.com/video/BV1q34y1X77H?p=1

maven依赖:
https://mvnrepository.com/search?q=drools

gitee项目笔记:
https://gitee.com/happy_sad/drools

一、00_droolsDemo

image-20230413163603891

1、pom.xml

引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、Order.java

编写实体类(com.jin.rules.entity.Order.java)

package com.jin.rules.entity;

import lombok.Data;

@Data
public class Order {

    /**
     * 订单金额
     */
    private int amount;

    /**
     * 积分
     */
    private int score;

    @Override
    public String toString() {
        return "Order{" +
                "amount=" + amount +
                ", score=" + score +
                '}';
    }
}

3、META-INF.kmodule.xml

编写配置文件(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="SimpleRuleKBase" packages="rules">
        <!--
        name:指定ksession的名称,可以任意,但是必须唯一
        default:指定当前ksession是否为默认
        -->
        <ksession name="simpleRuleKSession"/>
    </kbase>
</kmodule>

4、rules.score-rules.drl

编写规则文件(resources.rules.score-rules.drl)

package rules;

import com.jin.rules.entity.Order;

//100元以下不加分
rule "score_1" //名称需唯一
    when
        //工作内存中必须存在Order这种类型的Fact对象 ---类型约束
        //Fact对象的amount属性值必须小于等于100 ---属性约束
        $sssss:Order(amount < 100);
    then
        $sssss.setScore(0);
        System.out.println("触发规则,100元以下不加分");
end

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

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

//1000元以上 加1000分
rule "score_4"
    when
        $order:Order(1000 < amount)
    then
        $order.setScore(1000);
        System.out.println("触发规则,500元-1000元 加500分");
end

//直接触发规则
rule "score_5"
    when

    then
        System.out.println("触发规则,LHS始终为空,规则始终触发!");
end

//enabled false
rule "score_6"
    enabled false
    when

    then
        System.out.println("触发规则!");
end

5、ApplicationTests.java

编写测试类(com.jin.rules.ApplicationTests)

package com.jin.rules;

import com.jin.rules.entity.Order;
import org.junit.jupiter.api.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ApplicationTests {

    @Test
    void contextLoads() {
    }

    @Test
    public void test() {
        System.out.println("规则执行开始,执行规则");
        //第一步 获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步获取kieContainer
        KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer("SimpleRuleKBase");
        //第三步获取kieSession
        KieSession simpleRuleKSession = kieClasspathContainer.newKieSession("simpleRuleKSession");
        //新建事实对象
        Order order = new Order();
        order.setAmount(235);
        //第四步 插入事实对象到session中
        simpleRuleKSession.insert(order);
        //第五步 执行规则引擎
        simpleRuleKSession.fireAllRules();
        //第六步 关闭规则引擎
        simpleRuleKSession.dispose();
        System.out.println("规则执行完成,关闭规则");
    }

}

6、测试结果

image-20230413163720822

二、01_droolsDemo

image-20230413170120007

1、pom.xml

引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、entity实体

2.1 Customer.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Customer {
    private String name;
    private List<Order> orderList;
}
2.2 Order.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    /**
     * 订单金额
     */
    private int amount;

    /**
     * 积分
     */
    private int score;
}

3、META-INF.kmodule.xml

编写配置文件(resources.META-INF.kmodule.xml)

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">

    <!--
    name:指定kbase的名称,可以任意,但是必须唯一
    packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
    default:指定当前kbase是否为默认
    -->
    <kbase name="myKbase1" packages="rules" default="true">
        <!--
        name:指定ksession的名称,可以任意,但是必须唯一
        default:指定当前ksession是否为默认
        -->
        <ksession name="ksession-rule" default="true"/>
    </kbase>
</kmodule>

4、rules规则文件

4.1 customer-rules.drl
package rules;

import com.jin.rules.entity.*;

//测试contains
rule "rule_1"
    when
        $order:Order();
        $customer:Customer(orderList contains $order);
    then
        System.out.println("触发规则:orderList 包含$order...");
end

//测试not contains
rule "rule_2"
    when
        $order:Order();
        $customer:Customer(orderList not contains $order);
    then
        System.out.println("触发规则:orderList 不包含$order...");
end

//测试比较操作符matches
rule "rule_3"
    when
        Customer(name matches "张.*");
    then
        System.out.println("触发规则:name是以张为开头的...");
end

//测试比较操作符not matches
rule "rule_4"
    when
        Customer(name not matches "张.*");
    then
        System.out.println("触发规则:name不是以张为开头的...");
end
4.2 score-rules.drl
package rules;

import com.jin.rules.entity.Order;

//100元以下不加分
rule "score_1" //名称需唯一
    when
        //工作内存中必须存在Order这种类型的Fact对象 ---类型约束
        //Fact对象的amount属性值必须小于等于100 ---属性约束
        $sssss:Order(amount < 100);
    then
        $sssss.setScore(0);
        System.out.println("触发规则,100元以下不加分");
end

//100元-500元 加100分
rule "score_2"
    when
        $order:Order(100 <= amount && amount<= 500)
    then
        $order.setScore(100);
        System.out.println("触发规则,100元-500元 加100分");
end
//500元-1000元 加500分
rule "score_3"
    when
        $order:Order(500 < amount && amount <= 1000)
    then
        $order.setScore(500);
        System.out.println("触发规则,500元-1000元 加500分");
end
//1000元以上 加1000分
rule "score_4"
    when
        $order:Order(1000 < amount)
    then
        $order.setScore(1000);
        System.out.println("触发规则,500元-1000元 加500分");
end

5、DroolsDemoApplicationTests.java

package com.jin.rules;

import com.jin.rules.entity.Customer;
import com.jin.rules.entity.Order;
import org.drools.core.base.RuleNameEqualsAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;

@SpringBootTest
class DroolsDemoApplicationTests {

    @Test
    void contextLoads() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer("myKbase1");
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession("ksession-rule");
        //事实对象
        Order order = new Order();
        order.setAmount(12);
//        order.setAmount(121);
//        order.setAmount(721);
//        order.setAmount(1211);
        //第四步:插入事实对象到session中
        kieSession.insert(order);
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();

        System.out.println("执行规则后积分:"+order.getScore());
    }

    /**
     * //测试contains
     */
    @Test
    void test01() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //事实对象
        Order order = new Order();
        Customer customer = new Customer();
        ArrayList<Order> orderList = new ArrayList<>();
        orderList.add(order);
        customer.setOrderList(orderList);

        //第四步:插入事实对象到session中
        kieSession.insert(order);
        kieSession.insert(customer);
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //测试not contains
     * //测试比较操作符not matches
     */
    @Test
    void test02() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //事实对象
        Order order = new Order();
        Customer customer = new Customer();
        ArrayList<Order> orderList = new ArrayList<>();
//        orderList.add(order);
        customer.setOrderList(orderList);

        //第四步:插入事实对象到session中
        kieSession.insert(order);
        kieSession.insert(customer);
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //测试比较操作符matches
     */
    @Test
    void test03() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //事实对象
        Order order = new Order();
        Customer customer = new Customer();
        customer.setName("张三");
        ArrayList<Order> orderList = new ArrayList<>();
//        orderList.add(order);
        customer.setOrderList(orderList);

        //第四步:插入事实对象到session中
        kieSession.insert(order);
        kieSession.insert(customer);
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //测试规则过滤器
     */
    @Test
    void test04() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //事实对象
        Order order = new Order();
        Customer customer = new Customer();
        customer.setName("张三");
        ArrayList<Order> orderList = new ArrayList<>();
//        orderList.add(order);
        customer.setOrderList(orderList);

        //第四步:插入事实对象到session中
        kieSession.insert(order);
        kieSession.insert(customer);
        //第五步:执行规则引擎
        //kieSession.fireAllRules();
        kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule_3"));
        //kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("rule_3"));
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

}

三、02_droolsFunction

image-20230413173951902

1、pom.xml

引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、entity实体

2.1 Customer.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Customer {
    private String name;
    private List<Order> orderList;
}
2.2 Order.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    /**
     * 订单金额
     */
    private int amount;

    /**
     * 积分
     */
    private int score;
}

3、META-INF.kmodule.xml

编写配置文件(resources.META-INF.kmodule.xml)

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">

    <!--
    name:指定kbase的名称,可以任意,但是必须唯一
    packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
    default:指定当前kbase是否为默认
    -->
    <kbase name="myKbase1" packages="rules" default="true">
        <!--
        name:指定ksession的名称,可以任意,但是必须唯一
        default:指定当前ksession是否为默认
        -->
        <ksession name="ksession-rule" default="true"/>
    </kbase>
</kmodule>

4、rules规则文件

customer-rules.drl

package rules;

import com.jin.rules.entity.*;

//1、Drools提供的内置方法insert
rule "rule_5"
    no-loop true    //避免死循环
    when
        eval(true);//默认成立
    then
        Customer customer = new Customer();
        customer.setName("张三");
        insert(customer);
        //insertLogical(customer);
        System.out.println("测试Drools提供的内置方法 insert 触发...");
end

rule "rule_6"
    no-loop true    //避免死循环
    when
        $customer:Customer(name == "张三");
    then
        System.out.println("测试Drools提供的内置方法 insert 触发..." + $customer.getName());
end

2、Drools提供的内置方法update
//rule "rule_7"
//    no-loop true    //避免死循环
//    when
//        $customer:Customer(name == "李四");
//    then
//        $customer.setName("王五");
//        update($customer)
//        System.out.println("测试Drools提供的内置方法 update 触发...");
//end
//
//rule "rule_8"
//    no-loop true    //避免死循环
//    when
//        $customer:Customer(name == "王五");
//    then
//        System.out.println("测试Drools提供的内置方法 update 触发..." + $customer.getName());
//end

3、Drools提供的内置方法retract
//rule "rule_9"
//    no-loop true    //避免死循环
//    when
//        $customer:Customer(name == "王五");
//    then
//        retract($customer)
//        System.out.println("测试Drools提供的内置方法 retract 触发...");
//end
//
//rule "rule_8"
//    no-loop true    //避免死循环
//    when
//        $customer:Customer();
//    then
//        System.out.println("测试Drools提供的内置方法 retract 触发..." + $customer.getName());
//end

5、ApplicationTests.java

package com.jin.rules;

import com.jin.rules.entity.Customer;
import org.junit.jupiter.api.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ApplicationTests {

    @Test
    void contextLoads() {
    }

    /**
     * insert 函数
     */
    @Test
    void test05() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * update 函数
     */
    @Test
    void test06() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //事实对象
        Customer customer = new Customer();
        customer.setName("李四");
        //第四步:插入事实对象到session中
        kieSession.insert(customer);
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * retract 函数
     */
    @Test
    void test07() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //事实对象
        Customer customer = new Customer();
        customer.setName("王五");
        //第四步:插入事实对象到session中
        kieSession.insert(customer);
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }
}

四、03_droolsProperty

image-20230413180250199

1、pom.xml

引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、entity实体

2.1 Customer.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Customer {
    private String name;
    private List<Order> orderList;
}
2.2 Order.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    /**
     * 订单金额
     */
    private int amount;

    /**
     * 积分
     */
    private int score;
}

3、META-INF.kmodule.xml

编写配置文件(resources.META-INF.kmodule.xml)

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">

    <!--
    name:指定kbase的名称,可以任意,但是必须唯一
    packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
    default:指定当前kbase是否为默认
    -->
    <kbase name="myKbase1" packages="rules" default="true">
        <!--
        name:指定ksession的名称,可以任意,但是必须唯一
        default:指定当前ksession是否为默认
        -->
        <ksession name="ksession-rule" default="true"/>
    </kbase>
</kmodule>

4、rules规则文件

attributes-rules.drl

package rules;

import com.jin.rules.entity.*
import java.text.SimpleDateFormat
import java.util.Date;

//1、salience属性(数值越大优先级越高)
rule "attributes_rule1"
salience 1
    when
        eval(true)
    then
        System.out.println("rule1...");
end

rule "attributes_rule2"
salience 2
    when
        eval(true)
    then
        System.out.println("rule2...");
end

2、no-loop(为true时表示该规则只会被引擎检查一次)
//rule "attributes_rule3"
//salience 3
//no-loop true
//    when
//        $customer:Customer(name == "张三")
//    then
//        update($customer)
//        System.out.println("死循环的customer name只被执行一次:" + $customer.getName());
//end

3、date-effective "yyyy-MM-dd"(只有当前系统时间>=date-effective设置的时间时执行)
//rule "attributes_rule4"
//salience 4
//    date-effective "2022-12-04" //设置的日期不小于今天的日期可以执行
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule4 is execution!");
//end

4、date-expires "yyyy-MM-dd"(只有当前系统时间<=date-expires设置的时间时执行)
//rule "attributes_rule5"
//salience 5
//    date-expires "2022-12-06" //设置的日期不大于今天的日期可以执行
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule5 is execution!");
//end

5、enabled(默认情况是true,为启动状态)
//rule "attributes_rule6"
//salience 6
//    enabled false
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule6 is execution!");
//end

6、dialect ""(默认为java,也可以指定为mvel)
//rule "attributes_rule7"
//salience 7
//dialect "java"
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule7 is execution!");
//end

7、activation-group ""(设置一个组,随机指定一个执行,也可加入优先级让优先级高的执行)
//rule "attributes_rule8"
//    activation-group "test"
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule8 is execution!");
//end
//
//
//rule "attributes_rule9"
//    activation-group "test"
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule9 is execution!");
//end

8、agenda-group ""(设置不同的组,在Java中指定一个组进行引擎扫描)
//rule "attributes_rule10"
//    agenda-group "001"
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule10 is execution!");
//end
//
//
//rule "attributes_rule11"
//    agenda-group "002"
//    auto-focus      //自动获得焦点
//    when
//        eval(true);
//    then
//        System.out.println("attributes_rule11 is execution!");
//end

9、timer()
//rule "attributes_rule13"
//    timer(5s 2s)    //5s后触发,然后每隔2s触发一次
//    when
//    then
//        System.out.println("attributes_rule13 is execution:触发时间为:" + new SimpleDateFormat("yyyy-MM-dd HH:m()m:ss").format(new Date()));
//end
//
//rule "attributes_rule14"
//    timer(cron:0/1 * * * * ?)    //每隔1s触发一次
//    when
//    then
//        System.out.println("attributes_rule14 is execution:触发时间为:" + new SimpleDateFormat("yyyy-MM-dd HH:m()m:ss").format(new Date()));
//end

5、ApplicationTests.java

package com.jin.rules;

import com.jin.rules.entity.Customer;
import org.drools.core.base.RuleNameEqualsAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ApplicationTests {

    @Test
    void contextLoads() {
    }

    /**
     * //1、salience属性(数值越大优先级越高)
     */
    @Test
    void test01() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //2、no-loop(为true时表示该规则只会被引擎检查一次)
     */
    @Test
    void test02() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //事实对象
        Customer customer = new Customer();
        customer.setName("张三");
        //第四部:
        kieSession.insert(customer);
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //3、date-effective "yyyy-MM-dd"(只有当前系统时间>=date-effective设置的时间时执行)
     */
    @Test
    void test03() {
        //设置日期格式(默认的日期格式为“dd-MMM-yyyy”)
        System.setProperty("drools.dateformat","yyyy-MM-dd");
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //4、date-expires "yyyy-MM-dd"(只有当前系统时间<=date-expires设置的时间时执行)
     */
    @Test
    void test04() {
        //设置日期格式(默认的日期格式为“dd-MMM-yyyy”)
        System.setProperty("drools.dateformat","yyyy-MM-dd");
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //5、enabled(默认情况是true,为启动状态)
     */
    @Test
    void test05() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //第五步:执行规则引擎
        kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("attributes_rule6"));
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //6、dialect ""(默认为java,也可以指定为mvel)
     */
    @Test
    void test06() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //第五步:执行规则引擎
        kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("attributes_rule7"));
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //7、activation-group ""(设置一个组,随机指定一个执行,也可加入优先级让优先级高的执行)
     */
    @Test
    void test07() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //8、agenda-group ""(设置不同的组,在Java中指定一个组进行引擎扫描)
     */
    @Test
    void test08() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();
        //活得执行焦点
        //kieSession.getAgenda().getAgendaGroup("002").setFocus();
        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //9、timer()
     */
    @Test
    void test09() throws InterruptedException {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();

        new Thread(new Runnable() {
            @Override
            public void run() {
                kieSession.fireUntilHalt();
            }
        }).start();

        Thread.sleep(10000);    //sleep了10s
        kieSession.halt();

        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }
}

五、04_droolsDeep

image-20230414153835812

1、pom.xml

引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、entity实体

2.1 Customer.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Customer {
    private String name;
    private List<Order> orderList;
}
2.2 Order.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    /**
     * 订单金额
     */
    private int amount;

    /**
     * 积分
     */
    private int score;
}
2.3 Person.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private int age;
    private String name;
}

3、META-INF.kmodule.xml

编写配置文件(resources.META-INF.kmodule.xml)

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">

    <!--
    name:指定kbase的名称,可以任意,但是必须唯一
    packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
    default:指定当前kbase是否为默认
    -->
    <kbase name="myKbase1" packages="rules" default="true">
        <!--
        name:指定ksession的名称,可以任意,但是必须唯一
        default:指定当前ksession是否为默认
        -->
        <ksession name="ksession-rule" default="true"/>
    </kbase>
</kmodule>

4、rules规则文件

high-rules.drl

package rules;

import com.jin.rules.entity.*
import java.util.List;
//定义全局变量
global List myGlobalList;
//1、global全局变量
rule "global_rule1"
    when
        eval(true)
    then
        myGlobalList.add("Hello world");
        System.out.println("global_rule1 is execution...");
end

rule "global_rule2"
    when
        eval(true)
    then
        System.out.println("myGlobalList集合的元素个数:" + myGlobalList.size());
        System.out.println("global_rule2 is execution...");
end

2、query查询
不带参数查询、当前query用于查询Working Memory中age>30的Person对象
//query "query_1"
//    $person:Person(age>30)
//end
带参数查询、当前query用于查询Working Memory中age>30且参数为nameParam的Person对象
//query "query_2"(String nameParam)
//    $person:Person(age>30,name == nameParam)
//end

3、function 函数
//function String fomat(String name){
//    return "hello" + name;
//}
//
//rule "function_rule"
//    when
//        $person:Person(name != null && age > 30)
//    then
//        //调用上面定义的函数
//        String fomat = fomat($person.getName());
//        System.out.println(fomat);
//end

5、ApplicationTests.java

package com.jin.rules;

import com.jin.rules.entity.Person;
import org.junit.jupiter.api.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest
class ApplicationTests {

    @Test
    void contextLoads() {
    }

    /**
     * //1、global全局变量
     */
    @Test
    void test01() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();

        //设置一个全局变量
        List<String> list = new ArrayList<>();
        kieSession.setGlobal("myGlobalList",list);

        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();

        System.out.println("规则执行完之后全局变量list的元素个数:" + list);
    }

    /**
     * //2、query查询
     */
    @Test
    void test02() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();

        Person p1 = new Person();
        p1.setAge(23);
        p1.setName("Jack1");
        kieSession.insert(p1);

        Person p2 = new Person();
        p2.setAge(56);
        p2.setName("Jack2");
        kieSession.insert(p2);

        Person p3 = new Person();
        p3.setAge(66);
        p3.setName("Jack3");
        kieSession.insert(p3);

        //执行查询
        QueryResults queryResults1 = kieSession.getQueryResults("query_1");
        for (QueryResultsRow queryResult : queryResults1) {
            Person p = (Person) queryResult.get("$person");
            System.out.println(p);
        }

        System.out.println("--------------------------------------");

        //执行查询
        QueryResults queryResults2 = kieSession.getQueryResults("query_2","Jack3");
        for (QueryResultsRow queryResult : queryResults2) {
            Person p = (Person) queryResult.get("$person");
            System.out.println(p);
        }

        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }

    /**
     * //3、function 函数
     */
    @Test
    void test03() {
        //第一步:获取KieServices
        KieServices kieServices = KieServices.Factory.get();
        //第二步:获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        //第三步:获取kieSession
        KieSession kieSession = container.newKieSession();

        Person p1 = new Person();
        p1.setAge(23);
        p1.setName("Jack1");
        kieSession.insert(p1);

        Person p2 = new Person();
        p2.setAge(56);
        p2.setName("Jack2");
        kieSession.insert(p2);

        Person p3 = new Person();
        p3.setAge(66);
        p3.setName("Jack3");
        kieSession.insert(p3);

        //第五步:执行规则引擎
        kieSession.fireAllRules();
        //第六步:关闭规则引擎
        kieSession.dispose();
    }
}

六、05_droolsSpring

image-20230414170147291

1、pom.xml

引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <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.kie</groupId>
            <artifactId>kie-spring</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

2、entity实体

2.1 Order.java
package com.jin.rules.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {

    /**
     * 订单金额
     */
    private int amount;

    /**
     * 积分
     */
    private int score;
}

3、rules规则文件

score-rules.drl

package rules;

import com.jin.rules.entity.Order;

//100元以下不加分
rule "score_1" //名称需唯一
    when
        //工作内存中必须存在Order这种类型的Fact对象 ---类型约束
        //Fact对象的amount属性值必须小于等于100 ---属性约束
        $sssss:Order(amount < 100);
    then
        $sssss.setScore(0);
        System.out.println("触发规则,100元以下不加分");
end

//100元-500元 加100分
rule "score_2"
    when
        $order:Order(100 <= amount && amount<= 500)
    then
        $order.setScore(100);
        System.out.println("触发规则,100元-500元 加100分");
end
//500元-1000元 加500分
rule "score_3"
    when
        $order:Order(500 < amount && amount <= 1000)
    then
        $order.setScore(500);
        System.out.println("触发规则,500元-1000元 加500分");
end
//1000元以上 加1000分
rule "score_4"
    when
        $order:Order(1000 < amount)
    then
        $order.setScore(1000);
        System.out.println("触发规则,500元-1000元 加500分");
end

4、规则引擎配置类

DroolsConfig.java

package com.jin.rules.config;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.Resource;
import java.io.IOException;

/**
 * 规则引擎配置类
 */
@Configuration
public class DroolsConfig {
    //指定规则文件存放的目录
    private static final String RULES_PATH = "rules/";
    private final KieServices kieServices = KieServices.Factory.get();
    @Bean
    @ConditionalOnMissingBean
    public KieFileSystem kieFileSystem() throws IOException {
        System.setProperty("drools.dateformat","yyyy-MM-dd");
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        ResourcePatternResolver resourcePatternResolver =
                new PathMatchingResourcePatternResolver();
        Resource[] files =
                resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
        String path = null;
        for (Resource file : files) {
            path = RULES_PATH + file.getFilename();
            kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
        }
        return kieFileSystem;
    }
    @Bean
    @ConditionalOnMissingBean
    public KieContainer kieContainer() throws IOException {
        KieRepository kieRepository = kieServices.getRepository();
        kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
        kieBuilder.buildAll();
        return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
    }
    @Bean
    @ConditionalOnMissingBean
    public KieBase kieBase() throws IOException {
        return kieContainer().getKieBase();
    }
    @Bean
    @ConditionalOnMissingBean
    public KModuleBeanFactoryPostProcessor kiePostProcessor() {
        return new KModuleBeanFactoryPostProcessor();
    }
}

5、service业务层

RuleService.java

package com.jin.rules.service;

import com.jin.rules.entity.Order;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RuleService {
    @Autowired
    private KieBase kieBase;

    public Order executeRule(Order order){
        System.out.println(order);
        KieSession kieSession = kieBase.newKieSession();
        kieSession.insert(order);
        kieSession.fireAllRules();
        kieSession.dispose();

        return order;
    }
}

6、controller层

package com.jin.rules.controller;

import com.jin.rules.entity.Order;
import com.jin.rules.service.RuleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/rules/order")
public class OrderController {
    @Autowired
    private RuleService ruleService;

    @RequestMapping("/saveOrder")
    public Order saveOrder(@RequestBody Order order){
        return ruleService.executeRule(order);
    }
}

7、测试

此处为了便利本人在idea安装RestFulTool插件(也可使用Postman),利用RestFulTool插件进行测试如下
请求参数(入参):body
{
  "amount": 520,
  "score": 0
}
返回参数(出参):response
{
  "amount": 520,
  "score": 500
}

image-20230414165831876

七、06_drools

image-20230416231806489

image-20230416231834030

1、数据库

1.建表rules
CREATE TABLE `rules` (
  `id` int(11) NOT NULL,
  `rules` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、插入一条规则数据
INSERT INTO `db_drools`.`rules`(`id`, `rules`) VALUES (1, 
'package rules;

import com.jin.rules.bean.Message;

rule "rule01"
    when
        $message:Message(status == 0)
    then
        $message.setContent("hello,Drools Message!!!");
        System.out.println("hello,Drools Message!!!");
end
');

2、application.properties

server.port=8009

application.main=com.jin.rules.Application

spring.datasource.url=jdbc:mysql://localhost:3306/db_drools?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=******
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver

mybatis.mapper-locations=classpath*:mapper/*Mapper.xml

3、pom.xml

引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</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-compiler</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>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-spring</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
    </dependencies>

4、bean实体

4.1 Message.java
package com.jin.rules.bean;

import java.io.Serializable;

public class Message implements Serializable {

    private static final long serialVersionUID = 1L;

    private String status;
    private String content;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}
4.2 Rules.java
package com.jin.rules.bean;

public class Rules {
    private Integer id;
    private String rules;

    public String getRules() {
        return rules;
    }

    public void setRules(String rules) {
        this.rules = rules;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

}

5、rules规则文件

rules.drl

#此处只需一个空的规则文件即可

6、mapper层

RulesDao.java

package com.jin.rules.dao;

import com.jin.rules.bean.Rules;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface RulesDao {
     Rules getById (@Param("id")Integer id);
}

7、sql层

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jin.rules.dao.RulesDao">
    <select id="getById" parameterType="int" resultType="com.jin.rules.bean.Rules">
        select *
        from rules
        where id = #{id}
    </select>
</mapper>

8、service层

package com.jin.rules.service;

import com.jin.rules.bean.Message;
import com.jin.rules.bean.Rules;
import com.jin.rules.dao.RulesDao;
import org.drools.core.ClassObjectFilter;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RulesService {
    @Autowired
    private RulesDao rulesDao;

    public String executeRules(Integer id) {
        String rules = "";
        Rules ru = rulesDao.getById(id);
        if (ru != null && ru.getRules() != null) {
            rules = ru.getRules();
        }

        KieServices kieServices = KieServices.Factory.get();
        KieFileSystem kfs = kieServices.newKieFileSystem();
        kfs.write("src/main/resources/rules/rules.drl", rules.getBytes());
        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
        Results results = kieBuilder.getResults();
        if (results.hasMessages(org.kie.api.builder.Message.Level.ERROR)) {
            System.out.println(results.getMessages());
            throw new IllegalStateException("### errors ###");
        }
        KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
        KieBase kieBase = kieContainer.getKieBase();
        KieSession ksession = kieBase.newKieSession();

        Message message = new Message();
        message.setStatus("0");
        ksession.insert(message);
        ksession.fireAllRules();

        String result= null;
        for (Object per : ksession.getObjects(new ClassObjectFilter(Message.class))) {
            if (((Message) per).getStatus().equals("0")) {
                result = ((Message) per).getContent();
            }
        }
        return result;
    }
}

9、controller层

package com.jin.rules.controller;

import com.jin.rules.bean.Rules;
import com.jin.rules.service.RulesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value = "/rules")
public class RulesController {

    @Autowired
    private RulesService rulesService;

    @RequestMapping(value ="/write" ,method = RequestMethod.POST)
    public String getRuleByWrite(@RequestBody Rules rule) {

        return rulesService.executeRules(rule.getId());
    }

}

10、测试

此处为了便利本人在idea安装RestFulTool插件(也可使用Postman),利用RestFulTool插件进行测试如下
请求参数(入参):body
{
  "id": 1,
  "rules": "String"
}
返回参数(出参):response
<html>
<body><h1>Whitelabel Error Page</h1>
<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>
<div id='created'>Sun Apr 16 23:14:54 CST 2023</div>
<div>There was an unexpected error (type=Not Found, status=404).</div>
</body>
</html>

image-20230416231609758

八、07_droolsDecision

image-20230601150141533

一、决策表

	对开发人员来说业务规则都是写在了drl文件中,这对开发人员来说是没有什么问题,如果是业务人员则不怎么友好,所以需要引入drools中决策表的使用,规则是写在excel文件中,通过上传决策表.xls到系统让其生成.drl文件,进行读取规则。
	图中ResultSet和ResultTable是必须的,而且同一个包中,此处是一个简单的决策表。
	
参考官网:https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#decision-tables-con_decision-tables

image-20230507123055678

二、RuleSet的属性

ResultSet:区域只可有一个。
LabelValueUsage
RuleSet生成的DRL文件的程序包名称。可选,默认值为“rule_table”。必须是第一个条目。
Sequential`true或false。如果是“true”,则使用显著性来确保规则自上而下地启动。可选,最多一次。如果省略,则不强制执行解雇令。
SequentialMaxPriority整数值可选,最多一次。在顺序模式中,此选项用于设置显著性的起始值。如果省略,则默认值为65535。
SequentialMinPriority整数值可选,最多一次。在顺序模式中,此选项用于检查是否未违反此最小显著性值。如果省略,则默认值为0。
EscapeQuotes`true或false。如果“true”,则转义引号,以便它们在DRL中按字面意思出现。可选,最多一次。如果省略,则转义引号。
IgnoreNumericFormat`true或false。如果为“true”,则忽略数值的格式,例如百分比和货币。可选,最多一次。如果省略,则DRL采用格式化的值。
Import要从另一个包导入的Java类的逗号分隔列表。可选,可以重复使用。
VariablesDRL全局变量的声明(后面跟着变量名的类型)。多个全局定义必须用逗号分隔。可选,可以重复使用。
Functions根据DRL语法的一个或多个查询定义。可选,可以重复使用。
Declare根据DRL语法的一个或多个查询定义。可选,可以重复使用。
Unit从此决策表生成的规则所属的规则单元。可选,最多一次。如果省略,则这些规则不属于任何单位。
Dialectjava或mvel。在决策表的操作中使用的方言。可选,最多一次。如果省略,则强制使用java。

三、RuleTable的属性

LabelOr custom label that begins withValueUsage
NAMEN提供从该行生成的规则的名称。默认值由RuleTable标记后面的文本和行号构成。最多一列。
DESCRIPTIONI在生成的规则中产生注释。最多一列。
CONDITIONC用于在条件中的模式内构造约束的代码段和插值。每个规则表至少有一个。
ACTIONA用于为规则的结果构造操作的代码段和插值。每个规则表至少有一个。
METADATA@用于构造规则的元数据项的代码段和插值。可选,任意列数。

四、规则属性的编写

在ResultSet和ResultTable这个地方都可以编写规则属性。ResultSet地方的规则属性将影响同一个包下所有的规则,而ResultTable这个地方的规则属性,只影响这个规则。ResultTable的优先级更高。

支持的规则属性有:PRIORITY、DATE-EFFECTIVE、DATE-EXPIRES、NO-LOOP、AGENDA-GROUP、ACTIVATION-GROUP、DURATION、TIMER、CALENDAR、AUTO-FOCUS、LOCK-ON-ACTIVE、RULEFLOW-GROUP。

五、需求

我们需要根据学生的成绩分数,给出相应的结果。规则如下:

特殊处理的规则:
规则一:只要名字是张三的,直接判定为 优
规则二:只要名字是李四的,如果分数在0,60之间,直接认为是一般

普通规则:
规则三:分数在0,60之间认为是不及格
规则四:分数在60,70之间认为是一般
规则五:分数在70,90之间认为是良好
规则六:分数在90,100之间认为是优

从上方的规则中,我们可以看到姓名为张三和李四的学生特殊处理了。

六、开发

1、pom.xml

引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jin</groupId>
    <artifactId>07_droolsDecision</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>07_droolsDecision</name>
    <description>07_droolsDecision</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-decisiontables</artifactId>
            <version>7.6.0.Final</version>
            <scope>test</scope>
        </dependency>
        <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>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.7</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
2、bean实体
package com.jin.rules.bean;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Student {

    private String name;
    // 分数只能在 0-100 之间
    private Integer score;

    public Student(String name, Integer score) {
        this.name = name;
        if (null == score || score < 0 || score > 100) {
            throw new RuntimeException("分数只能在0-100之间");
        }
        this.score = score;
    }
}
3、META-INF.kmodule.xml

编写配置文件(resources.META-INF.kmodule.xml)

<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <kbase name="kbase" packages="rules.decision.tables" default="false">
        <ksession name="ksession" default="false" type="stateful"/>
    </kbase>
</kmodule>
4、rules.decision.tables.student-score.xlsx
https://gitee.com/happy_sad/drools/tree/master/07_droolsDecision/src/main/resources/rules/decision/tables
5、测试
package com.jin.rules;

import com.jin.rules.bean.Student;
import lombok.extern.slf4j.Slf4j;
import org.drools.decisiontable.InputType;
import org.drools.decisiontable.SpreadsheetCompiler;
import org.kie.api.KieServices;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.utils.KieHelper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * drools 决策表的使用
 */
@Slf4j
public class DroolsDecisionTableApplication {
    public static void main(String[] args) throws IOException {
        decisionTable2Drl();
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.newKieClasspathContainer();
        // 张三虽然只得20分,但是根据规则判断,结果应该是  优
        invokedDecisionTable(kieContainer, new Student("张三", 20));
        // 李四虽然只得20分,但是根据规则判断,结果应该是  一般
        invokedDecisionTable(kieContainer, new Student("李四", 20));
        // 李四得75分,但是根据规则判断,结果应该是  良好
        invokedDecisionTable(kieContainer, new Student("李四", 75));
        // 王五得59分,但是根据规则判断,结果应该是  不及格
        invokedDecisionTable(kieContainer, new Student("王五", 59));
        // 赵六得69分,但是根据规则判断,结果应该是  一般
        invokedDecisionTable(kieContainer, new Student("赵六", 69));
        // 钱七得79分,但是根据规则判断,结果应该是  良好
        invokedDecisionTable(kieContainer, new Student("钱七", 79));
        // 李八得99分,但是根据规则判断,结果应该是  优
        invokedDecisionTable(kieContainer, new Student("李八", 99));
    }

    /**
     * 执行方法
     * @param kieContainer
     * @param student
     */
    public static void invokedDecisionTable(KieContainer kieContainer, Student student) {
        System.out.println("\r");
        KieSession kieSession = kieContainer.newKieSession("ksession");
        StringBuilder result = new StringBuilder();
        kieSession.setGlobal("resultsInfo", result);
        kieSession.insert(student);
        kieSession.fireAllRules();
        kieSession.dispose();
        System.out.println("规则执行结果:" + result);
    }

    /**
     * 决策表转换成 drl 文件
     */
    public static void decisionTable2Drl() throws IOException {
        Resource resource = ResourceFactory.newClassPathResource("rules/decision/tables/student-score.xlsx", "UTF-8");
        InputStream inputStream = resource.getInputStream();
        SpreadsheetCompiler compiler = new SpreadsheetCompiler();
        String drl = compiler.compile(inputStream, InputType.XLS);
        log.info("决策表转换的drl内容为:\r{}", drl);
        // 验证一下 drl 文件是否有问题
        KieHelper kieHelper = new KieHelper();
        Results results = kieHelper.addContent(drl, ResourceType.DRL).verify();
        List<Message> messages = results.getMessages(Message.Level.ERROR);
        if (null != messages && !messages.isEmpty()) {
            for (Message message : messages) {
                log.error(message.getText());
            }
        }
    }
}

image-20230601150141533

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jin-进

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值