Flowable是BPMN的一个基于Java的软件实现,但是不仅仅限于BPMN,还有DMN决策表和CMMN Case管理引擎,并且有自己的用户管理,微服务API的功能,是一个服务平台。
是由开发了Acitivity6的开发人员,再次升级开发的。
<dependencies>
<dependency>
<groupId>org.flowablegroupId>
<artifactId>flowable-engineartifactId>
<version>6.3.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.49version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.21version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.1.7version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.1.7version>
dependency>
dependencies>
@Test
public void testProcessEngine(){
// 流程配置对象
ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();
// 数据库配置
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8");
// 配置如果表结构不存在就新建
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 构造核心流程对象
ProcessEngine processEngine = configuration.buildProcessEngine();
System.err.println(processEngine);
}
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/logFile.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="APP_NAME" value="MY_APP_NAME" />
<property name="LOG_DIR" value="logs" />
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{15} - %msg%n" />
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %boldYellow([%thread]) %cyan(%logger{15}) %msg%n"/>
<contextName>${APP_NAME}contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}pattern>
encoder>
appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/logFile.logfile>
<append>trueappend>
<encoder>
<pattern>${FILE_LOG_PATTERN}pattern>
encoder>
appender>
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/dayLogFile.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>30maxHistory>
rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}pattern>
encoder>
appender>
<logger name="com.example.Logger1" level="DEBUG" additivity="true">
logger>
<logger name="com.example.Logger2" level="DEBUG" additivity="false">
logger>
<logger name="com.example.Logger3" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
logger>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
<appender-ref ref="RollingFile" />
root>
configuration>
使用官方给的请假测试流程。
流程图说明
resource
文件夹下,并命名为holiday-request.bpmn20.xml
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<userTask id="approveTask" name="Approve or reject request"/>
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
<conditionExpression xsi:type="tFormalExpression">
conditionExpression>
sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
<conditionExpression xsi:type="tFormalExpression">
conditionExpression>
sequenceFlow>
<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="org.flowable.CallExternalSystemDelegate"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
<userTask id="holidayApprovedTask" name="Holiday approved"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="org.flowable.SendRejectionMail"/>
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
process>
definitions>
public class DoFlowable {
ProcessEngineConfiguration configuration = null;
/**
* 获取flowable流引擎对象
*/
@Before
public void testProcessEngine(){
// 流程配置对象
configuration = new StandaloneProcessEngineConfiguration();
// 数据库配置
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8");
// 配置如果表结构不存在就新建
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
}
/**
* 部署流程
*/
@Test
public void testDeploy(){
// 获取 processEngine 对象
ProcessEngine processEngine = configuration.buildProcessEngine();
// 获取 repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取 deployment 对象
Deployment deployment = repositoryService.createDeployment()// 创建Deployment对象
.addClasspathResource("holiday-request.bpmn20.xml") // 添加流程部署文件
.name("请求流程") // 设置部署流程的名称
.deploy(); // 执行
System.err.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getName() = " + deployment.getName());
}
}
ProcessEngine
对象public class ProcessEngineUtils {
/**
* 获取flowable流引擎对象
*/
public static ProcessEngine getProcessEngine(){
// 流程配置对象
ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();
// 数据库配置
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC&nullCatalogMeansCurrent=true&useSSL=true");
// 配置如果表结构不存在就新建
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 构造核心流程对象
return configuration.buildProcessEngine();
}
}
/**
* 查询流程定义信息
*/
@Test
public void deploymentQuery(){
ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取查询对象
ProcessDefinitionQuery processQuery = repositoryService.createProcessDefinitionQuery();
// 定义查询信息(单个查询)
ProcessDefinition definition = processQuery.deploymentId("2501").singleResult();
}
/**
* 删除流程定义
*/
@Test
public void deployDel(){
ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.deleteDeployment("1"); // 删除对应id的流程,启动中不可以删除
// repositoryService.deleteDeployment("1", true); // 删除对应id的流程(包含其中的过程数据),不考虑启动状态。
}
/**
* 启动流程
*/
@Test
public void deployRun(){
// 配置传递的参数
Map<String, Object> params = new HashMap<>();
params.put("employee","王五");
params.put("days",3);
params.put("description","累了");
ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
// 1:这里的 key 对应配置文件中的 process 的 id
// 2:传递的参数
ProcessInstance holidayRequest = runtimeService.startProcessInstanceByKey("holidayRequest", params);
}
<userTask id="approveTask" name="Approve or reject request" flowable:assignee="Ekko"/>
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
/**
* 任务查询
*/
@Test
public void taskQuery(){
ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest") // 指定流程key
.taskAssignee("Ekko") // 指定处理人
.list();
for (Task task : list) {
System.out.println(task.getProcessDefinitionId());
System.out.println(task.getName());
System.out.println(task.getAssignee());
System.out.println(task.getDescription());
System.out.println(task.getId());
}
}
<!-- 同意流程节点-->
<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="com.yy.flowable.service.AppService"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
<!-- 拒绝流程让任务节点-->
<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="com.yy.flowable.service.RejectService"/>
<!-- 拒绝-指向结束-->
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
/**
* @author : JinMing Zhou
* @description: 通过类
* @date : 2023/1/9 17:48
*/
public class AppService implements JavaDelegate {
/**
* 触发器,流程走到这里执行该方法
* @param delegateExecution
*/
@Override
public void execute(DelegateExecution delegateExecution) {
// 通过,执行逻辑
System.out.println("通过。");
}
}
/**
* @author : JinMing Zhou
* @description: 拒绝类
* @date : 2023/1/9 17:48
*/
public class RejectService implements JavaDelegate {
/**
* 请假流程拒绝触发器
* @param delegateExecution
*/
@Override
public void execute(DelegateExecution delegateExecution) {
System.err.println("不给通过!");
}
}
/**
* 处理流程
*/
@Test
public void completeTask(){
// 指定审批参数
Map<String, Object> params = new HashMap<>();
params.put("approved",false);
ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 查询任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest") // 指定流程key
.taskAssignee("Ekko") // 指定处理人
.singleResult();
// 处理操作
taskService.complete(task.getId(), params);
}
/**
* 历史信息查询
*/
@Test
public void historyQuery(){
ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.processDefinitionId("holidayRequest:1:17503")
.finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();
for (HistoricActivityInstance historicActivityInstance : list) {
System.err.println(historicActivityInstance.getActivityId() + " took "
+ historicActivityInstance.getDurationInMillis() + " milliseconds");
}
}