SpringBoot入门建站全系列(三十四)使用Drools规则引擎做排班系统
一、概述
Drools 是用 Java 语言编写的开放源码规则引擎,使用 Rete 算法对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。
总结一句,Drools就是使用已经写好的规则,对业务代码中提交给引擎保管的bean做筛选,筛选后的结果,就是我们想要的结果,例如排班系统,可以将人员存储到引擎中,然后按照排班规则(drl文件)对人员进行筛选归类。
Drools排班的简单示例,可以在Spring组件化构建的Drools组件中查看并下载。
首发地址: 品茗IT: https://www.pomit.cn/p/2486115243215361
如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。
下面我们来处理下面这种场景(该场景是从网上找来的,部分源码做了改动保证可运行):
场景:
- 员工分为两种:司机,外勤
- 每天分白、中、晚三个班次
- 每班 3 人,一个司机,两个外勤
规则:
获取到人员排班信息。
二、基本配置
Drools的规则可以配置在XML和drl文件中,也可以从表里取,这里先讲下如何从表里取规则并应用。
2.1 Maven依赖
需要引入数据库相关配置和drools相关jar包,还要引入kie-api.
<dependency>
这样写,maven依赖不保证完全下载下来,有个jboss的jar包可能下载不下来,可以在pom.xml中多配置一个:
<repositories>
2.2 配置文件
在application.properties 中需要配置数据库相关信息的信息,如:
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.dbcp2.max-wait-millis=60000
spring.datasource.dbcp2.min-idle=20
spring.datasource.dbcp2.initial-size=2
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.test-while-idle=true
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.test-on-return=false
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/cff?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=cff
spring.datasource.password=123456
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
spring.autoconfigure.exclude=org.activiti.spring.boot.SecurityAutoConfiguration
这只是数据库的配置而已,没有drools的配置。
三、 Drools规则引擎实体
按照前面说到的场景。
场景:
- 员工分为两种:司机,外勤
- 每天分白、中、晚三个班次
- 每班 3 人,一个司机,两个外勤
3.1 排期实体
因为要排班,首先要确定排班日历,实体如下。
WorkDate:
package
3.2 排班对象实体
我们新建一个实体Worker。
Worker:
package
3.3 班次实体
建立班次实体,保存排期及worker对象。
Shift:
package
四、排班规则
这个规则可以存储到数据库中,也可以写到配置文件中,这里是写到数据库中,规则如下:
4.1 规则
package com.cff.springbootwork.drools
import com.cff.springbootwork.drools.domain.work.*;
rule "司机"
when
shift : Shift(driver == null, $date : workDate, $no : no)
worker : Worker(type == 1, easyDay >= 6, maxDay <= 4, $total : shiftTotal )
eval( !shift.getWorkDate().containsWorker(worker) )
not Worker(type == 1, shiftTotal < $total )
not Shift(driver == null, workDate.day < $date.day)
not Shift(driver == null, workDate.day == $date.day, no < $no )
then
shift.setDriver( worker );
worker.addShift( shift );
update( shift );
update( worker );
end
rule "外勤 1"
when
shift : Shift(assistant1 == null, $date : workDate, $no : no)
worker : Worker(easyDay >= 6, maxDay <= 4, $total : shiftTotal)
eval( !shift.getWorkDate().containsWorker(worker) )
not Worker( shiftTotal < $total )
not Shift(assistant1 == null, workDate.day < $date.day)
not Shift(assistant1 == null, workDate.day == $date.day, no < $no )
then
shift.setAssistant1( worker );
worker.addShift( shift );
update( shift );
update( worker );
end
rule "外勤 2"
when
shift : Shift(assistant2 == null, $date : workDate, $no : no)
worker : Worker(easyDay >= 6, maxDay <= 4, total : shiftTotal)
eval( !shift.getWorkDate().containsWorker(worker) )
not Worker( shiftTotal < total )
not Shift(assistant2 == null, workDate.day < $date.day)
not Shift(assistant2 == null, workDate.day == $date.day, no < $no )
then
shift.setAssistant2( worker );
worker.addShift( shift );
update( shift );
update( worker );
end
rule "移除班次"
when
shift : Shift()
eval( shift.isDone() )
then
retract( shift );
end
这里:
- Worker(type == 1 表示worker是司机。easyDay >= 6, maxDay <= 4限定要筛选的worker休息日在6天以上,连续工作日在5天以下。
- not 关键字表示,非,就是表示满足not后面规则的实体需要被过滤掉。
- update关键字表示更新满足规则的实体。
- eval关键字表示过滤调返回值是false的实体。
4.2 规则入库
将规则存储到drools_rule文件中,建表语句如下:
CREATE TABLE `drools_rule` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) CHARACTER SET utf8mb4 DEFAULT NULL,
`rule` text CHARACTER SET utf8mb4,
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`visible` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
4.3 规则CRUD
普通mybatis查询而已。
RulesDao:
package
4.3 规则实体
普通实体,与数据库表字段对应而已,无特别意义。
package
五、规则引擎的使用
这里,
- 先建立实体列表、日历和班次列表;
- 从数据库读规则并应用,返回KieSession;
- KieSession将所有实体插入并应用上面所述规则;
- 打印排班结果。
ShiftService:
package
六、测试
建立测试web
ShiftController:
package
七、其他实体
ShiftRes :
package
ResultModel :
package
SpringBoot入门建站全系列(三十四)使用Drools规则引擎做排班系统
一、概述
Drools 是用 Java 语言编写的开放源码规则引擎,使用 Rete 算法对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。
总结一句,Drools就是使用已经写好的规则,对业务代码中提交给引擎保管的bean做筛选,筛选后的结果,就是我们想要的结果,例如排班系统,可以将人员存储到引擎中,然后按照排班规则(drl文件)对人员进行筛选归类。
Drools排班的简单示例,可以在Spring组件化构建的Drools组件中查看并下载。
如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以 加入我们的java学习圈,点击即可加入 ,共同学习,节约学习时间,减少很多在学习中遇到的难题。
下面我们来处理下面这种场景(该场景是从网上找来的,部分源码做了改动保证可运行):
场景:
- 员工分为两种:司机,外勤
- 每天分白、中、晚三个班次
- 每班 3 人,一个司机,两个外勤
规则:
获取到人员排班信息。
二、基本配置
Drools的规则可以配置在XML和drl文件中,也可以从表里取,这里先讲下如何从表里取规则并应用。
2.1 Maven依赖
需要引入数据库相关配置和drools相关jar包,还要引入kie-api.
<dependency>
这样写,maven依赖不保证完全下载下来,有个jboss的jar包可能下载不下来,可以在pom.xml中多配置一个:
<repositories>
2.2 配置文件
在application.properties 中需要配置数据库相关信息的信息,如:
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.dbcp2.max-wait-millis=60000
spring.datasource.dbcp2.min-idle=20
spring.datasource.dbcp2.initial-size=2
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.test-while-idle=true
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.test-on-return=false
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/cff?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=cff
spring.datasource.password=123456
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
spring.autoconfigure.exclude=org.activiti.spring.boot.SecurityAutoConfiguration
这只是数据库的配置而已,没有drools的配置。
三、 Drools规则引擎实体
按照前面说到的场景。
场景:
- 员工分为两种:司机,外勤
- 每天分白、中、晚三个班次
- 每班 3 人,一个司机,两个外勤
3.1 排期实体
因为要排班,首先要确定排班日历,实体如下。
WorkDate:
package
3.2 排班对象实体
我们新建一个实体Worker。
Worker:
package
3.3 班次实体
建立班次实体,保存排期及worker对象。
Shift:
package
四、排班规则
这个规则可以存储到数据库中,也可以写到配置文件中,这里是写到数据库中,规则如下:
4.1 规则
package com.cff.springbootwork.drools
import com.cff.springbootwork.drools.domain.work.*;
rule "司机"
when
shift : Shift(driver == null, $date : workDate, $no : no)
worker : Worker(type == 1, easyDay >= 6, maxDay <= 4, $total : shiftTotal )
eval( !shift.getWorkDate().containsWorker(worker) )
not Worker(type == 1, shiftTotal < $total )
not Shift(driver == null, workDate.day < $date.day)
not Shift(driver == null, workDate.day == $date.day, no < $no )
then
shift.setDriver( worker );
worker.addShift( shift );
update( shift );
update( worker );
end
rule "外勤 1"
when
shift : Shift(assistant1 == null, $date : workDate, $no : no)
worker : Worker(easyDay >= 6, maxDay <= 4, $total : shiftTotal)
eval( !shift.getWorkDate().containsWorker(worker) )
not Worker( shiftTotal < $total )
not Shift(assistant1 == null, workDate.day < $date.day)
not Shift(assistant1 == null, workDate.day == $date.day, no < $no )
then
shift.setAssistant1( worker );
worker.addShift( shift );
update( shift );
update( worker );
end
rule "外勤 2"
when
shift : Shift(assistant2 == null, $date : workDate, $no : no)
worker : Worker(easyDay >= 6, maxDay <= 4, total : shiftTotal)
eval( !shift.getWorkDate().containsWorker(worker) )
not Worker( shiftTotal < total )
not Shift(assistant2 == null, workDate.day < $date.day)
not Shift(assistant2 == null, workDate.day == $date.day, no < $no )
then
shift.setAssistant2( worker );
worker.addShift( shift );
update( shift );
update( worker );
end
rule "移除班次"
when
shift : Shift()
eval( shift.isDone() )
then
retract( shift );
end
这里:
- Worker(type == 1 表示worker是司机。easyDay >= 6, maxDay <= 4限定要筛选的worker休息日在6天以上,连续工作日在5天以下。
- not 关键字表示,非,就是表示满足not后面规则的实体需要被过滤掉。
- update关键字表示更新满足规则的实体。
- eval关键字表示过滤调返回值是false的实体。
4.2 规则入库
将规则存储到drools_rule文件中,建表语句如下:
CREATE TABLE `drools_rule` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) CHARACTER SET utf8mb4 DEFAULT NULL,
`rule` text CHARACTER SET utf8mb4,
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`visible` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
4.3 规则CRUD
普通mybatis查询而已。
RulesDao:
package
4.3 规则实体
普通实体,与数据库表字段对应而已,无特别意义。
package
五、规则引擎的使用
这里,
- 先建立实体列表、日历和班次列表;
- 从数据库读规则并应用,返回KieSession;
- KieSession将所有实体插入并应用上面所述规则;
- 打印排班结果。
ShiftService:
package
六、测试
建立测试web
ShiftController:
package
七、其他实体
ShiftRes :
ResultModel :
详细实体及完整代码,可以访问《SpringBoot入门建站全系列(三十四)使用Drools规则引擎做排班系统》查看完整文章
快速构建项目
Spring项目快速开发工具:
一键快速构建Spring项目工具
一键快速构建SpringBoot项目工具
一键快速构建SpringCloud项目工具
一站式Springboot项目生成
Mysql一键生成Mybatis注解Mapper
Spring组件化构建
SpringBoot组件化构建
SpringCloud服务化构建