配置:
路径:resources/META-INF/kmodule.xml
<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="myKbase" packages="rules" default="true">
<ksession name="ksession-rule" default="true"/>
</kbase>
</kmodule>
1、DroolsConfig:
package com.drools;
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.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.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
/**
* decription 规则引擎配置类
* @author wangjingjing
* @date 2020/7/31 10:07
*/
@Configuration
public class DroolsConfig {
private static final String RULE_PATH = "rules/";
private final KieServices kieServices = KieServices.Factory.get();
@Bean
public KieServices getKieServices(){
return kieServices;
}
@Bean
@ConditionalOnMissingBean
public KieFileSystem kieFileSystem() throws IOException {
System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm");
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULE_PATH + "*.drl");
String path = null;
for (Resource file : files) {
path = RULE_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
public KModuleBeanFactoryPostProcessor kiePostProcessor() {
return new KModuleBeanFactoryPostProcessor();
}
}
2、RuleService:
package com.drools;
import com.haidilao.edge.config.ConstantConfig;
import com.haidilao.edge.rabbitmq.DirectProducer;
import com.haidilao.edge.vo.ServiceMessage;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RuleService {
@Autowired
private KieBase kieBase;
@Autowired
private DirectProducer directProducer;
public void ruleByName(ServiceMessage obj,String ruleName) {
KieSession kieSession = kieBase.newKieSession();
kieSession.insert(obj);
kieSession.setGlobal("topic", ConstantConfig.SERVICE_DOWNLINK_TOPIC);
kieSession.setGlobal("directProducer", directProducer);
//todo 后期不用过滤
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter(ruleName));
kieSession.dispose();
}
public void rule() {
KieSession kieSession = kieBase.newKieSession();
kieSession.setGlobal("topic", ConstantConfig.SERVICE_DOWNLINK_TOPIC);
kieSession.setGlobal("directProducer", directProducer);
kieSession.fireAllRules();
kieSession.dispose();
}
}
3、rule文件配置:
路径:resources/rules/Mqtt.drl
import com.vo.ServiceMessage
import com.config.ConstantConfig
import com.rabbitmq.DirectProducer
global String topic
global DirectProducer directProducer
rule "Mqtt"
when
$msg:ServiceMessage(identify == "order")
then
JSONObject jsonObject=new JSONObject();
String payload="触发事件上报内容";
jsonObject.put("identify","触发事件");
jsonObject.put("payload",payload);
System.out.println("directProducer:"+directProducer+";$msg:"+$msg);
directProducer.sendDirectMessage($msg.getPayload(), ConstantConfig.DIRECT_EXCHANGE, ConstantConfig.ROUTING);
MqttClientInit.getEmqInstance(true).publish($msg.getTopic().replace("output","input"), payload.getBytes(), 1, true);
System.out.println($msg.getIdentify()+"mqtt消息规则触发。。。。。");
end
4、controller:
@Autowired
private RuleService ruleService;
@RequestMapping("/testRule")
@ResponseBody
public String testTule() {
ruleService.rule();
return "ok";
}
5、实现规则热部署:
a、热部署配置ReloadDroolsRules:
package com.drools;
import org.drools.core.util.StringUtils;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class ReloadDroolsRules {
@Autowired
private KieContainer kieContainer;
@Autowired
private KieServices kieServices;
@Autowired
private KieFileSystem kieFileSystem;
private static final String RULE_PATH = "rules/";
public void reload(String drlName) throws Exception {
// loadDBRules(drlName, kfs);
loadFileRules(drlName, kieFileSystem);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
System.out.println(results.getMessages());
throw new IllegalStateException("### errors ###");
}
kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
System.out.println("新规则重载成功");
}
private void loadDBRules(String drlName, KieFileSystem kfs) {
// String path = "src/main/resources/rules/address.drl";
String path = "src/main/resources/" + RULE_PATH + "/" + drlName + ".drl";
// 从数据库加载的规则
kfs.write(path, "package plausibcheck.adress\n\n import com.neo.drools.model.Address;\n import com.neo.drools.model.fact.AddressCheckResult;\n\n rule \"Postcode 6 numbers\"\n\n when\n then\n System.out.println(\"打印日志:更新rules成功!\");\n end");
}
private void loadFileRules(String drlName, KieFileSystem kfs) throws IOException {
// 从classess/rules加载的规则
for (Resource file : getRuleFiles(drlName)) {
kfs.write(ResourceFactory.newClassPathResource(RULE_PATH + file.getFilename(), "UTF-8"));
}
}
private Resource[] getRuleFiles(String drlName) throws IOException {
if (StringUtils.isEmpty(drlName)) {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources(RULE_PATH + "**/*.*");
}
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources(RULE_PATH + "**/" + drlName + ".*");
}
}
b、调用热部署接口:我这里采用文件上传的方式:
@RequestMapping("/updateDrlFile")
@ResponseBody
public String updateDrlFile(HttpServletRequest request, MultipartFile file, @RequestParam("drlName") String drlName) throws Exception {
//更新drl后,再调用reload方法重载。即可热部署
String path = ResourceUtils.getURL("classpath:").getPath() + "rules/" + file.getOriginalFilename();
System.out.println("规则上传目录:" + path+",请注意每次规则热部署后要往项目路径里也放入一份,避免重启后规则丢失");
File dest = new File(path);
file.transferTo(dest);
reloadDroolsRules.reload(drlName);
return "ok";
}
好啦~完成!
奥对了,maven配置也加上吧!
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wangjingjing</groupId>
<artifactId>drools-study</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>drools-study</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<commons.lang3.version>3.4</commons.lang3.version>
<fastjson.version>1.2.50</fastjson.version>
<fasterxml.jackson.version>2.10.1</fasterxml.jackson.version>
<gson.version>2.8.6</gson.version>
<jslf4j-log4j12.version>1.7.7</jslf4j-log4j12.version>
<nekohtml.version>1.9.22</nekohtml.version>
<guava.version>28.1-jre</guava.version>
<ons-client.version>1.8.4.Final</ons-client.version>
<drools-compiler.version>7.40.0.Final</drools-compiler.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--drools开始 -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${drools-compiler.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>${drools-compiler.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${drools-compiler.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${drools-compiler.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--drools结束 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${jslf4j-log4j12.version}</version>
</dependency>
<!-- spring boot web 的 html 支持依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- thymeleaf使用非严格的html依赖 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>${nekohtml.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.openservices</groupId>
<artifactId>ons-client</artifactId>
<version>${ons-client.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>iot-common</warName>
<webResources>
<resource>
<directory>lib/</directory>
<targetPath>WEB-INF/lib</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
以上!如有问题,欢迎交流~