文章目录

  • 1. 捋清三个概念
  • 2. 五种流程启动方式
  • 3. 简单实践
  • 4. 删除流程实例
  • 5. 获取运行的活动节点

上篇文章松哥和大家聊了 Flowable 中的流程部署问题,今天我们继续来聊聊流程实例。

部署之后的流程,这个还不能直接运行,例如我们部署了一个请假流程,现在 zhangsan 想要请假,他就需要开启一个请假流程,lisi 想请假,他也需要开启一个请假流程,这一个一个开启的请假流程就是流程实例,而我们一开始部署的请假流程,则类似于一个模版,基于此模版,我们可以开启很多个具体的流程实例。从这个角度来说,上篇文章我们定义的 ProcessDefinition 就类似于一个 Java 类,今天我们要介绍的 ProcessInstance 则相当于一个 Java 对象。

1. 捋清三个概念

首先我们需要先捋清三个概念:

  • 流程定义 ProcessDefinition
  • 流程实例 ProcessInstance
  • 执行实例 Execution

流程定义

流程定义 ProcessDefinition 这个好说,其实就是我们上篇文章中和大家介绍的内容。将一个流程 XML 文件部署到 flowable 中,这就是一个定义好的流程了,基于这个定义好的流程,我们可以开启很多流程实例。

流程实例

流程实例 ProcessInstance 就是通过流程定义启动的一个流程,他表示一个流程从开始到结束的最大的流程分支,在一个流程中,只存在一个流程实例,流程实例和流程定义的关系就类似于 Java 对象和 Java 类之间的关系。

执行实例

执行实例 Execution 稍微有点难以理解。

首先从类的关系上来看,ProcessInstance 就是 Execution 的子类。

流程实例通常是执行实例的根结点,即在一个流程中,出口和入口可以算是一个流程实例的节点,而中间的过程则是执行实例。

假如流程本身就是一条线,那么流程实例和执行实例基本上是一样的,但是如果流程中包含多条线,例如下图:

这张图中有并行网关,并行任务执行的时候,每一个并行任务就是一个执行实例,这样大家就好理解了。

结论就是,在一个流程实例中,除了开始和结束之外,其他的都是执行实例。即使流程只有一条线,中间的也都是执行实例,只不过此时的执行实例等于流程实例而已。

好啦,三个基本概念先捋清楚。

2. 五种流程启动方式

当我们将流程部署好之后,接下来启动流程,我们有五种不同的方式去启动一个流程。

  1. 通过流程定义的 id 去启动

首先就是通过流程定义的 id 去启动一个流程,对应的方法名称就是 RuntimeService#startProcessInstanceById,该方法有好几个重载的方法,不同的重载方法只是传递的参数不同而已,其他基本上都是一样的。

  1. 通过流程的 key 去启动

也可以通过流程定义的 key 去启动一个流程,根据上篇文章的介绍,大家知道,这个流程定义的 key 其实就是流程 XML 文件中的 id,这个对应的方法名是 RuntimeService#startProcessInstanceByKey

  1. 通过流程的 key+tenantId 去启动

有这样一种情况,例如我有两个子系统 A 和 B,A 和 B 中都有一个请假流程的定义,现在当我想要启动一个流程的时候,怎么知道是启动 A 的请假流程还是启动 B 的请假流程呢?此时我们可以通过租户 ID 即 tenantId 去区分,所以,流程启动就还有一个方法 RuntimeService#startProcessInstanceByKeyAndTenantId

  1. 通过流程的 message 去启动

通过消息去启动一个流程,对应的方法是 RuntimeService#startProcessInstanceByMessage

  1. 通过流程的 message+tenanId 去启动

通过消息+租户 ID 去启动一个流程,对应的方法是 RuntimeService#startProcessInstanceByMessageAndTenantId

3. 简单实践

首先我们绘制一个简单的流程图,然后按照上篇文章所介绍的方式进行部署,流程图如下:

流程 XML 文件如下:

