欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Drools】动态规则引擎使用和配置(SpringBoot集成Drools)

程序员文章站 2022-05-28 11:19:22
...

前提:自己有一个springBoot的项目.没有的话自己创建即可。
直接上手:

pom.xml添加如下jar包:

            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-core</artifactId>
                <version>7.52.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-compiler</artifactId>
                <version>7.52.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-decisiontables</artifactId>
                <version>7.52.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-templates</artifactId>
                <version>$7.52.0.Final</version>
            </dependency>

            <dependency>
                <groupId>org.kie</groupId>
                <artifactId>kie-api</artifactId>
                <version>7.52.0.Final</version>
            </dependency>

为方便测试,可以多添加springboot test依赖(因为下面的例子会用到):

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

随便找个地方创建Test测试类

import org.junit.Test;
import org.junit.runner.RunWith;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.utils.KieHelper;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DroolsApplicationHelloWordTests {

    @Test
    public void test() {
        EntityInfoVo actualInfoVo = new EntityInfoVo(210137L, false, "规则", "描述");
        final KieBase kieBase = getKieSession("rule1", "(a>30||<10)");
        KieSession ksession = kieBase.newKieSession();
        ksession.setGlobal("ruleResult", actualInfoVo);
        Map<String, Object> map = new HashMap<>();
        map.put("a", 50);
        ksession.insert(map);
        ksession.fireAllRules();
        //移除session状态
        ksession.destroy();
        ksession.dispose();
        System.out.println("是否命中:"+actualInfoVo.getHit());
    }


    /**
     * @param ruleName 规则名称
     * @param rule     规则信息, 如 a>0||b<30
     * @return
     */
    private KieBase getKieSession(String ruleName, String rule) {
        String myRule = "import java.util.Map;\n" +
                "global com.example.droolsdemo.entity.EntityInfoVo ruleResult;\n" +
                "rule \"%s\"\n" +
                "         dialect \"mvel\"\n" +
                "         no-loop false \n" +
                "      when\n" +
                "        $fact:Map(%s)\n" +
                "      then\n" +
                "\t  ruleResult.setHit(Boolean.TRUE);\n" +
                "end";
        //生成完整的规则字符串
        final String ruleStr = String.format(myRule, ruleName, rule);
        KieHelper helper = new KieHelper();
        helper.addContent(ruleStr, ResourceType.DRL);
        return helper.build();
    }
}

实体类:

public class EntityInfoVo implements Serializable {
    private Long crowdCode;
    /**
     * 是否命中
     * true:命中
     * false:不命中
     */
    private Boolean hit;
    /**
     * 值说明
     */
    private String valueDes;
    /**
     * 规则说明
     */
    private String ruleDes;
    public Long getCrowdCode() {
        return crowdCode;
    }
    public void setCrowdCode(Long crowdCode) {
        this.crowdCode = crowdCode;
    }
    public Boolean getHit() {
        return hit;
    }
    public void setHit(Boolean hit) {
        this.hit = hit;
    }
   public String getValueDes() {
        return valueDes;
    }
    public void setValueDes(String valueDes) {
        this.valueDes = valueDes;
    }
    public String getRuleDes() {
        return ruleDes;
    }
    public void setRuleDes(String ruleDes) {
        this.ruleDes = ruleDes;
    }
    public EntityInfoVo(Long crowdCode, Boolean hit, String valueDes, String ruleDes) {
        this.crowdCode = crowdCode;
        this.hit = hit;
        this.valueDes = valueDes;
        this.ruleDes = ruleDes;
    }

    public EntityInfoVo() {
    }
}

