drools详解

article/2025/10/1 10:05:44

1、基本的概念
请参考这个链接,差不多的语法感觉都介绍了
drools-api的基本语法链接

2、如何将drl文件配置在数据库中,实现动态加载:

package com.neo.drools;import com.neo.drools.model.Message;
import org.kie.api.io.ResourceType;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderError;
import org.kie.internal.builder.KnowledgeBuilderErrors;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.runtime.StatefulKnowledgeSession;import java.io.UnsupportedEncodingException;/**  * @Description:将下面的两给drl字符串,其实可以放进数据库中,或者有专门的机制来维护这个字符串,* 后面直接读取这个字符串(其实就是drl文件),那么就可以实现动态加载了,缺点是,偏技术,业务人员看不懂* @Author: wumingdu* @Date: 2022/5/26 13:38*/
public class DdLoadTest {public static void main(String[] args) {//rule,rule2可以放在数据库中,有个唯一code和他们对于,代码要执行规则的时候,根据code从数据库获取出来就OK了,这样自己开发的规则管理系统那边对数据库里的规则进行维护就行了String rule = "package com.neo.drools\r\n";rule += "import com.neo.drools.model.Message;\r\n";rule += "rule \"rule1\"\r\n";rule += "\twhen\r\n";rule += "Message( status == 1, myMessage : msg )";rule += "\tthen\r\n";rule += "\t\tSystem.out.println( 1+\":\"+myMessage );\r\n";rule += "end\r\n";String rule2 = "package com.neo.drools\r\n";rule += "import com.neo.drools.model.Message;\r\n";rule += "rule \"rule2\"\r\n";rule += "\twhen\r\n";rule += "Message( status == 2, myMessage : msg )";rule += "\tthen\r\n";rule += "\t\tSystem.out.println( 2+\":\"+myMessage );\r\n";rule += "end\r\n";StatefulKnowledgeSession kSession = null;try {KnowledgeBuilder kb = KnowledgeBuilderFactory.newKnowledgeBuilder();//装入规则,可以装入多个kb.add(ResourceFactory.newByteArrayResource(rule.getBytes("utf-8")), ResourceType.DRL);kb.add(ResourceFactory.newByteArrayResource(rule2.getBytes("utf-8")), ResourceType.DRL);KnowledgeBuilderErrors errors = kb.getErrors();for (KnowledgeBuilderError error : errors) {System.out.println(error);}KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase();kBase.addKnowledgePackages(kb.getKnowledgePackages());kSession = kBase.newStatefulKnowledgeSession();Message message1 = new Message();message1.setStatus(1);message1.setMsg("hello world!");Message message2 = new Message();message2.setStatus(2);message2.setMsg("hi world!");kSession.insert(message1);kSession.insert(message2);kSession.fireAllRules();} catch (UnsupportedEncodingException e) {e.printStackTrace();} finally {if (kSession != null)kSession.dispose();}}
}

3、如何读取drl、决策表、csv文件:

注意:下文中的RULES_PATH,其实就是配置在resource下的路径,会通过kieFileSystem组件去读取这个目录下的所有文件。

配置drl文件的配置类(springboot+drl配置方式)

package com.itheima.drools.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.api.runtime.KieSession;
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@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic KieBase kieBase() throws IOException {return kieContainer().getKieBase();}@Bean@ConditionalOnMissingBeanpublic KModuleBeanFactoryPostProcessor kiePostProcessor() {return new KModuleBeanFactoryPostProcessor();}
}

