Drools 的环境搭建及简单示例

环境: idea + jdk1.8 + gradle(或maven)

构造这样一个需求背景,双十一来了,商品打折,假设商品价格 (0,500], 打85折,商品价格 (500, 1000],打8折, 商品价格 (1000,∞), 一律减 300。

1. 创建项目

新建一个 gradle 项目,创建包:com.sharpcj,新建类 Product.java 和 Main.java

Drools 规则引擎环境搭建插图

Product.java 文件如下:

package com.sharpcj;
public class Product {
private String name; // 商品名称
private double prePrice; // 商品定价
private double realPrice; //商品实际售价
public Product() {
}
public Product(String name, double prePrice) {
this.name = name;
this.prePrice = prePrice;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrePrice() {
return prePrice;
}
public void setPrePrice(double prePrice) {
this.prePrice = prePrice;
}
public double getRealPrice() {
return realPrice;
}
public void setRealPrice(double realPrice) {
this.realPrice = realPrice;
}
}
package com.sharpcj; public class Product { private String name; // 商品名称 private double prePrice; // 商品定价 private double realPrice; //商品实际售价 public Product() { } public Product(String name, double prePrice) { this.name = name; this.prePrice = prePrice; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrePrice() { return prePrice; } public void setPrePrice(double prePrice) { this.prePrice = prePrice; } public double getRealPrice() { return realPrice; } public void setRealPrice(double realPrice) { this.realPrice = realPrice; } }
package com.sharpcj;

public class Product {
    private String name;  // 商品名称
    private double prePrice;  // 商品定价
    private double realPrice;  //商品实际售价

    public Product() {
    }

    public Product(String name, double prePrice) {
        this.name = name;
        this.prePrice = prePrice;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrePrice() {
        return prePrice;
    }

    public void setPrePrice(double prePrice) {
        this.prePrice = prePrice;
    }

    public double getRealPrice() {
        return realPrice;
    }

    public void setRealPrice(double realPrice) {
        this.realPrice = realPrice;
    }
}

然后在 Main.java 新建 main 方法。

2. Gradle引入Drools库

打开 build.gradle 文件,添加相应的插件和依赖

plugins {
id 'java'
}
plugins {
id 'application'
}
mainClassName = 'com.sharpcj.Main'
group 'com.sharpcj'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile group: 'org.kie', name: 'kie-api', version: '7.5.0.Final'
compile group: 'org.drools', name: 'drools-compiler', version: '7.5.0.Final'
}
plugins { id 'java' } plugins { id 'application' } mainClassName = 'com.sharpcj.Main' group 'com.sharpcj' version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile group: 'org.kie', name: 'kie-api', version: '7.5.0.Final' compile group: 'org.drools', name: 'drools-compiler', version: '7.5.0.Final' }
plugins {
    id 'java'
}

plugins {
    id 'application'
}

mainClassName = 'com.sharpcj.Main'

group 'com.sharpcj'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    compile group: 'org.kie', name: 'kie-api', version: '7.5.0.Final'
    compile group: 'org.drools', name: 'drools-compiler', version: '7.5.0.Final'
}

引入 Java 插件,使Gradle可以构建Java代码,同时引入了执行Drools依赖的两个库, 指定了 mainClassName

3.编写 drools 文件

在 resources 目录下面新建包 demo.rules,用来存放 drools 规则文件。然后新建文件 product.drl

Drools 规则引擎环境搭建插图1

内容如下:

package com.sharpcj;
rule "Product price less than 500" // 给规则取个名
when
pp : Product( prePrice <= 500 ) // 规则
then
// 符合规则后执行的操作,是Java代码
double prePrice = pp.getPrePrice();
pp.setRealPrice(prePrice * 0.85);
System.out.println(pp.getName() + "活动价是:" + pp.getRealPrice());
end
rule "Product price less than 1000" // 给规则取个名
when
p : Product( prePrice > 500 && prePrice <=1000 ) // 规则
then
// 符合规则后执行的操作,是Java代码
double prePrice = p.getPrePrice();
p.setRealPrice(prePrice * 0.8);
System.out.println(p.getName() + "活动价是:" + p.getRealPrice());
end
rule "Product price more than 1000" // 给规则取个名
when
p : Product( prePrice > 1000 ) // 规则
then
// 符合规则后执行的操作,是Java代码
double prePrice = p.getPrePrice();
p.setRealPrice(prePrice - 300);
System.out.println(p.getName() + "活动价是:" + p.getRealPrice());
end
package com.sharpcj; rule "Product price less than 500" // 给规则取个名 when pp : Product( prePrice <= 500 ) // 规则 then // 符合规则后执行的操作,是Java代码 double prePrice = pp.getPrePrice(); pp.setRealPrice(prePrice * 0.85); System.out.println(pp.getName() + "活动价是:" + pp.getRealPrice()); end rule "Product price less than 1000" // 给规则取个名 when p : Product( prePrice > 500 && prePrice <=1000 ) // 规则 then // 符合规则后执行的操作,是Java代码 double prePrice = p.getPrePrice(); p.setRealPrice(prePrice * 0.8); System.out.println(p.getName() + "活动价是:" + p.getRealPrice()); end rule "Product price more than 1000" // 给规则取个名 when p : Product( prePrice > 1000 ) // 规则 then // 符合规则后执行的操作,是Java代码 double prePrice = p.getPrePrice(); p.setRealPrice(prePrice - 300); System.out.println(p.getName() + "活动价是:" + p.getRealPrice()); end
package com.sharpcj;

