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
@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();
}
}
根据文件,不管是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