<process id="leave" name="请假流程" isExecutable="true"><startEvent id="startEvent1" flowable:formFieldValidation="true" flowable:initiator="INITIATOR"></startEvent><userTask id="sid-EF721F14-B1F1-4B3B-8018-608757EF5391" name="提交请假申请" flowable:assignee="${INITIATOR}" flowable:formFieldValidation="true"><extensionElements><modeler:activiti-idm-initiator xmlns:modeler="http://flowable.org/modeler"><![CDATA[true]]></modeler:activiti-idm-initiator></extensionElements></userTask><sequenceFlow id="sid-9C18B4D2-127C-40FD-BC81-1E947628D316" sourceRef="startEvent1" targetRef="sid-EF721F14-B1F1-4B3B-8018-608757EF5391"></sequenceFlow><userTask id="sid-CC8E2905-C524-4C32-86DE-8C76102EBDF2" name="主管审批" flowable:assignee="zhangsan" flowable:formFieldValidation="true"><extensionElements><modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete></extensionElements></userTask><sequenceFlow id="sid-62E837FF-DF33-414C-AC21-2DA84E478856" sourceRef="sid-EF721F14-B1F1-4B3B-8018-608757EF5391" targetRef="sid-CC8E2905-C524-4C32-86DE-8C76102EBDF2"></sequenceFlow><userTask id="sid-D033E54B-4388-46B1-A8F9-472ABD2E1435" name="经理审批" flowable:assignee="lisi" flowable:formFieldValidation="true"><extensionElements><modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete></extensionElements></userTask><sequenceFlow id="sid-7EDE624F-1D8F-4DF3-BB97-F8D9066A7A75" sourceRef="sid-CC8E2905-C524-4C32-86DE-8C76102EBDF2" targetRef="sid-D033E54B-4388-46B1-A8F9-472ABD2E1435"></sequenceFlow><endEvent id="sid-FB77ACAC-DB24-4F44-9925-2FE2EAE09EF8"></endEvent><sequenceFlow id="sid-21345500-1FCF-4356-9FB1-834C09BEA9CB" sourceRef="sid-D033E54B-4388-46B1-A8F9-472ABD2E1435" targetRef="sid-FB77ACAC-DB24-4F44-9925-2FE2EAE09EF8"></sequenceFlow>
</process>

这个 XML 文件我跟大家说一句,在启动节点上我设置了 flowable:initiator="INITIATOR",相当于定义了流程发起人的变量为 INITIATOR,这个变量名是自定义的,定义好之后,将来我就可以在其他节点中就可以使用这个变量了。

很简单的流程,其中:

  • 提交请假申请是由流程的发起人完成。
  • 主管是 zhangsan。
  • 经理是 lisi。

好了,先按照上篇文章我们介绍的方式部署流程。

接下来我们要启动流程,假设我们用流程定义的 key 来启动一个流程实例:

@SpringBootTest
public class RuTest {@AutowiredRuntimeService runtimeService;private static final Logger logger = LoggerFactory.getLogger(RuTest.class);@Testvoid test01() {Authentication.setAuthenticatedUserId("wangwu");ProcessInstance pi = runtimeService.startProcessInstanceByKey("leave");logger.info("id:{},activityId:{}",pi.getId(),pi.getActivityId());}
}

启动的代码其实很简单,当流程启动成功之后,流程中的每一步都会记录在 ACT_RU_EXECUTION 表中,同时,如果这个节点是一个用户任务节点(UserTask),那么同时还会在 ACT_RU_TASK 表中添加一条记录。

Authentication.setAuthenticatedUserId("wangwu"); 表示设置流程的发起人。

另外一种设置流程发起人的方式如下:

@Autowired
IdentityService identityService;
@Test
void test01() {identityService.setAuthenticatedUserId("wangwu");ProcessInstance pi = runtimeService.startProcessInstanceByKey("leave");logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}

对于我们上面的流程来说,启动之后,就会进入到提交请假申请这个节点中,所以一共走了两个节点,那么 ACT_RU_EXECUTION 表中应该有两条记录了,如下图:

再来看看 ACT_RU_TASK 表中的内容:

可以看到,该表中有一条记录,这条记录其实就是提交请假申请这个节点,现在流程就停在这一步了,需要用户手动操作,才会继续向下走。

从这两张表中我们也可以大致上看出来,EXECUTION 和 ProcessInstance 之间的关系,ACT_RU_EXECUTION 表中的每一条记录就是一个 EXECUTION,多个 EXECUTION 对应同一个 PROC_INST_ID_,而 ACT_RU_TASK 表中的每一条 Task 记录也都对应了一个 EXECUTION。

现在我们就先去查询 wangwu 需要完成的 Task(wangwu 是流程的发起人):

@Autowired
TaskService taskService;
@Test
void test02() {List<Task> list = taskService.createTaskQuery().taskAssignee("wangwu").list();for (Task task : list) {logger.info("id:{};name:{};taskDefinitionKey:{}",task.getId(),task.getName(),task.getTaskDefinitionKey());}
}