根据文件,不管是drl文件,还是excel表格,或者是csv文件,将其动态的转换成字符串,这段代码很牛掰

	/*** 规则文件,决策表解析成字符串* @param realPath  决策表路径* @return  字符串*/public String encodeToString(String realPath) {File file = new File(realPath);if (!file.exists()) {return null;}// drl文件if (realPath.endsWith(SUFFIX_DRL)) {return read(file);}InputStream is = null;try {is = new FileInputStream(file);} catch (FileNotFoundException e) {logger.error("file not fount.");}// excel文件 xls和xlsx都支持// @author <a href="mailto:312182539@qq.com">fbf</a>if (realPath.endsWith(SUFFIX_EXCEL)||realPath.endsWith(SUFFIX_EXCEL_2007)) {return new SpreadsheetCompiler().compile(is, InputType.XLS);}// csv文件if (realPath.endsWith(SUFFIX_CSV)) {return new SpreadsheetCompiler().compile(is, InputType.CSV);}if (is != null) {try {is.close();} catch (IOException e) {logger.error("close stream error=>", e);}}return "package src.main.resources;";}/*** 读取drl文件*/private String read(File file) {FileInputStream fis = null;ByteArrayOutputStream bos = null;try {fis = new FileInputStream(file);bos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = fis.read(buffer)) != -1) {bos.write(buffer, 0, length);}return bos.toString();} catch (IOException e) {e.printStackTrace();} finally {try {if (bos != null) {bos.close();}if (fis != null) {fis.close();}} catch (IOException e) {e.printStackTrace();}}return null;}//这里还有很重要的一步,不管是excel,还是drl,最终会变解析为字符串//这个字符串是需要被解析运行的,如下:/*** 把字符串解析成KieSession* @param drl   规则文件字符串* @return  KieSession*/public KieSession decodeToSession(String... drl) {KieHelper kieHelper = new KieHelper();for (String s : drl) {kieHelper.addContent(s, ResourceType.DRL);}Results results = kieHelper.verify();if (results.hasMessages(Message.Level.WARNING, Message.Level.ERROR)) {List<Message> messages = results.getMessages(Message.Level.WARNING, Message.Level.ERROR);for (Message message : messages) {logger.error("Error: {}", message.getText());}throw new IllegalStateException("Compilation errors.");}KieBaseConfiguration config = kieHelper.ks.newKieBaseConfiguration();if (EventProcessingOption.STREAM.getMode().equalsIgnoreCase(getMode())) {config.setOption(EventProcessingOption.STREAM);} else {config.setOption(EventProcessingOption.CLOUD);}KieBase kieBase = kieHelper.build(config);KieSession kieSession = kieBase.newKieSession();if (getListener() == null || !LISTENER_CLOSE.equalsIgnoreCase(getListener())) {kieSession.addEventListener(new DefaultRuleRuntimeEventListener());kieSession.addEventListener(new DefaultAgendaEventListener());kieSession.addEventListener(new DefaultProcessEventListener());}return kieSession;}
KieBase kieBase = kieHelper.build();kieBase.addEventListener(new DefaultKieBaseEventListener(){@Overridepublic void beforeKiePackageRemoved(BeforeKiePackageRemovedEvent event) {super.beforeKiePackageRemoved(event);String packageName = event.getKiePackage().getName();System.out.println("beforeKiePackageRemoved : " + packageName);}});kieBase.removeKiePackage("com.rules");

4、设置拦截器等,大致的意思就是在实时对象插入或者修改或者删除的时候 做一些拦截,然后动态的加载逻辑,这是drools官方为我们提供的扩展东西,挺好的!!!

	 KieBase kieBase = kieHelper.build(config);KieSession kieSession = kieBase.newKieSession();if (getListener() == null || !LISTENER_CLOSE.equalsIgnoreCase(getListener())) {kieSession.addEventListener(new DefaultRuleRuntimeEventListener());kieSession.addEventListener(new DefaultAgendaEventListener());kieSession.addEventListener(new DefaultProcessEventListener());}return kieSession;
package com.drools.core.listener;import org.kie.api.event.rule.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @author <a href="mailto:hongwen0928@outlook.com">Karas</a>* @date 2020/9/9* @since 7.37.0.Final*/
public class DefaultAgendaEventListener implements AgendaEventListener {protected final Logger logger = LoggerFactory.getLogger(getClass());@Overridepublic void matchCreated(MatchCreatedEvent event) {logger.info("===>>匹配的规则:{}", event.getMatch().getRule());}@Overridepublic void matchCancelled(MatchCancelledEvent event) {}@Overridepublic void beforeMatchFired(BeforeMatchFiredEvent event) {logger.info("===>>开始执行Java代码块,匹配规则:{},评估对象:{}",event.getMatch().getRule(), event.getMatch().getFactHandles());}@Overridepublic void afterMatchFired(AfterMatchFiredEvent event) {logger.info("===>>结束执行Java代码块,匹配规则:{},评估对象:{}",event.getMatch().getRule(), event.getMatch().getFactHandles());}@Overridepublic void agendaGroupPopped(AgendaGroupPoppedEvent event) {}@Overridepublic void agendaGroupPushed(AgendaGroupPushedEvent event) {}@Overridepublic void beforeRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {}@Overridepublic void afterRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {}@Overridepublic void beforeRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {}@Overridepublic void afterRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {}
}package com.drools.core.listener;import org.kie.api.event.process.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @author <a href="mailto:hongwen0928@outlook.com">Karas</a>* @date 2020/9/9* @since 7.37.0.Final*/
public class DefaultProcessEventListener implements ProcessEventListener {protected final Logger logger = LoggerFactory.getLogger(getClass());@Overridepublic void beforeProcessStarted(ProcessStartedEvent event) {}@Overridepublic void afterProcessStarted(ProcessStartedEvent event) {}@Overridepublic void beforeProcessCompleted(ProcessCompletedEvent event) {}@Overridepublic void afterProcessCompleted(ProcessCompletedEvent event) {}@Overridepublic void beforeNodeTriggered(ProcessNodeTriggeredEvent event) {}@Overridepublic void afterNodeTriggered(ProcessNodeTriggeredEvent event) {}@Overridepublic void beforeNodeLeft(ProcessNodeLeftEvent event) {}@Overridepublic void afterNodeLeft(ProcessNodeLeftEvent event) {}@Overridepublic void beforeVariableChanged(ProcessVariableChangedEvent event) {}@Overridepublic void afterVariableChanged(ProcessVariableChangedEvent event) {}
}package com.drools.core.listener;import org.kie.api.event.rule.ObjectDeletedEvent;
import org.kie.api.event.rule.ObjectInsertedEvent;
import org.kie.api.event.rule.ObjectUpdatedEvent;
import org.kie.api.event.rule.RuleRuntimeEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @author <a href="mailto:hongwen0928@outlook.com">Karas</a>* @date 2020/9/9* @since 7.37.0.Final*/
public class DefaultRuleRuntimeEventListener implements RuleRuntimeEventListener {protected final Logger logger = LoggerFactory.getLogger(getClass());@Overridepublic void objectInserted(ObjectInsertedEvent event) {logger.info("===>>插入对象:{};操作规则:{}", event.getFactHandle(), event.getRule());}@Overridepublic void objectUpdated(ObjectUpdatedEvent event) {logger.info("===>>更新对象:{};操作规则:{}", event.getFactHandle(), event.getRule());}@Overridepublic void objectDeleted(ObjectDeletedEvent event) {logger.info("===>>删除对象:{};操作规则:{}", event.getFactHandle(), event.getRule());}
}

5、将决策表转化成drl字符串

    // 把xls文件解析为Stringpublic static String getDRL (String realPath) throws FileNotFoundException {File file = new File(realPath); // 例如:C:\\abc.xlsInputStream is = new FileInputStream(file);SpreadsheetCompiler compiler = new SpreadsheetCompiler();String drl = compiler.compile(is, InputType.XLS);System.out.println(drl);return drl;}

顺便分享一个完整的案例,如何从数据库读取脚本,实现动态加载,包括简单的表设计,全量代码:

github-drools+db代码

6、drools部分api使用(这些api是你市面上可能找不到的,一般百度是找不到的哦):
6.1、drl文件中使用函数

package rulesimport com.huan.drools.Person// 定义一个方法,判断用户是否可以玩游戏
function boolean playGameOk(Person person){return person.getAge()>=18;
}// 在when中调用这个函数
function String whenInvoked(Person person){return "whenInvoked,peronName:" + person.getName();
}// 判断用户是否可以玩游戏,主要是为了测试调用drl自定义的函数
rule "rule_can_play_game"when$person: Person()$invokedFunction: String() from whenInvoked($person)thenSystem.out.println("在when中调用function获取的结果: " + $invokedFunction);System.err.println("drl function 判断: 用户:["+$person.getName()+"]是否可以玩游戏?["+playGameOk($person)+"]");System.err.println("java static function 调用: "+ String.format("当前用户:%s", $person.getName()));
end

6.2 map在drools的应用

package com.rules
import java.util.Map;
import com.secbro.drools.model.Person;rule "map-usage"agenda-group "map-group"when$obj : Object();$map : Map(["p1"] != $obj);thenSystem.out.println("p1's age is " + ((Person)$map.get("p1")).getAge());System.out.println("p2's age is " + ((Person)$map.get("p2")).getAge());end

6.3、全局变量,可以通过这个在drl中 动态的调用 java代码:

package com.rules
import com.secbro.drools.model.Risk
import com.secbro.drools.model.Messageglobal com.secbro.drools.EmailService emailServicerule "test-global"agenda-group "test-global-group"when
thenMessage message = new Message();message.setRule(drools.getRule().getName());message.setDesc("to send email!");emailService.sendEmail(message);
end

6.4、函数的使用:

package com.rulesfunction String hello(String name){return "Hello " + name + "!";
}rule helloSomeoneagenda-group "function-group"wheneval(true);thenSystem.out.println(hello("Tom"));end

6.5、可以在规则文件中获取"rule"这个对象,然后可以获取到很多属性:

package com.rulesrule "Get name and package demo"agenda-group "Name and package"when
thenSystem.out.println("The rule's name is '" + drools.getRule().getName() + "'");System.out.println("The rule's package is  '" + drools.getRule().getPackageName() + "'");
end

6.5、query方法,相当于给java提供一个入口,去获取drl文件里面的对象:

package com.rules
import com.secbro.drools.model.Person;rule "query-test"agenda-group "query-test-group1"when$person : Person()thenSystem.out.println("The rule query-test fired!");endquery "query-1"$person : Person(age > 30)
endquery "query-2"(String nameParam)$person : Person(age > 30,name == nameParam)
end
package com.secbro.drools.test;import com.secbro.drools.BaseTest;
import com.secbro.drools.model.Person;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;/*** Created by zhuzs on 2017/8/20.*/
public class QueryTest extends BaseTest {@Testpublic void queryTest() {KieSession kieSession = this.getKieSession("query-test-group1");Person p1 = new Person();p1.setAge(29);Person p2 = new Person();p2.setAge(40);kieSession.insert(p1);kieSession.insert(p2);int count = kieSession.fireAllRules();System.out.println("Fire " +count + " rule(s)!");QueryResults results = kieSession.getQueryResults("query-1");System.out.println("results size is " + results.size());for(QueryResultsRow row : results){Person person = (Person) row.get("$person");System.out.println("Person from WM, age : " + person.getAge());}kieSession.dispose();}@Testpublic void queryWithParamTest() {KieSession kieSession = this.getKieSession("query-test-group1");Person p1 = new Person();p1.setAge(29);p1.setName("Ross");Person p2 = new Person();p2.setAge(40);p2.setName("Tom");kieSession.insert(p1);kieSession.insert(p2);int count = kieSession.fireAllRules();System.out.println("Fire " +count + " rule(s)!");QueryResults results = kieSession.getQueryResults("query-2","Tom");System.out.println("results size is " + results.size());for(QueryResultsRow row : results){Person person = (Person) row.get("$person");System.out.println("Person from WM, age : " + person.getAge() + "; name :" + person.getName());}kieSession.dispose();}
}

6.6、同一个对象类型,在drl文件中如何展示:

package com.rulesimport com.secbro.drools.model.Customer;rule "two same objects"agenda-group "two same objects"when$firstCustomer:Customer(age == 59);$secondCustomer:Customer(this != $firstCustomer,age == 61);thenSystem.out.println("firstCustomer age :" + $firstCustomer.getAge());System.out.println("secondCustomer age :" + $secondCustomer.getAge());end

6.7、drl文件中的from的用法:

package com.rulesimport com.secbro.drools.model.Customer;
import java.util.List;rule "two same objects in list"agenda-group "two same objects in list"when$list : List();$firstCustomer:Customer(age == 59) from $list;$secondCustomer:Customer(this != $firstCustomer,age == 61) from $list;thenSystem.out.println("two same objects in list:firstCustomer age :" + $firstCustomer.getAge());System.out.println("two same objects in list:secondCustomer age :" + $secondCustomer.getAge());end

6.8、Calendar在 drools的使用:设置不同的日期限制,规则中对应的触发日期就不一样,比time更强大一些

package com.secbro.drools.chapter21;import com.secbro.drools.BaseTest;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.time.Calendar;
import org.quartz.impl.calendar.WeeklyCalendar;public class CalenderTest extends BaseTest{@Testpublic void testCalender(){KieSession kieSession = this.getKieSessionBySessionName("calenderTest-rules");kieSession.getCalendars().set("weekday_exclude",WEEKDAY_EXCLUDE);kieSession.getCalendars().set("weekday",WEEKDAY);kieSession.fireAllRules();kieSession.dispose();}private static final Calendar WEEKDAY = new Calendar() {@Overridepublic boolean isTimeIncluded(long timestamp) {WeeklyCalendar weeklyCalendar = new WeeklyCalendar();weeklyCalendar.setDaysExcluded(new boolean[]{false,false,false,false,false,false,false});weeklyCalendar.setDayExcluded(java.util.Calendar.WEDNESDAY,true);return weeklyCalendar.isTimeIncluded(timestamp);}};private static final Calendar WEEKDAY_EXCLUDE = new Calendar() {@Overridepublic boolean isTimeIncluded(long timestamp) {WeeklyCalendar weeklyCalendar = new WeeklyCalendar();weeklyCalendar.setDaysExcluded(new boolean[]{false,false,false,false,false,false,false});return weeklyCalendar.isTimeIncluded(timestamp);}};}
package com.calenderTestrule "test-calender-rule"
calendars "weekday"
whenthenSystem.out.println("test-calender-rule 被触发");
endrule "test-calender-rule-1"
calendars "weekday_exclude"
whenthenSystem.out.println("test-calender-rule-1 被触发");
end

6.9、declare 用法:

package com.newType
import java.util.Date;rule "new-type-rule-1"when$country: Country(name == "美国")
thenAddress address = new Address();address.setName(CountryName.CHINA.getFullName());address.setCity("北京");address.setNumber(100000);insert(address);endrule "new-type-rule"when$address : Address(name == CountryName.CHINA.getFullName())
thenSystem.out.println("规则被触发");enddeclare Address extends Countrynumber : Integercity : StringcrateTime : Date
enddeclare Countryname : String
enddeclare enum CountryNameCHINA("中国");fullName : String
end

6.10、meta-元数据:

 declare City@author("wmd")name : String @keyaddress: Stringend

6.11、根据不同的路径读excel决策表:

    @Testpublic void checkDrl() throws FileNotFoundException {File file = new File("E:\\GitHub\\respo\\drools-lesson\\src\\main\\resources\\decision.xls");InputStream is = new FileInputStream(file);SpreadsheetCompiler compiler = new SpreadsheetCompiler();String drl = compiler.compile(is, InputType.XLS);System.out.println(drl);}@Testpublic void checkDrl2() throws FileNotFoundException {SpreadsheetCompiler compiler = new SpreadsheetCompiler();String drl = compiler.compile(ResourceFactory.newClassPathResource("com/decision/decision.xls"), InputType.XLS);System.out.println(drl);}

6.12、如何获取kiebase 如何获取kiesession

package com.secbro2.drools.chapter6;import org.kie.api.KieServices;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.runtime.KieContainer;import java.util.Collection;
import java.util.List;
/*** @author zzs*/
public class Chapter6 {public static void main(String[] args) {KieServices kieServices = KieServices.Factory.get();KieContainer container = kieServices.getKieClasspathContainer();Results results = container.verify();List<Message> messages = results.getMessages();System.out.println("messages size:" + messages.size());for (Message msg : messages) {System.out.println("level:" + msg.getLevel() + ";text=" + msg.getText());}Collection<String> kieBaseNames = container.getKieBaseNames();for(String kieBaseName : kieBaseNames){System.out.println("kieBaseName----" + kieBaseName);Collection<String> kieSessionNamesInKieBase = container.getKieSessionNamesInKieBase(kieBaseName);for(String kieSession : kieSessionNamesInKieBase){System.out.println("kieSession-----" + kieSession);}}}
}

6.13、如何获取jar里面的规则文件,Drools中提供了一个类KieScanner,可以支持从Maven存储库动态的加载并更新规则。官方给出的例子没有很好的证明这一能力。下面我来演示一下:

package com.secbro2.drools.demo;import org.kie.api.KieServices;
import org.kie.api.builder.KieScanner;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
/*** @author zzs*/
public class Demo8 {public static void main(String[] args) throws InterruptedException {KieServices kieServices = KieServices.Factory.get();KieContainer container = kieServices.newKieContainer(kieServices.newReleaseId("com.secbro2","drools-rules","1.0-SNAPSHOT"));KieScanner kieScanner = kieServices.newKieScanner(container);kieScanner.start(1000);KieSession kieSession = container.newKieSession("all-kieSession-1");while (true){Thread.sleep(5000);int nums = kieSession.fireAllRules();System.out.println("Fire " + nums + " rules!");}}
}

6.14、获取jar包里面的规则,利用ksession动态的获取里面的不同类型的对象,通过过滤器:

package cn.abel.service;import cn.abel.model.Person;
import org.drools.core.ClassObjectFilter;
import org.kie.api.KieServices;
import org.kie.api.builder.KieScanner;
import org.kie.api.builder.ReleaseId;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;/**  * @Description:* @Author: wumingdu* @Date: 2022/5/27 10:23*/
@Service
public class ExecuteService {private KieContainer kContainer;@PostConstructpublic void setUp() {KieServices ks = KieServices.Factory.get();ReleaseId releaseId = ks.newReleaseId("cn.abel", "springboot-drools-dynamic-rules-kjar", "1.0-SNAPSHOT");kContainer = ks.newKieContainer(releaseId);KieScanner kScanner = ks.newKieScanner(kContainer);// Start the KieScanner polling the Maven repository every 10 secondskScanner.start(10000L);}public Integer execute() {KieSession kSession = kContainer.newKieSession("PersonAgeSession");kSession.setGlobal("out", System.out);kSession.insert(new Person("Dave",100));kSession.fireAllRules();Integer result = null;for (Object per : kSession.getObjects(new ClassObjectFilter(Person.class))) {if (((Person) per).getName().equals("abel")) {result = ((Person) per).getAge();}}return result;}
}

6.15 drt用法,这个,我个人觉得不好用,但是也写下吧

template header
age
type
logpackage com.us.templates;global java.util.List list;template "cheesefans"rule "Cheese fans_@{row.rowNumber}"whenPerson(age == @{age})Cheese(type == "@{type}")thenlist.add("@{log}");
end
end template

在这里插入图片描述
在这里插入图片描述

/** Copyright 2010 Red Hat, Inc. and/or its affiliates.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.us.templates;import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;import java.util.ArrayList;
import java.util.List;/*** @author  yyb*/
public class SimpleRuleTemplateExample {public static void main(String[] args) {KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();execute(kc);}public static void execute(KieContainer kc) {KieSession ksession = kc.newKieSession("TemplatesKS");//now create some test dataksession.insert(new Cheese("stilton",42));ksession.insert(new Person("michael","stilton",42));//        Young man cheddarksession.insert(new Cheese("cheddar",21));ksession.insert(new Person("michael","stilton",21));final List<String> list = new ArrayList<String>();ksession.setGlobal("list", list);ksession.fireAllRules();System.out.println(list);ksession.dispose();}
}

6.16、创建一个kjar、初始化一个jar,动态加载(这个功能,个人觉得很吊)

package com.secbro2.drools.demo;import org.drools.compiler.kie.builder.impl.InternalKieModule;
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.builder.ReleaseId;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.builder.model.KieSessionModel;
import org.kie.api.conf.EqualityBehaviorOption;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.io.Resource;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;/*** @author zzs*/
public class DynamicDrlDemo {private static final String RULES_FILE_NAME = "rules.drl";/*** 默认规则文件所在路径*/private static final String RULES_PATH = "com";/*** 规则文件内容(可以从数据库中加载)*/private static final String RULES = "package com.rules\n" +"\n" +"rule \"chapter4\"\n" +"\n" +"when\n" +"\n" +"then\n" +"\n" +"System.out.println(\"Fire the default rules for dynamic!\");\n" +"end";public static void main(String[] args) {KieServices kieServices = KieServices.Factory.get();// 指定kjar包final ReleaseId releaseId = kieServices.newReleaseId("com.secbro2", "drools-rules", "1.0.0");// 创建初始化的kjarInternalKieModule kJar = initKieJar(kieServices, releaseId);KieRepository repository = kieServices.getRepository();repository.addKieModule(kJar);KieContainer kieContainer = kieServices.newKieContainer(releaseId);KieSession session = kieContainer.newKieSession();//同一个fact第一次不命中try {session.fireAllRules();} finally {session.dispose();}System.out.println("-----first fire end-------");//新增一个规则文件kJar = createKieJar(kieServices, releaseId, new ResourceWrapper(ResourceFactory.newByteArrayResource(RULES.getBytes()), RULES_FILE_NAME));repository.addKieModule(kJar);kieContainer.updateToVersion(releaseId);//同一个fact再次过滤规则:命中session = kieContainer.newKieSession();try {session.fireAllRules();} finally {session.dispose();}System.out.println("-----second fire end-------");}/*** 获取规定目录下的规则文件*/private static List<File> getRuleFiles() {List<File> list = new ArrayList<>();URL url = Thread.currentThread().getContextClassLoader().getResource("");if (url == null) {return list;}String filePath = url.getPath();File rootDir = new File(filePath);File[] files = rootDir.listFiles();if (files == null) {return list;}for (File itemFile : files) {if (itemFile.isDirectory() && itemFile.getName().equals(RULES_PATH)) {File[] childrenFile = itemFile.listFiles();if (childrenFile != null) {for (File f : childrenFile) {if (f.getName().endsWith(".drl")) {list.add(f);}}}}}return list;}/*** 初始化一个kjar:把原有的drl包含进新建的kjar中** @param ks* @param releaseId*/public static InternalKieModule initKieJar(KieServices ks, ReleaseId releaseId) {KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);kfs.writePomXML(getPom(releaseId));for (File file : getRuleFiles()) {kfs.write("src/main/resources/" + file.getName(),ResourceFactory.newClassPathResource(RULES_PATH + File.separator + file.getName(), "UTF-8"));}KieBuilder kieBuilder = ks.newKieBuilder(kfs);if (!kieBuilder.buildAll().getResults().getMessages().isEmpty()) {throw new IllegalStateException("Error creating KieBuilder.");}return (InternalKieModule) kieBuilder.getKieModule();}public static InternalKieModule createKieJar(KieServices ks, ReleaseId releaseId, ResourceWrapper resourceWrapper) {KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);kfs.writePomXML(getPom(releaseId));kfs.write("src/main/resources/" + resourceWrapper.getTargetResourceName(), resourceWrapper.getResource());KieBuilder kieBuilder = ks.newKieBuilder(kfs);if (!kieBuilder.getResults().getMessages().isEmpty()) {System.out.println(kieBuilder.getResults().getMessages());throw new IllegalStateException("Error creating KieBuilder.");}return (InternalKieModule) kieBuilder.getKieModule();}/*** 创建默认的kbase和stateful的kiesession** @param ks* @param isDefault* @return*/public static KieFileSystem createKieFileSystemWithKProject(KieServices ks, boolean isDefault) {KieModuleModel kproj = ks.newKieModuleModel();KieBaseModel kieBaseModel = kproj.newKieBaseModel("KBase").setDefault(isDefault).setEqualsBehavior(EqualityBehaviorOption.EQUALITY).setEventProcessingMode(EventProcessingOption.STREAM);// Configure the KieSession.kieBaseModel.newKieSessionModel("KSession").setDefault(isDefault).setType(KieSessionModel.KieSessionType.STATEFUL);KieFileSystem kfs = ks.newKieFileSystem();kfs.writeKModuleXML(kproj.toXML());return kfs;}/*** 创建kjar的pom** @param releaseId    maven* @param dependencies 依赖* @return*/public static String getPom(ReleaseId releaseId, ReleaseId... dependencies) {StringBuilder pom = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"+ "         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"+ "  <modelVersion>4.0.0</modelVersion>\n" + "\n" + "  <groupId>" + releaseId.getGroupId()+ "</groupId>\n" + "  <artifactId>" + releaseId.getArtifactId() + "</artifactId>\n" + "  <version>"+ releaseId.getVersion() + "</version>\n" + "\n");if (dependencies != null && dependencies.length > 0) {pom.append("<dependencies>\n");for (ReleaseId dep : dependencies) {pom.append("<dependency>\n");pom.append("  <groupId>").append(dep.getGroupId()).append("</groupId>\n");pom.append("  <artifactId>").append(dep.getArtifactId()).append("</artifactId>\n");pom.append("  <version>").append(dep.getVersion()).append("</version>\n");pom.append("</dependency>\n");}pom.append("</dependencies>\n");}pom.append("</project>");return pom.toString();}static class ResourceWrapper {private Resource resource;private String targetResourceName;public ResourceWrapper(Resource resource, String targetResourceName) {this.resource = resource;this.targetResourceName = targetResourceName;}public Resource getResource() {return resource;}public String getTargetResourceName() {return targetResourceName;}public void setResource(Resource resource) {this.resource = resource;}public void setTargetResourceName(String targetResourceName) {this.targetResourceName = targetResourceName;}}
}

决策表长什么样?截图看看
在这里插入图片描述

7、drools如何结合 规则流呢?
drools引擎控制规则分组,以及规则执行先后次序的方法有多种。
第一种:salience
第二种:ruleflow-group 如下图:(流程的编写可以使用drools的eclipse插件可视化的完成。)
官网参考地址:http://www.jboss.org/drools/drools-flow

rule "XX"
ruleflow-group "A"...then...
end

注意:第二种比较复杂,结合流程图,可以完成很复杂的商业逻辑:

下面详细聊聊其用法:


http://chatgpt.dhexx.cn/article/YlGyGXDC.shtml

相关文章

Drools基本介绍,入门案例,基本语法

目录 经典需求与场景 需求 传统做法-if 传统做法-策略 问题&#xff1f; 规则引擎 概念 起源 原理--基于 rete 算法的规则引擎 规则引擎应用场景 Drools 介绍 消费赠送积分案例 第一步&#xff1a; 创建工程&#xff0c;引入jar 创建 drools 自动配置类 订单实体…

Drools 简介

序 现实生活中&#xff0c;规则无处不在。对于某些企业级应用&#xff0c;诸如欺诈检测软件&#xff0c;购物车&#xff0c;活动监视器&#xff0c;信用和保密应用之类的系统&#xff0c;经常会有大量的、错综复杂的业务规则配置&#xff0c;而且随着企业管理者的决策变化&…

drools 介绍

1 .场景 1.1需求 商城系统消费赠送积分 100元以下, 不加分 100元-500元 加100分 500元-1000元 加500分 1000元 以上 加1000分 ...... 1.2传统做法 1.2.1 if...else if (order.getAmout() < 100){ order.setScore(0); addScore(order); }else if(order.getAmo…

计组——定点数原码反码补码移码以及它们之间的转换

原码 用尾数表示真值的绝对值&#xff0c;符号位“0/1”对应“正/负” 若机器字长n1位&#xff0c;原码整数的表示范围&#xff1a; − ( 2 n − 1 ) ≤ x ≤ 2 n − 1 {\color{Red} -(2^{n}-1)\leq x\leq 2^{n}-1} −(2n−1)≤x≤2n−1&#xff08;关于原点对称&#xff09;…

数据的表示:原码、反码、补码、移码以及浮点数的运算

前言 复习到数据表示方面相关的知识&#xff0c;所以在这里做一下记录&#xff0c;也方便大家参考。 什么是 R 进制 对于 R 机制&#xff0c;如果要实现与十进制的转换&#xff0c;则使用 按权展开法&#xff0c;其具体操作为&#xff1a; 将 R 进制数的每一位数值用 R k R…

五分钟理解原码补码反码和移码

这是计算机的基本知识了&#xff0c;一定要好好学。哈哈废话不多说&#xff0c;直接进入正题吧。计算机中有无符号数和有符号数两大类。 有符号数就是正负数&#xff0c;在计算机中正好用0和1分别去代表正和负。(ps:好多人不理解机器数和真值&#xff0c;机器数就是把符号数字…

原码、反码、补码、移码的表示

若字长n为8时&#xff0c;那么45的二进制表示0 0101101 &#xff0c;若数值X 1.原码 [X]原&#xff0c;在二进制数值中&#xff0c;正数保持不变&#xff0c;负数符号位置1. 2.反码 [X]反&#xff0c;的正数保持不变 &#xff0c; 负数对数值的绝对值每一位按位求反 3.补码…

关于补码移码各自和原码的联系、来历、功能及I EEE754标准中移码范围问题

最近在学习计算机组成原理时,遇到一些问题,记录在此。 如果你对下面这段话有疑惑或者兴趣&#xff0c;我或许能说点什么你感兴趣的。 真值-128的补码&#xff1a;1000 0000&#xff0c;这个补码本身表示的二进制数&#xff08;无符号&#xff09;是128&#xff0c;其对应着真…

移码的计算方式

规则&#xff1a;对应真值的补码的符号位取反&#xff1b; 计算公式&#xff1a; 式中&#xff1a;x为真值&#xff0c;n为整数的位数&#xff1b; 形式上补码是先减后增的&#xff0c;移码是递增的&#xff1b;根据人类的习惯&#xff0c;移码可以清楚的反映对应真值的大小…

计算机组成原理学习笔记:定点数、浮点数、原码、反码、补码、移码

定点数与浮点数 所谓定点数就是指小数点的位置固定不变而浮点数是小数点的位置是不固定的&#xff0c;会浮动 1 ) 定点数 用熟悉的十进制数来类比&#xff0c;定点数就是我们平时更习惯使用的常规的计数方式&#xff0c;我们会显式的标明小数点的位置Eg: 110.12 2 &#xf…

原码,补码,移码

一、原码 ①最高位为符号位&#xff0c;0表示正数&#xff0c;1表示负数&#xff1b; ②除符号位其它数值部分&#xff0c;就是数值本身绝对值的二进制数&#xff1b; ③负数的原码是在其绝对值得的基础上&#xff0c;符号位变为1&#xff1b; 但是&#xff1a; 0的表示不唯一&…

移码补码原理

计算机中的“数”&#xff0c;花样很多&#xff0c;又是ASCII码、又是BCD码等等&#xff0c;下面&#xff0c;做而论道写了一些关于移码、补码的一些看法&#xff0c;欢迎拍砖。 机器数 计算机中的“数”&#xff0c;其实都不是数字&#xff0c;它们都是一些高、低电平。其中&a…

浮点数与移码

浮点数的组成和计数原理 浮点数是什么浮点数的表示与规定浮点数的规定&#xff08;IEEE754 标准&#xff09;浮点数的表示范围&#xff08;IEE7标准瞎&#xff09;阶码用移码表示 浮点数是什么 浮点数就是小数点可以任意浮动的数字。   因为在计算机的机器语言中&#xff0c;…

图神经网络时代的深度聚类

©PaperWeekly 原创 作者&#xff5c;纪厚业 学校&#xff5c;北京邮电大学博士生 研究方向&#xff5c;图神经网络和推荐系统 聚类作为经典的无监督学习算法在数据挖掘/机器学习的发展历史中留下了不可磨灭的印记。其中&#xff0c;经典的聚类算法 K-Means 也被选为数据挖…

聊聊测试工程师的核心能力模型

这是鼎叔的第二篇原创文章。 行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。 多年大厂技术总监和质量通道委员经验&#xff0c;横跨多个不同领域&#xff0c;微信公众号“敏捷测试转型”&#xff0c;欢迎多多交流。 鼎叔过往接触过各个团队的测试&#xff08;测试开发&…

对比学习有多火?文本聚类都被刷爆了…

文 | 花小花Posy 大家好&#xff0c;我是小花。 对比学习的大火???? 越来越旺了&#xff0c;已然从CV蔓延到NLP了。今天给大家介绍的正是一篇将对比学习应用到文本聚类上的工作&#xff0c;NAACL21新鲜出炉的paper——《Supporting Clustering with Contrastive Learning》…

(附源码)小程序 记账微信小程序 毕业设计 180815

记账微信小程序 摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;记账微信小程序被用户普遍使用&#xff0…

使用Python+OpenCV+Tensorflow实现图像聚类

介绍 大家好&#xff0c;最近在参加深度学习竞赛时&#xff0c;遇到了一个有趣的问题&#xff0c;即如何将给定的图像集进行聚类&#xff0c;你可能会说&#xff0c;这不是一个简单的分类问题吗&#xff1f;使用卷积神经网络&#xff0c; 就实现&#xff0c;但关键在于没有合适…

论文阅读笔记(15):Deep Subspace Clustering with Data Augmentation,深度子空间聚类+数据增强

论文阅读笔记&#xff08;15&#xff09;&#xff1a;Deep Subspace Clustering with Data Augmentation&#xff0c;深度子空间聚类数据增强 摘要1 介绍2 相关工作带增强的聚类方法具有一致性损失的自监督子空间聚类中的自表达模型 3 深度子空间聚类数据增强总结 4 寻找有效增…

【SaaS金羊毛】微信小程序We分析

微信前几天发布了通告https://mp.weixin.qq.com/cgi-bin/announce?actiongetannouncement&announce_id11652079103ziYFG&version&langzh_CN&token&#xff0c;小程序统计模块会升级为”We分析“这样一款独立的产品。实际上这也符合很多B端产品的趋势&#xff…