简介
首先,官方用户手册
flowable 是一个使用 Java 编写的轻量级业务流程引擎。flowable 流程引擎可用于部署 BPMN 2.0 流程定义(用于定义流程的行业 XML 标准), 创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据,等等。
我对工作流的定义是:一件事通过一系列的判断与分支,走向终点的流程的定义。工作流是复杂版本的状态机。
而工作流程引擎,则是对工作流的一个整体的抽象,用来创建、销毁、管理、执行工作流。
日常的生活我们就面临审批这审批那的,审批的流程也是不固定的。如果通过代码实现的话,是可以用状态机完成这种一两级的审批,一旦流程较长或者变动、代码就会难以维护。
所以flowable流程引擎把这部分抽象出来,将配置的流程保存在数据库,流程控制代替我们操作,我们只需要在流程每个节点到达的时候做对应的事情,不需要关心下个节点是什么节点,上一个节点是什么节点。
flowable用BPMN 2.0描绘流程,BPMN 协议是一种国际通用的建模语言,他能让自然人轻松阅读,更能被计算机所解析,就像你说中文我能听得懂,说日文我听着就费劲一样。
flowable基于activiti6衍生出来的版本,flowable目前最新版本是v6.7.0,开发团队是从activiti中分裂出来的,修复了一众activiti6的bug,并在其基础上研发了DMN支持,BPEL支持等等。
flowable发展过来,已经不单单关注流程引擎部分开发,而是以流程引擎为基础,衍生到决策引擎、表单引擎、案例模型引擎等其他大功能模块开发。
以下对 Flowable 进行简要说明:
- 是一款轻量级的流程引擎,以 java 语言编写
- 支持 BPMN2.0
- 非常灵活,可以方便的部署到以 java 编程的环境中去
- 多个应用开箱即用(Flowable Modeler, Flowable Admin, Flowable IDM and Flowable Task)
功能特性
- 异步处理历史数据 当前版本处理历史数据与运行时数据处在同一个线程,大量使用案例表明,处理历史数据占用较长时间而用户不得不等待该线程事务的结束。改为异步处理后性能明显得到改善。
- 回退功能 通过 API 方式,让工作流当前状态回滚到之前的状态。
- 增加和拓展对事件子流程的支持
- 提高对事件监听器事务生命周期的支持
- 新增全局 Counter 功能
Flowable 是 Activiti 的衍生版本,相对于 Activiti 来说,它具有以下更加丰富的特性:
- flowable 已经支持所有的历史数据使用 mongdb 存储,activiti 没有。
- flowable 支持事务子流程,activiti 没有。
- flowable 支持多实例加签、减签,activiti 没有。
- flowable 支持 httpTask 等新的类型节点,activiti 没有。
- flowable 支持在流程中动态添加任务节点,activiti 没有。
- flowable 支持历史任务数据通过消息中间件发送,activiti 没有。
- flowable 支持 java11,activiti 没有。
- flowable 支持动态脚本,,activiti 没有。
- flowable 支持条件表达式中自定义 juel 函数,activiti 没有。
- flowable 支持 cmmn 规范,activiti 没有。
- flowable 修复了 dmn 规范设计器,activit 用的 dmn 设计器还是旧的框架,bug 太多。
- flowable 屏蔽了 pvm,activiti6 也屏蔽了 pvm(因为 6 版本官方提供了加签功能,发现 pvm 设计的过于臃肿,索性直接移除,这样加签实现起来更简洁、事实确实如此,如果需要获取节点、连线等信息可以使用 bpmnmodel 替代)。
- flowable 与 activiti 提供了新的事务监听器。activiti5 版本只有事件监听器、任务监听器、执行监听器。-
- flowable 对 activiti 的代码大量的进行了重构。
- activiti 以及 flowable 支持的数据库有 h2、hsql、mysql、oracle、postgres、mssql、db2。其他数据库不支持的。
flowable的基本操作
首先创建一个Maven项目,pom中引入的依赖如下
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ykuee</groupId>
<artifactId>flowable-yktest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- flowable流程引擎引入 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.3.0</version>
</dependency>
<!-- mysql jdbc驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- flowable使用slf4j作为内部日志框架 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<!-- 使用log4j作为slf4j的实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
创建流程引擎实例
1.我们可以通过直接手写配置类的方式构建
// 获取配置器实例
ProcessEngineConfiguration config = new StandaloneProcessEngineConfiguration();
config.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable_test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=TRUE")
.setJdbcUsername("ykuee")
.setJdbcPassword("123456")
/*
* flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产环境常用)
* true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
* create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
* drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。
*/
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = config.buildProcessEngine();
processEngine.getRepositoryService();
flowable提供的配置类有以下几个
- JtaProcessEngineConfiguration 通过类名也知道该类支持 JTA事物
- MultiSchemaMultiTenantProcessEngineConfiguration “多数据库多租户” 流程引擎配置类,通过此类为开发人员提供了自动路由机制,这样当流程引擎需要连接对各数据库进行操作时,客户端无需关心引擎到底连接的是哪个数据库,该类通过路由规则自动选择需要自动操作的数据库,数据库的操作对客户端来说是透明的,客户端无需关心其内部路由的实现机制。
- StandaloneInMemProcessEngineConfiguration 该类通常可以在开发环境中自测使用,默认采用 H2 数据可存储数据
- StandaloneProcessEngineConfiguration 标准的流程引擎配置类
偷偷看下源码,发现标准配置类初始化了非常多的东西
2.除了上面的硬编码的方式外,我们还可以在 resources 目录下创建一个 flowable.cfg.xml
文件,注意这个名称是固定的哦。内容如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration"
class="org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/flowable_test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true" />
<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUsername" value="ykuee" />
<property name="jdbcPassword" value="123456" />
<property name="databaseSchemaUpdate" value="true" />
<property name="asyncExecutorActivate" value="false" />
</bean>
</beans>
通过以下代码也获取流程引擎实例
processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getRepositoryService();
再看看源码是怎么读取的配置文件
进入init方法
ProcessEngines 会扫描 flowable.cfg.xml 与 flowable-context.xml 文件。对于 flowable.cfg.xml 文件,流程引擎会以标准 Flowable 方式构建引擎:ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()。对于 flowable-context.xml 文件,流程引擎会以 Spring 的方式构建:首先构建 Spring 应用上下文,然后从该上下文中获取流程引擎。
所有的服务都是无状态的。这意味着你可以很容易的在集群环境的多个节点上运行 Flowable,使用同一个数据库,而不用担心上一次调用实际在哪台机器上执行。不论在哪个节点执行,对任何服务的任何调用都是幂等(idempotent)的。
在配置文件装入内存后,配置类的初始化就和之前的是一样的了。
运行代码后,查看数据库就发现已经有表创建进去了。
引擎表结构
在获取到引擎实例后,数据库中会自动创建引擎所需要的表结构。
工作流程的相关操作都是操作存储在对应的表结构中,为了能更好的弄清楚 flowable 的实现原理和细节,我们有必要先弄清楚 flowable 的相关表结构及其作用。在 flowable 中的表结构在初始化的时候会创建五类表结构,具体如下:
- ACT_RE :'RE’表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
- ACT_RU:'RU’表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Flowable 只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
- ACT_HI:'HI’表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
- ACT_GE: GE 表示 general。 通用数据, 用于不同场景下
- ACT_ID: ’ID’表示 identity (组织机构)。这些表包含标识的信息,如用户,用户组,等等。
具体的表结构的含义
表分类 | 表名 | 解释 |
---|---|---|
一般数据 | ||
[ACT_GE_BYTEARRAY] | 通用的流程定义和流程资源 | |
[ACT_GE_PROPERTY] | 系统相关属性 | |
流程历史记录 | ||
[ACT_HI_ACTINST] | 历史的流程实例 | |
[ACT_HI_ATTACHMENT] | 历史的流程附件 | |
[ACT_HI_COMMENT] | 历史的说明性信息 | |
[ACT_HI_DETAIL] | 历史的流程运行中的细节信息 | |
[ACT_HI_IDENTITYLINK] | 历史的流程运行过程中用户关系 | |
[ACT_HI_PROCINST] | 历史的流程实例 | |
[ACT_HI_TASKINST] | 历史的任务实例 | |
[ACT_HI_VARINST] | 历史的流程运行中的变量信息 | |
流程定义表 | ||
[ACT_RE_DEPLOYMENT] | 部署单元信息 | |
[ACT_RE_MODEL] | 模型信息 | |
[ACT_RE_PROCDEF] | 已部署的流程定义 | |
运行实例表 | ||
[ACT_RU_EVENT_SUBSCR] | 运行时事件 | |
[ACT_RU_EXECUTION] | 运行时流程执行实例 | |
[ACT_RU_IDENTITYLINK] | 运行时用户关系信息,存储任务节点与参与者的相关信息 | |
[ACT_RU_JOB] | 运行时作业 | |
[ACT_RU_TASK] | 运行时任务 | |
[ACT_RU_VARIABLE] | 运行时变量表 | |
用户用户组表 | ||
[ACT_ID_BYTEARRAY] | 二进制数据表 | |
[ACT_ID_GROUP] | 用户组信息表 | |
[ACT_ID_INFO] | 用户信息详情表 | |
[ACT_ID_MEMBERSHIP] | 人与组关系表 | |
[ACT_ID_PRIV] | 权限表 | |
[ACT_ID_PRIV_MAPPING] | 用户或组权限关系表 | |
[ACT_ID_PROPERTY] | 属性表 | |
[ACT_ID_TOKEN] | 记录用户的 token 信息 | |
[ACT_ID_USER] | 用户表 |
service服务接口
Service 是工作流引擎提供用于进行工作流部署、执行、管理的服务接口,我们使用这些接口可以就是操作服务对应的数据表
通过 ProcessEngine 创建 Service
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
// ...
service 名称 | service 作用 |
---|---|
RepositoryService | Flowable 的资源管理类 |
RuntimeService | Flowable 的流程运行管理类 |
TaskService | Flowable 的任务管理类 |
HistoryService | Flowable 的历史管理类 |
ManagerService | Flowable 的引擎管理类 |
简单介绍:
- RepositoryService 很可能是使用 Flowable 引擎要用的第一个服务。这个服务提供了管理与控制部署 (deployments) 与流程定义 (process definitions) 的操作。管理静态信息,
- RuntimeService 用于启动流程定义的新流程实例。
- IdentityService 很简单。它用于管理(创建,更新,删除,查询……)组与用户。请注意,Flowable 实际上在运行时并不做任何用户检查。例如任务可以分派给任何用户,而引擎并不会验证系统中是否存在该用户。这是因为 Flowable 有时要与 LDAP、Active Directory 等服务结合使用。
- FormService 是可选服务。也就是说 Flowable 没有它也能很好地运行,而不必牺牲任何功能。这个服务引入了开始表单 (start form) 与任务表单 (task form) 的概念。 开始表单是在流程实例启动前显示的表单,而任务表单是用户完成任务时显示的表单。Flowable 可以在 BPMN 2.0 流程定义中定义这些表单。表单服务通过简单的方式暴露这些数据。再次重申,表单不一定要嵌入流程定义,因此这个服务是可选的。
- TaskService 所有任务相关的东西都组织在其中,需要用户操作的任务。例如创建、独立运行 (standalone)任务,决定任务的执行用户 (assignee),或者将用户通过某种方式与任务关联,认领 (claim) 与完成 (complete) 任务
- HistoryService 暴露 Flowable 引擎收集的所有历史数据。当执行流程时,引擎会保存许多数据(可配置),例如流程实例启动时间、谁在执行哪个任务、完成任务花费的事件、每个流程实例的执行路径,等等。这个服务主要提供查询这些数据的能力。
- ManagementService 通常在用 Flowable 编写用户应用时不需要使用。它可以读取数据库表与表原始数据的信息,也提供了对作业 (job) 的查询与管理操作。Flowable 中很多地方都使用作业,例如定时器 (timer),异步操作 (asynchronous continuation),延时暂停 / 激活 (delayed suspension/activation) 等等。后续会详细介绍这些内容。
- DynamicBpmnService 可用于修改流程定义中的部分内容,而不需要重新部署它。例如可以修改流程定义中一个用户任务的办理人设置,或者修改一个服务任务中的类名。
创建流程实例
我们这里使用官网的流程示例,是一个非常简单的请假流程。Flowable 引擎需要流程定义为 BPMN 2.0 格式,这是一个业界广泛接受的 XML 标准。 在 Flowable 术语中,我们将其称为一个流程定义 (process definition)。一个流程定义可以启动多个流程实例 (process instance)。流程定义可以看做是重复执行流程的蓝图。 在这个例子中,流程定义定义了请假的各个步骤,而一个流程实例对应某个员工提出的一个请假申请。
BPMN 2.0 存储为 XML,并包含可视化的部分:使用标准方式定义了每个步骤类型(人工任务,自动服务调用,等等)如何呈现,以及如何互相连接。这样 BPMN 2.0 标准使技术人员与业务人员能用双方都能理解的方式交流业务流程。
我们要使用的流程定义为:
这个流程very简单。但为了明确起见,说明一下几个要点:
- 我们假定启动流程需要提供一些信息,例如雇员名字、请假时长以及说明。当然,这些可以单独建模为流程中的第一步。 但是如果将它们作为流程的 “输入信息”,就能保证只有在实际请求时才会建立一个流程实例。否则(将提交作为流程的第一步),用户可能在提交之前改变主意并取消,但流程实例已经创建了。 在某些场景中,就可能影响重要的指标(例如启动了多少申请,但还未完成),取决于业务目标。
- 左侧的圆圈叫做启动事件 (start event)。这是一个流程实例的起点。
- 第一个矩形是一个用户任务 (user task)。这是流程中人类用户操作的步骤。在这个例子中,经理需要批准或驳回申请。
- 取决于经理的决定,排他网关 (exclusive gateway) (带叉的菱形) 会将流程实例路由至批准或驳回路径。
- 如果批准,则需要将申请注册至某个外部系统,并跟着另一个用户任务,将经理的决定通知给申请人。当然也可以改为发送邮件。
- 如果驳回,则为雇员发送一封邮件通知他。
一般来说,这样的流程定义使用可视化建模工具建立,如 Flowable Designer (Eclipse) 或 Flowable Web Modeler (Web 应用)。
但在这里我们直接撰写 XML,以熟悉 BPMN 2.0 及其概念。
与上面展示的流程图对应的 BPMN 2.0 XML 在下面显示。请注意这只包含了 “流程部分”。如果使用图形化建模工具,实际的 XML 文件还将包含 “可视化部分”,用于描述图形信息,如流程定义中各个元素的坐标(所有的图形化信息包含在 XML 的 BPMNDiagram 标签中,作为 definitions 标签的子元素)。
将下面的 XML 保存在 src/main/resources 文件夹下名为 holiday-request.bpmn20.xml 的文件中。
<?xml version="1.0" encoding="UTF-8"?>
<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">
<![CDATA[
${approved}
]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${!approved}
]]>
</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>
流程文件可以使用工具画出来,然后生成xml,flowable-ui也有相应功能。
现在我们已经有了流程 BPMN 2.0 XML 文件,下来需要将它部署 (deploy) 到引擎中。部署一个流程定义意味着:
- 流程引擎会将 XML 文件存储在数据库中,这样可以在需要的时候获取它。
- 流程定义转换为内部的、可执行的对象模型,这样使用它就可以启动流程实例。
将流程定义部署至 Flowable 引擎,需要使用 RepositoryService,其可以从 ProcessEngine 对象获取。使用 RepositoryService,可以通过 XML 文件的路径创建一个新的部署 (Deployment),并调用 deploy() 方法实际执行:
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("holiday-request.bpmn20.xml")
.deploy();
log.info("deployment id:{}",deployment.getId());
日志中也打印出流程ID
11:41:51,180 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 1934932165 to pool.
11:41:51,180 [main] DEBUG org.flowable.common.engine.impl.interceptor.LogInterceptor - --- DeployCmd finished --------------------------------------------------------
11:41:51,180 [main] INFO FlowableTest - deployment id:5001
进程已结束,退出代码0
查看数据库表,也已创建成功
查询流程定义信息
使用刚刚的流程id查询
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId("5001")
.singleResult();
log.info("name:{}",processDefinition.getName());
日志打印出任务名称
11:44:27,927 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 1934932165 to pool.
11:44:27,928 [main] DEBUG org.flowable.common.engine.impl.interceptor.LogInterceptor - --- ProcessDefinitionQueryImpl finished --------------------------------------------------------
11:44:27,928 [main] INFO FlowableTest - name:HolidayRequest
进程已结束,退出代码0
删除流程定义信息
第二个参数是否级联删除,一般流程在运行是不能被删除的,true会强制删除,与之关联的数据也会一并删除。
RepositoryService repositoryService = processEngine.getRepositoryService();
//是否级联删除
repositoryService.deleteDeployment("5001",true);
此时再查看数据库,发现流程已经被删除掉了。
启动流程实例
接下来,我们使用 RuntimeService 启动一个流程实例。传入参数放到MAP里传递,其中的键就是之后用于获取变量的标识符。这个流程实例使用 BPMN 2.0 XML 文件中设置的 id 属性启动,在这个例子里是 holidayRequest。
//通过RuntimeService启动流程实例
RuntimeService runtimeService = processEngine.getRuntimeService();
//构建流程变量
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employee", "Ykuee");
variables.put("nrOfHolidays", 100);
variables.put("description", "寄");
//启动流程实例
ProcessInstance holidayRequest = runtimeService.startProcessInstanceByKey("holidayRequest", variables);
log.info("processDefinitionId:{}",holidayRequest.getProcessDefinitionId());
log.info("activityId:{}",holidayRequest.getActivityId());
log.info("id:{}",holidayRequest.getId());
日志输出
12:11:52,205 [main] DEBUG org.flowable.common.engine.impl.interceptor.LogInterceptor - --- StartProcessInstanceCmd finished --------------------------------------------------------
12:11:52,205 [main] INFO FlowableTest - processDefinitionId:holidayRequest:1:7503
12:11:52,205 [main] INFO FlowableTest - activityId:null
12:11:52,205 [main] INFO FlowableTest - id:10001
进程已结束,退出代码0
查看数据库,看到参数已经保存了,并且任务也有了流转。
查询当前并处理任务
现在我们需要处理任务,但之前BPMN文件里没有定义审批人,所以需要修改一下,相应的,之前的任务也会作废,删掉任务,重新部署再重新提交一个请假申请。
<userTask id="approveTask" name="Approve or reject request" flowable:assignee="boss"/>
通过 assignee
,指定一个审批请假的人 boss。
重新提交后,我们通过boss查看流转到他这里的任务
TaskService taskService = processEngine.getTaskService();
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest")
.taskAssignee("boss")
.list();
for(Task task : taskList){
log.info("taskId:{}",task.getId());
log.info("name:{}",task.getName());
log.info("assignee:{}",task.getAssignee());
log.info("desc:{}",task.getDescription());
log.info("procDefId:{}",task.getProcessDefinitionId());
}
日志打印
12:36:14,368 [main] DEBUG org.flowable.common.engine.impl.interceptor.LogInterceptor - --- TaskQueryImpl finished --------------------------------------------------------
12:36:14,368 [main] INFO FlowableTest - taskId:15009
12:36:14,368 [main] INFO FlowableTest - name:Approve or reject request
12:36:14,368 [main] INFO FlowableTest - assignee:boss
12:36:14,368 [main] INFO FlowableTest - desc:null
12:36:14,368 [main] INFO FlowableTest - procDefId:holidayRequest:1:12503
进程已结束,退出代码0
查询到任务,我们就可以以boss的身份处理它,直接拒绝掉。
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest")
.taskAssignee("boss")
.singleResult();
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("approved", false);
taskService.complete(task.getId(),variables);
这里我们传入的变量approved正是BPMN中定义的变量,在xml定义里,如果被拒绝,还会进行下一步,发送邮件
<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="org.flowable.SendRejectionMail"/>
这其实就像一个触发器,审批拒绝之后就会触发,来整一个。
package org.flowable;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
/**
* @program: flowable-yktest
* @description:
* @author: 27872
* @create: 2022-06-19 12:48
**/
public class SendRejectionMail implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
//执行触发器逻辑
System.out.println("撸起袖子加油干");
}
}
查看日志,可以发现已经触发了这段代码,任务也结束了流程。
12:50:34,206 [main] DEBUG org.flowable.engine.impl.history.AbstractHistoryManager - Current history level: AUDIT, level required: ACTIVITY
12:50:34,206 [main] DEBUG org.flowable.engine.impl.agenda.ContinueProcessOperation - Executing activityBehavior class org.flowable.engine.impl.bpmn.helper.ClassDelegate on activity 'sendRejectionMail' with execution 15005
撸起袖子加油干
12:50:34,208 [main] DEBUG org.flowable.engine.impl.agenda.DefaultFlowableEngineAgenda - Operation class org.flowable.engine.impl.agenda.TakeOutgoingSequenceFlowsOperation added to agenda
act_ru_task中已经不见了
在历史任务中可以查到踪迹
历史任务查询
选择使用 Flowable 这样的流程引擎的原因之一,是它可以自动存储所有流程实例的审计数据或历史数据。这些数据可以用于创建报告,深入展现组织运行的情况,瓶颈在哪里,等等。
例如,如果希望显示流程实例已经执行的时间,就可以从 ProcessEngine 获取 HistoryService,并创建历史活动 (historical activities) 的查询。在下面的代码片段中,可以看到我们添加了一些额外的过滤条件:
- 只选择一个特定流程实例的活动
- 只选择已完成的活动
结果按照结束时间排序,代表其执行顺序。
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> activities =
historyService.createHistoricActivityInstanceQuery()
.processDefinitionId("holidayRequest:1:12503")
.finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();
for (HistoricActivityInstance activity : activities) {
log.info(activity.getActivityId() + " took "
+ activity.getDurationInMillis() + " milliseconds");
}
查看控制台
12:59:46,264 [main] DEBUG org.flowable.common.engine.impl.interceptor.LogInterceptor - --- HistoricActivityInstanceQueryImpl finished --------------------------------------------------------
12:59:46,264 [main] INFO FlowableTest - startEvent took 2 milliseconds
12:59:46,264 [main] INFO FlowableTest - _flow_startEvent__approveTask took 0 milliseconds
12:59:46,264 [main] INFO FlowableTest - approveTask took 1355323 milliseconds
12:59:46,264 [main] INFO FlowableTest - _flow_approveTask__decision took 0 milliseconds
12:59:46,264 [main] INFO FlowableTest - decision took 12 milliseconds
12:59:46,264 [main] INFO FlowableTest - _flow_decision__sendRejectionMail took 0 milliseconds
12:59:46,264 [main] INFO FlowableTest - sendRejectionMail took 2 milliseconds
12:59:46,264 [main] INFO FlowableTest - _flow_sendRejectionMail__rejectEnd took 0 milliseconds
12:59:46,264 [main] INFO FlowableTest - rejectEnd took 1 milliseconds
进程已结束,退出代码0
结尾
Flowable 引擎支持的功能与特性还有很多,这仅仅是个开始。
从以上的示例流程看出,引擎在实际使用过程中大致流程:
- 前端配置流程,将流程配置信息以 XML 或者 JSON 的格式给到后端
- 后端调用流程引擎的部署方法,部署流程
- 后端调用流程引擎的发起流程方法,发起一个流程,流程引擎根据我们配置的流程信息,流程推进到第一个任务节点
- 流程引擎的每个任务节点到达时可以发出一个事件,我们在不同的事件可以处理一些任务到达时的逻辑
- 后端调用流程引擎的推动流程方法,对流程进行推动,流程引擎会推动到下一个任务节点
- 重复以上操作,直到流程结束
Comments | NOTHING