根据前面的介绍,我们知道,这个查询肯定是去 ACT_RU_TASK 表中进行查询的,我们来看下执行的 SQL:

可以看到,这里就是根据 ASSIGNEE_ 字段去查询任务的。

查询到任务之后,接下来去完成任务:

@Test
void test03() {List<Task> list = taskService.createTaskQuery().taskAssignee("wangwu").list();for (Task task : list) {taskService.complete(task.getId());}
}

这个表示查询到 wangwu 的任务然后完成,这个方法执行完成之后,首先会在 ACT_RU_TASK 表中插入一条新的需要 zhangsan 完成的 Task,然后会更新 ACT_RU_EXECUTION 表中对应的执行实例信息,最后再从 ACT_RU_TASK 表中删除需要 wangwu 完成的记录,这些操作是在同一个事务当中完成的。

好了,现在再去执行 test02 的查询方法,就会发现查不到了,因为没有 wangwu 需要完成的 task 了,接下来应该去查询 zhangsan 需要完成的 task。

当一个流程实例完成后,ACT_RU_TASK 和 ACT_RU_EXECUTION 表中的记录都会被删除,所以我们可以通过查询 ACT_RU_EXECUTION 表中是否还有记录,去判断一个一个流程目前是处于执行状态还是完成状态,代码如下:

@Test
void test04() {String pId = "9c8557dd-3727-11ed-9404-acde48001122";ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(pId).singleResult();if (pi == null) {logger.info("{} 流程执行结束", pId);}else{logger.info("{} 流程正在执行中", pId);}
}

最后,如果你想要去 ACT_RU_EXECUTION 表中查询执行实例也是 OK 的,方式如下:


@Test
void test05() {List<Execution> list = runtimeService.createExecutionQuery().processInstanceId("6d0341c7-3729-11ed-8e4e-acde48001122").list();for (Execution execution : list) {logger.info("id:{};processInstanceId:{};name:{}",execution.getId(),execution.getProcessInstanceId(),execution.getName());}
}

查看执行的 SQL 如下:

: ==>  Preparing: SELECT RES.* , P.KEY_ as ProcessDefinitionKey, P.ID_ as ProcessDefinitionId, P.NAME_ as ProcessDefinitionName, P.VERSION_ as ProcessDefinitionVersion, P.DEPLOYMENT_ID_ as DeploymentId from ACT_RU_EXECUTION RES inner join ACT_RE_PROCDEF P on RES.PROC_DEF_ID_ = P.ID_ WHERE RES.PROC_INST_ID_ = ? order by RES.ID_ asc
: ==> Parameters: 6d0341c7-3729-11ed-8e4e-acde48001122(String)
: <==      Total: 2

可以看到,就是去 ACT_RU_EXECUTION 表中查询的。

4. 删除流程实例

如果我们想删除一个流程实例,操作方式如下:

@Test
void test06() {runtimeService.deleteProcessInstance("65ab0b38-38f3-11ed-b103-acde48001122", "javaboy想删除了");
}

注意这个是删除正在执行的流程实例信息,并不会删除历史流程信息。

5. 获取运行的活动节点

可以根据执行实例的 ID 去查询活动节点的 ID,方式如下:

@Test
void test07() {List<Execution> list = runtimeService.createExecutionQuery().list();for (Execution execution : list) {List<String> activeActivityIds = runtimeService.getActiveActivityIds(execution.getId());for (String activeActivityId : activeActivityIds) {System.out.println("activeActivityId = " + activeActivityId);}}
}

这里查询的其实就是 ACT_RU_EXECUTION 表,查询到的 activeActivityId 其实就是该表的 ACT_ID 字段,我们来看下查询的 SQL:

好啦,流程实例先聊这么多,下篇文章我们继续~