getKieSession方法说明:
1- global com.example.droolsdemo.entity.EntityInfoVo ruleResult;
设置的全局对象,可用于规则走完when后,对该对象进行设置相应的赋值。(比如你要将结果带到外面的代码…可以看:ruleResult.setHit(Boolean.TRUE) 这行代码)
2- dialect :方言,可选 mvel,java 默认java
3- no-loop:是否循环判断,一般情况下都设置为false,因为如果是true 就会对你insert进来的对象进行循环遍历判断,处理不好会造成死循环.
4- 动态规则的重点: helper.addContent(ruleStr, ResourceType.DRL);

test方法说明:
1-

EntityInfoVo actualInfoVo = new EntityInfoVo(210137L, false, "规则", "描述");
ksession.setGlobal("ruleResult", actualInfoVo);
这两个设置规则全局对象。

2-

Map<String, Object> map = new HashMap<>();
map.put("a", 50);
ksession.insert(map);
这几行是将要判断的对象放进去,用于规则判断

3-
执行结果:
【Drools】动态规则引擎使用和配置(SpringBoot集成Drools)
注意点:
A- (a>30||<10) 这个规则,表示你要insert的对象,要有a,b两个字段,如果没有就会报错,因为源码里面会去找你insert进去的对象的字段,跟规则的字段对比。当然前面a>30返回true了,后面的b就不需要了,如果改成:a>30&&b<10 这个方法就会报错,修改如下:

Map<String, Object> map = new HashMap<>();
map.put("a", 50);
map.put("b", 50);
ksession.insert(map);

进一步优化

import org.junit.Test;
import org.junit.runner.RunWith;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.utils.KieHelper;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DroolsApplicationHelloWordTests {

    private static Map<String, KieBase> kieCache = new ConcurrentHashMap<>();
    @Test
    public void test() {
        EntityInfoVo actualInfoVo = new EntityInfoVo(210137L, false, "规则", "描述");
        final KieBase kieBase = getKieSession("rule1", "(a>30||<10)");
        KieSession ksession = kieBase.newKieSession();
        ksession.setGlobal("ruleResult", actualInfoVo);
        Map<String, Object> map = new HashMap<>();
        map.put("a", 50);
        ksession.insert(map);
        ksession.fireAllRules();
        //移除session状态
        ksession.destroy();
        ksession.dispose();
        System.out.println("是否命中:"+actualInfoVo.getHit());
    }


    /**
     * @param ruleName 规则名称
     * @param rule     规则信息, 如 a>0||b<30
     * @return
     */
    private KieBase getKieSession(String ruleName, String rule) {
        if (kieCache.get(ruleName) != null) {
            return kieCache.get(ruleName);
        }
        String myRule = "import java.util.Map;\n" +
                "global com.example.droolsdemo.entity.EntityInfoVo ruleResult;\n" +
                "rule \"%s\"\n" +
                "         dialect \"mvel\"\n" +
                "         no-loop false \n" +
                "      when\n" +
                "        $fact:Map(%s)\n" +
                "      then\n" +
                "\t  ruleResult.setHit(Boolean.TRUE);\n" +
                "end";
        //生成完整的规则字符串
        final String ruleStr = String.format(myRule, ruleName, rule);
        KieHelper helper = new KieHelper();
        helper.addContent(ruleStr, ResourceType.DRL);
        final KieBase build = helper.build();
        kieCache.put(ruleName, build);
        return build;
    }
}
//或者使用无状态的session  这样不需要维护会话的状态
//StatelessKieSession statelessKieSession = kieBase.newStatelessKieSession();
statelessKieSession.execute(object);//类似于ksession.insert(map);
进入源码可以看到:
    public void execute(Object object) {
        StatefulKnowledgeSession ksession = this.newWorkingMemory();

        try {
            ksession.insert(object);
            ksession.fireAllRules();
        } finally {
            this.dispose(ksession);
        }
    }
源码内部帮我们实现了dispose方法

完整代码:
demo

参考文献:
1-官方文档

2 中文文档(忘了在哪下载的了)
链接:https://pan.baidu.com/s/11Ex8a5aOc0HDsi2L73UQcQ
提取码:rhao

相关标签: java笔记 java