参考文档

https://tkjohn.github.io/flowable-userguide

Flowable

简介

Flowable是一个使用Java编写的轻量级业务流程引擎。

Flowable是Activiti原班主创人员从Activiti分离出来的一套工作流引擎,是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理员。其核心是超快速、稳定的BPMN2流程引擎,易于与 Spring集成使用。
Activiti7是 Salaboy团队开发的。进行维护activiti6以及activiti5代码。目前的activiti5以及activiti6代码还是原Tijs

Rademakers原有团队开发的。Salaboy团队目前在开发activiti7框架。对于activiti6以及activiti5的代码官方已经宣称暂停维护了。activiti7就是噱头 内核使用的还是activiti6。并没有为引擎注入更多的新特性,只是在activiti之外的上层封装了一些应用。

所需软件

1、JDK 1.8+
2、IDE/Eclipse
图形化设计插件 actiBPM 、JBoss jBPM。(JBoss jBPM已经停止维护,其在新版本的Intellij下安装容易出问题)
对于UI效果追求较高的同学可以试试其他bpmn设计工具:flowable_uivisual-paradigmbpmn-js(demo: https://demo.bpmn.io/)

数据表名说明

Flowable的所有数据库表都以ACT_开头。第二部分是说明表用途的两字符标示符。服务API的命名也大略符合这个规则。

ACT_RE_*: 'RE’代表repository。带有这个前缀的表包含“静态”信息,例如流程定义与流程资源(图片、规则等)。

ACT_RU_*: 'RU’代表runtime。这些表存储运行时信息,例如流程实例(process instance)、用户任务(user task)、变量(variable)、作业(job)等。Flowable只在流程实例运行中保存运行时数据,并在流程实例结束时删除记录。这样保证运行时表小和快。

ACT_HI_*: 'HI’代表history。这些表存储历史数据,例如已完成的流程实例、变量、任务等。

详情可参考博客:

使用一个工作流的大致步骤

创建流程引擎 —> 部署流程定义 —> 启动流程示例 —> 查询与完成任务 —> 结束

Flowable Spring Boot stater的列表:

Starter

描述

flowable-spring-boot-starter-cmmn

提供以独立运行模式启动CMMN引擎的依赖

flowable-spring-boot-starter-cmmn-rest

提供以独立运行模式启动CMMN引擎,并提供其REST API的依赖。

flowable-spring-boot-starter-dmn

提供以独立运行模式启动DMN引擎的依赖。

flowable-spring-boot-starter-dmn-rest

提供以独立运行模式启动DMN引擎,并提供其REST API的依赖。

flowable-spring-boot-starter-process

提供以独立运行模式启动流程引擎的依赖。

flowable-spring-boot-starter-process-rest

提供以独立运行模式启动流程引擎,并提供其REST API的依赖。

flowable-spring-boot-starter

提供启动所有Flowable引擎(流程,CMMN,DMN,Form,Content及IDM)的依赖。

flowable-spring-boot-starter-rest

提供启动所有Flowable引擎,并提供其REST API的依赖。

flowable-spring-boot-starter-actuator

提供Spring Boot Actuator所需的依赖。

Flowable Spring Boot支持的配置参数列表:

# ===================================================================
# Common Flowable Spring Boot Properties
# 通用Flowable Spring Boot参数         
# 本示例文件只作为指导。请不要直接拷贝至你自己的应用中。
# ===================================================================

# Core (Process) FlowableProperties
# 核心(流程)
flowable.check-process-definitions=true # 是否需要自动部署流程定义。
flowable.custom-mybatis-mappers= # 需要添加至引擎的自定义Mybatis映射的FQN。
flowable.custom-mybatis-x-m-l-mappers= # 需要添加至引擎的自定义Mybatis XML映射的路径。
flowable.database-schema= # 如果数据库返回的元数据不正确,可以在这里设置schema用于检测/生成表。
flowable.database-schema-update=true # 数据库schema更新策略。
flowable.db-history-used=true # 是否要使用db历史。
flowable.deployment-name=SpringBootAutoDeployment # 自动部署的名称。
flowable.history-level= # 要使用的历史级别。
flowable.process-definition-location-prefix=classpath*:/processes/ # 自动部署时查找流程的目录。
flowable.process-definition-location-suffixes=**.bpmn20.xml,**.bpmn # 'processDefinitionLocationPrefix'路径下需要部署的文件的后缀(扩展名)。

更加详细的配置参加官方文档(5.7.8)

DEMO 说明

  • flowable-javase 基于java构建的命令行程序
  • flowable-boot 基于SpringBoot构建的简单demo
  • flowable-complex 白嫖来的稍微复杂的流程示例

flowable-boot 一个简单的操作示例

开启一个流程:
curl --location --request POST 'http://localhost:9001/process/start_process' \
--header 'Content-Type: application/json' \
--data-raw '{
	"processKey": "oneTaskProcess",
    "businessKey": "123456",
	"params": {
		"money": "800",
		"taskUser": "1"
	}
		
}'
查询报销申请人的任务列表
curl --location --request POST 'http://localhost:9001/process/tasks' \
--header 'Content-Type: application/json' \
--data-raw '{
	"assignee": "1"
}'
  • 返回结果展示:

展开查看

[
    {
        "assigneeUpdatedCount": 1,
        "assignee": "1",
        "name": "出差报销",
        "priority": 50,
        "createTime": "Jun 5, 2020 10:27:15 AM",
        "suspensionState": 1,
        "isIdentityLinksInitialized": false,
        "taskIdentityLinkEntities": [],
        "executionId": "11e7c1c2-a6d4-11ea-b68b-76d55d87e7da",
        "processInstanceId": "11e74c8f-a6d4-11ea-b68b-76d55d87e7da",
        "processDefinitionId": "submitExpenseAccount:1:e210e66d-a6d3-11ea-b68b-76d55d87e7da",
        "taskDefinitionKey": "fillTask",
        "isCanceled": false,
        "isCountEnabled": true,
        "variableCount": 0,
        "identityLinkCount": 0,
        "subTaskCount": 0,
        "tenantId": "",
        "forcedUpdate": false,
        "usedVariablesCache": {},
        "id": "11eaa7f6-a6d4-11ea-b68b-76d55d87e7da",
        "revision": 1,
        "isInserted": false,
        "isUpdated": false,
        "isDeleted": false,
        "originalPersistentState": {
            "processInstanceId": "11e74c8f-a6d4-11ea-b68b-76d55d87e7da",
            "processDefinitionId": "submitExpenseAccount:1:e210e66d-a6d3-11ea-b68b-76d55d87e7da",
            "suspensionState": 1,
            "priority": 50,
            "executionId": "11e7c1c2-a6d4-11ea-b68b-76d55d87e7da",
            "taskDefinitionKey": "fillTask",
            "subTaskCount": 0,
            "createTime": "Jun 5, 2020 10:27:15 AM",
            "name": "出差报销",
            "isCountEnabled": true,
            "variableCount": 0,
            "assignee": "1",
            "identityLinkCount": 0
        }
    }
]
  • 使用processInstanceId 获取当前的流程状态图:

工作流实现Java java工作流flowable_json

申请人执行流程 (使用上述’id’)
curl --location --request POST 'http://localhost:9001/process/deal_process' \
--header 'Content-Type: application/json' \
--data-raw '{
	"taskId": "11eaa7f6-a6d4-11ea-b68b-76d55d87e7da"
		
}'
  • 当前的流程状态图:

工作流实现Java java工作流flowable_json_02

老板拒绝

  • 获取老板的任务列表,得到该任务的id
curl --location --request POST 'http://localhost:9001/process/tasks' \
--header 'Content-Type: application/json' \
--data-raw '{
	"assignee": "老板"
}'
  • 执行驳回
curl --location --request POST 'http://localhost:9001/process/deal_process' \
--header 'Content-Type: application/json' \
--data-raw '{
	"taskId": "70ab186d-a6d4-11ea-b68b-76d55d87e7da",
	"params": {
		"outcome": "驳回"
	}	
}'
  • 当前的流程状态图:

工作流实现Java java工作流flowable_json

老板驳回后,流程又回到报销申请人

申请人再次提交,并修改金额

curl --location --request POST 'http://localhost:9001/process/deal_process' \
--header 'Content-Type: application/json' \
--data-raw '{
	"taskId": "9f85ce92-a6d6-11ea-b68b-76d55d87e7da",
	"params": {
		"money": "488"
	}	
}'
  • 当前的流程状态图:
经理审批通过
curl --location --request POST 'http://localhost:9001/process/deal_process' \
--header 'Content-Type: application/json' \
--data-raw '{
	"taskId": "9c239b58-a6d7-11ea-b68b-76d55d87e7da",
	"params": {
		"outcome": "通过"
	}	
}'
  • 流程结束
说明
  • 任务处理人标记的两种方式
    使用 ‘flowable:assignee’ 指定
<userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">

使用 ‘class’ 指定

<userTask id="directorTak" name="经理审批">
      <extensionElements>
        <flowable:taskListener event="create" class="com.dy.glcx.demo.flowable.boot.flowable.listener.ManagerTaskHandler" />
      </extensionElements>
</userTask>
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
 
public class ManagerTaskHandler implements TaskListener {
 
    @Override
    public void notify(DelegateTask delegateTask) {
        // TODO 可做其他处理
        delegateTask.setAssignee("经理");
    }
 
}
备注
  • 使用demo前最好先从官方文档了解部分基础概念
  • 本示例demo比较简单,如需流程较长的示例可参考 flowable-complex 模块
  • 未完待续 …