玩转 Flowable 流程实例相关推荐

  1. 12.flowable 流程实例 终止流程

    项目地址:https://gitee.com/lwj/flowable.git 分支flowable-base 视频讲解地址 https://space.bilibili.com/485524575/ ...

  2. flowable流程实例管理接口

    一.流程实例的管理接口常见功能: 1.启动一个流程(即创建一个流程实例) 2.本人发起的流程实例 3.本人参与的流程实例 4.挂起/激活流程实例 5.提前终止流程实例(或又叫撤销流程) 6.彻底删除流 ...

  3. flowable流程实例笔记(1)

    RuntimeService 运行服务类 支持启动的方式 流程定义: 从这里获取资源文件. 执行实例: 流程实例中执行的每个环节.流程实例: 一个流程实例包括所有运行的节点,一个流程中流程实例只有一个 ...

  4. flowable实战(三)flowable流程实例管理接口

    文章目录 一.流程实例的管理接口常见功能: 1.启动一个流程(即创建一个流程实例) 2.本人发起的流程实例 3.本人参与的流程实例 4.挂起/激活流程实例 5.提前终止流程实例(或又叫撤销流程) 6. ...

  5. Flowable 流程实例的挂起(暂停)与激活

    今天来和小伙伴们聊一聊流程的挂起和激活. 这块实际上涉及到两部分内容: 流程定义的挂起和激活. 流程实例的挂起和激活. 一个定义好的流程,如果挂起了,那么就无法据此创建新的流程. 一个流程实例如果挂起 ...

  6. springboot集成flowable创建请假流程实例

    springboot如何集成flowable,如何部署flowable在线编辑器画bpm图以及bpm图的画法,我在上一篇博客中写了,这里直接上代码(源码地址:晚安/flowable_holiday ( ...

  7. Flowable 6.6.0 BPMN用户指南 -10 流程实例迁移 - 10.1 简单示例

    Flowable 6.6.0 用户指南相关文档下载 BPMN用户指南 第一部分 - 中文PDF精编版 BPMN用户指南 第二部分 - 中文PDF精编版 BPMN用户指南 第三部分 - 中文PDF精编版 ...

  8. 《Activiti/Flowable 深入BPM工作流》-流程实例怎么实现挂起?

    <Activiti/Flowable  深入BPM工作流>-流程实例怎么实现挂起? 一. 问题 1. 什么情况要进行流程的挂起? 2. 具体怎么将流程挂起? 二. 详情   1. 什么情况 ...

  9. (经验总结)flowable工作流_01_流程实例管理

    文章目录 一.流程定义管理功能有哪些? 二.删除流程实例会删除哪些表中的数据? 三.流程实例做什么用? 四.流程定义涉及的表 一.流程定义管理功能有哪些? 类名:ApiFlowableProcessI ...

  10. flowable实战(十三):为了启动流程实例时给流程加一个标题

    我们经常希望待办任务列表有一列是流程实例的名称,即标题,例如,我们希望流程的标题是:张三 2019-12-04 16:40:20 的请假申请,通常会采用一个命名规则:发起人+发起时间+流程模型名称把它 ...

最新文章

  1. Python断言方法:assert
  2. 设计模式系列-创建者模式
  3. pyqt怎么button怎么链接_SEO内部链接怎么优化
  4. Java中的ConcurrentHashMap
  5. 安装Ubuntu前三件重要的事情
  6. word双栏添加右栏下脚注而左栏满字方法
  7. 凯文.凯利:未来12个趋势(值得一读)
  8. Tableau数据分析-Chapter04标靶图、甘特图、瀑布图
  9. NOIP 2018 提高组初赛试题 题目+答案+简要解析
  10. SVG格式文件可以用什么软件打开?
  11. 4x root 红米_红米Note 4X root教程_红米Note4X获取root权限的方法
  12. 30.一张图理解EOS是什么
  13. urlencode的使用
  14. 长期主义:做你余生中最重要的事
  15. 工程管理系统源码-专注项目数字化管理
  16. Hibernate学习(一)
  17. centos 7 发送邮件
  18. cmake 超简单使用
  19. 手推BN、IN、LN、GN
  20. 基于 Python 的自然邻域法空间插值的实现与优化

热门文章

  1. 西门子PLCSIM仿真与第三方组态软件(包括HMI)的通信
  2. 移远ec20型号区别_移远EC20CEFDKG PCIE 全网通4G模块 增加B5频段 性价更高
  3. 骑士CMS模版注入+文件包含getshell漏洞复现
  4. 此版本专旧版本为android,关于Android9.0 此应用专为旧版Android打造,因此可能无法正常运行。请尝试检查更新或与开发者联系...
  5. 视频教程_干货视频教程分享
  6. JAVA后台权限管理系统
  7. STM32+L298N+PWM可调速小车(四驱)
  8. 一套适合入门的Oracle学习视频
  9. 西门子S7-200 SMART编程软件下载
  10. c语言贪吃蛇设计意义,C语言贪吃蛇设计理念.pdf