rule "Product price less than 500" // 给规则取个名
when
    pp : Product( prePrice <= 500 ) // 规则
then
    // 符合规则后执行的操作,是Java代码
    double prePrice = pp.getPrePrice();
    pp.setRealPrice(prePrice * 0.85);
    System.out.println(pp.getName() + "活动价是:" + pp.getRealPrice());
end


rule "Product price less than 1000" // 给规则取个名
when
    p : Product( prePrice > 500 && prePrice <=1000 ) // 规则
then
    // 符合规则后执行的操作,是Java代码
    double prePrice = p.getPrePrice();
    p.setRealPrice(prePrice * 0.8);
    System.out.println(p.getName() + "活动价是:" + p.getRealPrice());
end


rule "Product price more than 1000" // 给规则取个名
when
    p : Product( prePrice > 1000 ) // 规则
then
    // 符合规则后执行的操作,是Java代码
    double prePrice = p.getPrePrice();
    p.setRealPrice(prePrice - 300);
    System.out.println(p.getName() + "活动价是:" + p.getRealPrice());
end

4.编写配置文件

运行 drools 需要一个固定的配置文件,在 resources 文件下的目录 META_INF,名称固定为 kmodule.xml

Drools 规则引擎环境搭建插图2

配置文件至少包含如下几行:

<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="kbase1" packages="demo.rules">
<ksession name="ksession1" />
</kbase>
</kmodule>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"> <kbase name="kbase1" packages="demo.rules"> <ksession name="ksession1" /> </kbase> </kmodule>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <kbase name="kbase1" packages="demo.rules">
        <ksession name="ksession1" />
    </kbase>
</kmodule>

配置简单说明:

  • Kmodule中可以包含一个到多个kbase,分别对应drl的规则文件。
  • Kbase需要一个唯一的name,可以取任意字符串。
  • packages为drl文件所在resource目录下的路径。注意区分drl文件中的package与此处的package不一定相同。
  • 多个包用逗号分隔。默认情况下会扫描resources目录下所有(包含子目录)规则文件。
  • kbase的default属性,标示当前KieBase是不是默认的,如果是默认的则不用名称就可以查找到该KieBase,但每个module最多只能有一个默认KieBase。
  • kbase下面可以有一个或多个ksession,ksession的name属性必须设置,且必须唯一。

5.让规则文件程序跑起来

在 Main.java 类中编写测试方法,让规则文件跑起来:

package com.sharpcj;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
public class Main {
public static void main(String[] args){
new Main().test();
}
private void test(){
// 构建KieServices
KieServices ks = KieServices.Factory.get();
KieContainer kc = ks.getKieClasspathContainer();
// 获取kmodule.xml中配置中名称为ksession-rule的session,默认为有状态的。
KieSession kSession = kc.newKieSession("ksession1");
Product fan = new Product("电扇", 280);
Product washer = new Product("洗衣机",2200);
Product phone = new Product("手机", 998);
kSession.insert(fan);
kSession.insert(washer);
kSession.insert(phone);
kSession.fireAllRules();
kSession.dispose();
}
}
package com.sharpcj; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; public class Main { public static void main(String[] args){ new Main().test(); } private void test(){ // 构建KieServices KieServices ks = KieServices.Factory.get(); KieContainer kc = ks.getKieClasspathContainer(); // 获取kmodule.xml中配置中名称为ksession-rule的session,默认为有状态的。 KieSession kSession = kc.newKieSession("ksession1"); Product fan = new Product("电扇", 280); Product washer = new Product("洗衣机",2200); Product phone = new Product("手机", 998); kSession.insert(fan); kSession.insert(washer); kSession.insert(phone); kSession.fireAllRules(); kSession.dispose(); } }
package com.sharpcj;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class Main {
    public static void main(String[] args){
        new Main().test();
    }

    private void test(){
        // 构建KieServices
        KieServices ks = KieServices.Factory.get();
        KieContainer kc = ks.getKieClasspathContainer();
        // 获取kmodule.xml中配置中名称为ksession-rule的session,默认为有状态的。
        KieSession kSession = kc.newKieSession("ksession1");

        Product fan = new Product("电扇", 280);
        Product washer = new Product("洗衣机",2200);
        Product phone = new Product("手机", 998);
        kSession.insert(fan);
        kSession.insert(washer);
        kSession.insert(phone);
        kSession.fireAllRules();
        kSession.dispose();
    }
}

运行结果:

Drools 规则引擎环境搭建插图3

三、其它说明

1.不使用配置文件形式

上面使用的配置文件形式加载 drools 文件是 drools 7.x 版本才有的,在此之前,我们通常使用代码形式加载规则文件,当然在 drools 7.x 中依然可以使用这种方式,只不过有些 API 已经过时了,或者更新了。下面用代码形式加载规则文件代码如下:

/**
* 不使用 drools 7.x 配置文件
*/
private void test2(){
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("demo/rules/product.drl"), ResourceType.DRL);
KnowledgeBuilderErrors errors = kbuilder.getErrors();
if (errors.size() > 0) {
for (KnowledgeBuilderError error: errors) {
System.err.println(error);
}
throw new IllegalArgumentException("Could not parse knowledge.");
}
// 注释掉的是 drools 6.x API
/*KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();*/
// drools 7.x API
InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
Collection<KiePackage> pkgs = kbuilder.getKnowledgePackages();
kbase.addPackages(pkgs);
KieSession kieSession = kbase.newKieSession();
Product fan = new Product("电扇", 280);
Product washer = new Product("洗衣机",2200);
Product phone = new Product("手机", 998);
kieSession.insert(fan);
kieSession.insert(washer);
kieSession.insert(phone);
kieSession.fireAllRules();
kieSession.dispose();
}
/** * 不使用 drools 7.x 配置文件 */ private void test2(){ KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add(ResourceFactory.newClassPathResource("demo/rules/product.drl"), ResourceType.DRL); KnowledgeBuilderErrors errors = kbuilder.getErrors(); if (errors.size() > 0) { for (KnowledgeBuilderError error: errors) { System.err.println(error); } throw new IllegalArgumentException("Could not parse knowledge."); } // 注释掉的是 drools 6.x API /*KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(kbuilder.getKnowledgePackages()); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();*/ // drools 7.x API InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); Collection<KiePackage> pkgs = kbuilder.getKnowledgePackages(); kbase.addPackages(pkgs); KieSession kieSession = kbase.newKieSession(); Product fan = new Product("电扇", 280); Product washer = new Product("洗衣机",2200); Product phone = new Product("手机", 998); kieSession.insert(fan); kieSession.insert(washer); kieSession.insert(phone); kieSession.fireAllRules(); kieSession.dispose(); }
/**
     * 不使用 drools 7.x 配置文件
     */
    private void test2(){
        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add(ResourceFactory.newClassPathResource("demo/rules/product.drl"), ResourceType.DRL);

        KnowledgeBuilderErrors errors = kbuilder.getErrors();
        if (errors.size() > 0) {
            for (KnowledgeBuilderError error: errors) {
                System.err.println(error);
            }
            throw new IllegalArgumentException("Could not parse knowledge.");
        }


        // 注释掉的是 drools 6.x API
        /*KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();*/

        // drools 7.x API
        InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        Collection<KiePackage> pkgs = kbuilder.getKnowledgePackages();
        kbase.addPackages(pkgs);
        KieSession kieSession = kbase.newKieSession();
        Product fan = new Product("电扇", 280);
        Product washer = new Product("洗衣机",2200);
        Product phone = new Product("手机", 998);
        kieSession.insert(fan);
        kieSession.insert(washer);
        kieSession.insert(phone);
        kieSession.fireAllRules();
        kieSession.dispose();
    }

运行程序依然能得到相同的结果。

2.规则文件的类型

规则文件除了 drl 文件之类,还有其它类型的文件,如 xls, csv。

Drools技术视频

Drools规则引擎基础&Workbench实战&决策表套餐

Drools7 规则引擎视频教程

《Drools7系列优惠套餐》

《Drools7规则引擎进阶教程》

《Drools7规则引擎入门教程》

《Drools规则引擎之决策表从入门到精通》

作者:SharpCJ,出处:https://www.cnblogs.com/joy99/p/10134893.html



Drools 规则引擎环境搭建插图4

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:http://choupangxia.cn/2020/04/18/drools-gradle/