Flowable 是 BPMN 的一个基于 java 的软件实现,不过 Flowable 不仅仅包括 BPMN ,还有DMN 决策表和 CMMN Case 管理引擎,并且有自己的用户管理、微服务 API 等一系列功能,是一个服务平台。官方手册: https://tkjohn.github.io/flowable-userguide/#_introduction
org.flowable
flowable-engine
6.3.0
mysql
mysql-connector-java
8.0.21
然后创建一个普通的 Java 类,添加对应的 main 方法,首先要做的是初始化ProcessEngine 流程引擎实例。这是一个线程安全的对象,因此通常只需要在一个应用中初始化一次。 ProcessEngine 由 ProcessEngineConfiguration 实例创建。该实例可以配置与调整流程引擎的设置。 通常使用一个配置 XML 文件创建 ProcessEngineConfiguration ,但是(像在这里做的一样)也可以编程方式创建它。 ProcessEngineConfiguration 所需的最小配置,是数据库 JDBC 连接:
public static void main(String[] args) {
ProcessEngineConfiguration cfg = new
StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?
serverTimezone=UTC") //5.6
.setJdbcUsername("root")
.setJdbcPassword("root")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRU
E);
ProcessEngine processEngine = cfg.buildProcessEngine();
}
注意在mysql8.0中执行可能出现如下的错误
出现这种情况只需要在 mysql 的连接字符串中添加上nullCatalogMeansCurrent=true ,设置为只查当前连接的 schema 库即可。jdbc:mysql://localhost:3306/flowable_learn?serverTimezone=UTC&nullCatalogMeansCurrent=true
org.slf4j
slf4j-api
1.7.21
org.slf4j
slf4j-log4j12
1.7.21
log4j.rootLogger=DEBUG, CA
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p
%c %x - %m%n
- 我们假定启动流程需要提供一些信息,例如雇员名字、请假时长以及说明。当然,这些 可以单独建模为流程中的第一步。 但是如果将它们作为流程的“输入信息”,就能保证 只有在实际请求时才会建立一个流程实例。否则(将提交作为流程的第一步),用户可 能在提交之前改变主意并取消,但流程实例已经创建了。 在某些场景中,就可能影响重
- 要的指标(例如启动了多少申请,但还未完成),取决于业务目标。
- 左侧的圆圈叫做启动事件(start event)。这是一个流程实例的起点。
- 第一个矩形是一个用户任务(user task)。这是流程中用户操作的步骤。在这个例子 中,经理需要批准或驳回申请
- 取决于经理的决定,排他网关(exclusive gateway) (带叉的菱形)会将流程实例路由至 批准或驳回路径
- 如果批准,则需要将申请注册至某个外部系统,并跟着另一个用户任务,将经理的决定
- 通知给申请人。当然也可以改为发送邮件。
- 如果驳回,则为雇员发送一封邮件通知他。
/**
* 部署流程
*/
@Test
public void testDeploy(){
// 配置数据库相关信息 获取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new
StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowablelearn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRU
E);
// 获取流程引擎对象
ProcessEngine processEngine = cfg.buildProcessEngine();
// 部署流程 获取RepositoryService对象
RepositoryService repositoryService =
processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()// 创
建Deployment对象
.addClasspathResource("holiday-request.bpmn20.xml") // 添
加流程部署文件
.name("请求流程") // 设置部署流程的名称
.deploy(); // 执行部署操作
System.out.println("deployment.getId() = " +
deployment.getId());
System.out.println("deployment.getName() = " +
deployment.getName());
}
act_re_procdef :流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
act_ge_bytearray :流程资源表,流程部署的 bpmn文件和png图片会保存在该表中
/**
* 查看流程定义
*/
@Test
public void testDeployQuery(){
// 配置数据库相关信息 获取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new
StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowablelearn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRU
E);
// 获取流程引擎对象
ProcessEngine processEngine = cfg.buildProcessEngine();
// 部署流程 获取RepositoryService对象
RepositoryService repositoryService =
processEngine.getRepositoryService();
// 获取流程定义对象
输出结果为:
3.启动流程实例
现在已经在流程引擎中部署了流程定义,因此可以使用这个流程定义作为“模板”启动流
程实例。
要启动流程实例,需要提供一些初始化流程变量。一般来说,可以通过呈现给用户的表
单,或者在流程由其他系统自动触发时通过REST API,来获取这些变量。在这个例子里,我
们简化直接在代码中定义了,我们使用RuntimeService启动一个流程实例。
ProcessDefinition processDefinition =
repositoryService.createProcessDefinitionQuery()
.deploymentId("2501")
.singleResult();
System.out.println("processDefinition.getId() = " +
processDefinition.getId());
System.out.println("processDefinition.getName() = " +
processDefinition.getName());
System.out.println("processDefinition.getDeploymentId() = " +
processDefinition.getDeploymentId());
System.out.println("processDefinition.getDescription() = " +
processDefinition.getDescription());
}
processDefinition.getId() = holidayRequest:2:2503processDefinition.getName() = Holiday RequestprocessDefinition.getDeploymentId() = 2501processDefinition.getDescription() = null
要启动流程实例,需要提供一些初始化 流程变量 。一般来说,可以通过呈现给用户的表单,或者在流程由其他系统自动触发时通过REST API ,来获取这些变量。在这个例子里,我们简化直接在代码中定义了,我们使用RuntimeService 启动一个 流程实例 。
/**
* 启动流程实例
*/
@Test
public void testRunProcess(){
// 配置数据库相关信息 获取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new
StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowablelearn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRU
E);
// 获取流程引擎对象
ProcessEngine processEngine = cfg.buildProcessEngine();
// 启动流程实例通过 RuntimeService 对象
RuntimeService runtimeService =
processEngine.getRuntimeService();
// 构建流程变量
Map variables = new HashMap<>();
variables.put("employee","张三") ;// 谁申请请假
variables.put("nrOfHolidays",3); // 请几天假
variables.put("description","工作累了,想出去玩玩"); // 请假的原因
// 启动流程实例,第一个参数是流程定义的id
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("holidayRequest",
variables);// 启动流程实例
// 输出相关的流程实例信息
System.out.println("流程定义的ID:" +
processInstance.getProcessDefinitionId());
System.out.println("流程实例的ID:" + processInstance.getId());
System.out.println("当前活动的ID:" +
processInstance.getActivityId());
}
流程定义的 ID : holidayRequest:2:2503流程实例的 ID : 5001当前活动的 ID : null
对应的流程实例ID为:5001
/**
* 查看任务
*/
@Test
public void testQueryTask(){
// 配置数据库相关信息 获取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowablelearn2serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 获取流程引擎对象
ProcessEngine processEngine = cfg.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
List list = taskService.createTaskQuery()
.processDefinitionKey("holidayRequestNew")
.taskAssignee("lisi")
.list();
for (Task task : list) {
System.out.println("task.getProcessDefinitionId() = " + task.getProcessDefinitionId());
System.out.println("task.getId() = " + task.getId());
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getName() = " + task.getName());
}
}
task.getProcessDefinitionId() = holidayRequestNew:1:10003task.getId() = 12508task.getAssignee() = lisitask.getName() = Approve or reject request
/**
* 完成任务
*/
@Test
public void testCompleteTask() {
// 配置数据库相关信息 获取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new
StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowablelearn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRU
E);
// 获取流程引擎对象
ProcessEngine processEngine = cfg.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("holidayRequestNew")
.taskAssignee("lisi")
.singleResult();
// 添加流程变量
Map variables = new HashMap<>();
variables.put("approved", false); // 拒绝请假
// 完成任务
taskService.complete(task.getId(), variables);
}
@Test
public void testDeleteProcess() {
// 配置数据库相关信息 获取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new
StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowablelearn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 获取流程引擎对象
ProcessEngine processEngine = cfg.buildProcessEngine();
RepositoryService repositoryService =
processEngine.getRepositoryService();
// 删除流程定义,如果该流程定义已经有了流程实例启动则删除时报错
// repositoryService.deleteDeployment("1");
// 设置为TRUE 级联删除流程定义,及时流程有实例启动,也可以删除,设置为false
非级联删除操作。
repositoryService.deleteDeployment("2501", true);
}
只选择一个特定流程实例的活动只选择已完成的活动结果按照结束时间排序,代表其执行顺序。
/**
* 查看历史
*/
@Test
public void testQueryHistory() {
// 配置数据库相关信息 获取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new
StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowablelearn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 获取流程引擎对象
ProcessEngine processEngine = cfg.buildProcessEngine();
HistoryService historyService =
processEngine.getHistoryService();
List list =
historyService.createHistoricActivityInstanceQuery()
.processDefinitionId("holidayRequestNew:1:10003")
.finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();
for (HistoricActivityInstance historicActivityInstance : list) {
System.out.println(historicActivityInstance.getActivityId()
+ " took "
+ historicActivityInstance.getDurationInMillis() + "milliseconds");
}
}