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
注意:第二种比较复杂,结合流程图,可以完成很复杂的商业逻辑:
下面详细聊聊其用法: