Camunda工作流引擎三
本篇继续拓宽对 Camunda 工作流的学习!
《Camunda 工作流引擎一》
《Camunda 工作流引擎二》
提要
文章目录
- 提要
- 正文
- 组任务
- 网关
- 排他网关
- 并行网关
- 包含网关
- 事件网关
- SpringBoot整合
本文仍然在前文的 Demo 基础上进行!
正文
组任务
在一个流程中一个用户任务,有时可以被多个人中的任意一个审批即可,例如:请假流程的部门审批这个用户任务中,只要部门经理或者部门副经理其中的任意一个人审批通过即可。
这时候就需要候选人机制,首先在流程模型中给该用户任务设置候选人列表,这样用户任务就变成了组任务:
重新部署流程定义,启动一条流程,执行 input 用户任务:
/*** 开启一个流程实例*/
@Test
public void runProcinst(){Map<String,Object> params = new HashMap<>();params.put("employee","zhangsan");params.put("leave",new Leave("NO00001","休假",new Date()));params.put("days",2);ProcessInstance holiday = runtimeService.startProcessInstanceByKey("holiday",params);System.out.println(holiday.getProcessDefinitionId());System.out.println(holiday.getId());System.out.println(holiday.getProcessInstanceId());
}/*** 流程任务执行*/
@Test
public void taskComplete(){//目前只有一个任务,业务中根据场景选择其他合适的方式Task task = taskService.createTaskQuery().taskAssignee("zhangsan").singleResult();taskService.complete(task.getId());
}
此时 approve1 用户任务被创建,可以在 act_ru_task
表中看到这个任务的 assignee 是空的,同时可以观察到 act_ru_identitylink
表中有两个 type 为 candidate 的记录(user_id 是 zhangsan 和 lisi),需要根据某个候选人去查询到他的代办任务,但是并不能像之前仅有一个 assignee 的时候那样直接去 complete 自己的待办任务,因为每个候选人都可以看到这个组任务,如果某个候选人准备执行(审批)这个查到的代办组任务,则需要先拾取(claim)这个组任务,将其变成自己的个人任务后执行:
/*** 候选人拾取任务*/
@Test
public void claimTask() {//查询候选人的代办任务Task task = taskService.createTaskQuery().processDefinitionKey("holiday").taskCandidateUser("lisi").singleResult();//打印任务实例Id和assigneeSystem.out.println(task.getId());System.out.println(task.getAssignee());//nulltaskService.claim(task.getId(),"lisi");
}/*** 流程任务执行*/
@Test
public void taskComplete(){//已经变成了 lis 的个人任务Task task = taskService.createTaskQuery().taskAssignee("lisi").singleResult();taskService.complete(task.getId());
}
如果某个候选人拾取组任务后,又不想执行了,还可以退还这个个人任务,此时个人任务会重新变成组任务,每个候选人都可以查到并去拾取:
/*** 候选人返还任务*/
@Test
public void sendBackTask() {//查询候选人的代办任务Task task1 = taskService.createTaskQuery().processDefinitionKey("holiday").taskCandidateUser("lisi").singleResult();System.out.println(task1);//null//查询候选人的代办任务Task task2 = taskService.createTaskQuery().processDefinitionKey("holiday").taskAssignee("lisi").singleResult();//打印任务实例Id和assigneeSystem.out.println(task2.getId());System.out.println(task2.getAssignee());//lisi//退还任务,就是将assignee重新设置为nulltaskService.setAssignee(task2.getId(),null);
}
从退还任务发现可以主动去设置 assignee ,那么也可以使用同样的方法去完成任务的转移(交接/交付):
/*** 主动交接/转移任务*/
@Test
public void handOverTask() {//查询候选人的代办任务Task task = taskService.createTaskQuery().processDefinitionKey("holiday").taskCandidateUser("lisi").singleResult();System.out.println(task.getId());System.out.println(task.getAssignee());//null//将assignee重新设置为laowangtaskService.setAssignee(task.getId(),"laowang");
}
此时 act_ru_task
表中对应的任务实例中的 assignee 字段就变成了 laowang,执行任务推进流程直至结束后,观察 act_hi_identitylink
表:
TYPE_ 出现了两种:assignee 是任务的参与者、candidate 是任务的候选人,其中 wangwu 也是任务的候选人,但是其并不是任务的参与者;OPERATION_TYPE_ 也出现了两种:add 用户作为任务的 assignee 加入,delete 用户退还任务(其中 lisi 在任务创建时是 candidate,然后拾取任务,再退换任务)。
网关
排他网关
在之前设想过一种情况:请假时间<=3
的时候只需要部门审批(approve1),当请假时间>3
的时候还需要人事总监审批。在没有使用排他网关的时候,只是在两条顺序流上添加了条件表达式,当表达式结果是 true 的时候,才会走对应的分支:
但是如果上面这种方式出现两条顺序流上的表达式都为 true ,则两条分支都会进行,从而违背我们的设计初衷。这是就需要引入我们的排他网关:
此时,由于排他网关的存在,即使两条分支条件都成立,也只会走其中的一条分支。
排他网关还可以接受进入的顺序流,只要有顺序流进入网关,就会立刻通过。
PS:引入排他网关后,如果两条分支的结果都为 false,则会抛出异常。
并行网关
并行网关主要有分支和汇聚的功能。
分支:并行所有分支出去的顺序流。PS:即使并行网关分支出去的顺序流上有条件表达式,也会被忽略掉。
汇聚:所有到达并行网关的顺序流,都要在此等待,直到所有的顺序流分支都到达并行网关之后才可以通过。
例如:
存储请假单信息后,并行去存储考勤信息和计算工资,当两个任务都完成后、都汇聚到并行网关后再执行到结束事件。
包含网关
包含网关更像是排他网关和并行网关的结合体。它也有分支和汇聚两个功能,同时它也会去执行顺序流上的表达式,只有当分支出的顺序流上的表达式为 true 的时候,才会去执行该顺序流。
同样的,包含网关在汇聚时,也只需要等待条件为 true 被执行的分支都汇聚后,就可以继续执行。
例如:
存储请假单信息后,正式员工
请假不扣工资就不需要去计算工资,只需要去计算考勤即可;实习生
按天算工资,所以请假后需要去执行计算工资;如果是正式员工
则执行完计算考勤后到达第二个包含网关后直接继续执行;如果是实习生
则需要去执行计算考勤和计算工资,当两个任务都执行完汇聚到第二个包含网关后,才能继续执行到结束事件。
事件网关
之前的网关在控制出口顺序流的时候,通常是以顺序流定义的条件表达式的结果去进行选择的。而事件网关,则是以事件作为驱动,通过捕获中间事件来选择出口顺序流的。
当进行之事件网关时执行被暂停并创建一个事件订阅,等待某个中间事件被触发后流程会继续沿着该事件的顺序流继续执行,一个事件网关只会创建一个事件订阅,所以只会选择第一个触发的中间事件继续执行。
一个事件网关至少有两条出口顺序流,且事件网关只能连接至 intermediateCatchEvent
(捕获中间事件) 类型的元素:
例如:
事件网关两条出口顺序流分别连接到 TimerIntermediateCatchEvent
(定时器中间事件) 元素:
PS:Timer Definition 的值需要遵循 ISO 8086 标准中的表示方法。
和一个 SignalIntermediateCatchEvent
(信号中间事件) 元素:
为了便于观察流程的走向,两个捕获中间事件元素后面又连接了一个用户任务,分别设置了执行监听器和任务监听器:
public class TimerEventListener implements TaskListener, ExecutionListener {@Overridepublic void notify(DelegateExecution delegateExecution) throws Exception {System.out.println("定时器事件的ExecutionListener触发了!");}@Overridepublic void notify(DelegateTask delegateTask) {System.out.println("定时器事件的TaskListener触发了!");}
}public class SignalEventListener implements TaskListener, ExecutionListener {@Overridepublic void notify(DelegateExecution delegateExecution) throws Exception {System.out.println("信号事件的ExecutionListener触发了!");}@Overridepublic void notify(DelegateTask delegateTask) {System.out.println("信号事件的TaskListener触发了!");}
}
接下来就是部署流程定义,启动一个流程实例:
@Test
public void runProcinst(){Map<String,Object> params = new HashMap<>();// 30秒params.put("duration","P0Y0M0DT0H0M30S");ProcessInstance holiday = runtimeService.startProcessInstanceByKey("eventGateway",params);System.out.println(holiday.getProcessDefinitionId());System.out.println(holiday.getId());System.out.println(holiday.getProcessInstanceId());//为了观察控制台效果try {Thread.sleep(10000000000000L);} catch (InterruptedException e) {e.printStackTrace();}
}
观察 act_ru_job
表中,timer 已经被创建了,等待 30 秒后,控制台打印出:
定时器事件的ExecutionListener触发了!
定时器事件的TaskListener触发了!
并且 act_ru_task
表中,已经创建出 “ 定时器事件触发了 ”用户任务了,此时 timer 也从 act_ru_job
表中删除了。
再次启动一条流程,观察 act_ru_job
表中,timer 已经被创建了,测试触发信号中间事件
:
/***触发信号中间事件*/
public void signalEvent(){List<Execution> list = runtimeService.createExecutionQuery().processInstanceId("b2be29c3-dfab-11ea-aa93-98fa9b4e8fcb").signalEventSubscriptionName("nextSignal").list();for (Execution execution : list) {runtimeService.signalEventReceived("nextSignal",execution.getId());}
}
控制台打印出:
信号事件的ExecutionListener触发了!
信号事件的TaskListener触发了!
act_ru_task
表中,已经创建出 “ 信号事件触发了 ”用户任务,此时 act_ru_job
表中的 timer 也被删除了。
SpringBoot整合
在第一篇文章《Camunda 工作流引擎一》中就已经详细记录了如何启动一个最简单的 SpringBoot + Camunda 的项目了。
在前文的所有测试方法方法中,也不难看出已经整合入了 SpringBoot ,所以就不需要采用 下面这种方式去获取各种 Service 实例:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeServiceImpl runtimeService = processEngine.getRuntimeService();
而是交由 Spring 容器管理,采用 @Autowired 的方法自动注入,这也是业务中更加常用的方式。
菜鸟本菜,不吝赐教,感激不尽!
更多题解源码和学习笔记:github 、CSDN 、M1ng
Camunda工作流引擎三相关推荐
- Camunda工作流引擎一
实习工作中需要用到工作流引擎,去实现业务审批流的功能模块,由于 Flowable 不支持 MariaDB (重要原因之一),所以项目中选择了 Camunda 工作流引擎. 由于没有接触过工作流引擎,所 ...
- camunda工作流引擎流程定义部署 流程定义查询 激活流程实例
camunda工作流引擎流程定义部署 流程定义查询 激活流程实例 1.通过xml字符串部署流程定义 /*** 通过xml字符串部署流程定义* @param processModelVo* @retur ...
- Camunda 工作流引擎 demo
CamundaDemo 本Demo采用springBoot和camunda内嵌的方式. 在SpringBoot中加入ca ...
- Camunda工作流引擎简记
本文转载自玩转Camunda之实战篇-赶紧收藏起来吧_哔哩哔哩_bilibili 其中部分内容,经过本人修改 一.工作流相关介绍 BPM(BusinessProcessManagement),业务流程 ...
- Camunda工作流引擎之bpmn设计器定制
在 Vue.js应用中,基于 bpmn-js. 定制 vue-bpmn-modeler 前段时间,由于公司业务需要工作流引擎,但是由于之前的工作流引擎是第三方付费的,又遇到客户需要本地地方部署,所以需 ...
- 驰骋工作流引擎三种项目集成开发模式
CCBPM分为如下几种开发模式,您可以根据自己的需要选择合适自己的开发模式,这些开发模式并不是截然分开的而是可以相互综合使用的,就算在同一个流程,也可以第一个节点使用自由表单,第2个节点使用自定义表单 ...
- 三、Camunda工作流的表和用途说明(实践是检验真理的唯一标准)
本人在工作中用的Camunda7.11版本共47张表. camunda工作流的表大体上分为 5 类: ACT_RE_*: 'RE'表示流程资源存储,这个前缀的表包含了流程定义和流程静态资源(图片,规则 ...
- OA 系统工作流引擎 Camunda 实践(1)
[审核人员看清楚再审核,我是把自己公司的案例分析一下, 这哪是广告???] Camunda是Activiti最大的贡献者之一(除Alfresco以外),同时也是它一个主 要的执行咨询合作伙伴.cam ...
- Camunda工作流平台的使用
工作流可以实现业务流程的自动化,用户可以自己定义工作流程,通过流程来把常用的任务组织起来,而无需在程序中固化流程.这也符合当今微服务,低代码开发的趋势. Camunda是目前主流的一个工作流平台,遵循 ...
最新文章
- leetcode之Reorder List
- JavaScript创建Map对象(转)
- c语言 goto 跳出循环,goto语句可以跳出循环.ppt
- linux sublime3 插件安装插件,手动安装sublimeText3插件
- 基于使用AspectJ实现AOP,注解AOP开发(基于xml文件、基于注解)
- layui弹出层:倒计时后自动关闭(含代码、案例)
- 韩国f4计算机考试在哪报名,2020年F4签证资格考试报名方式及考试日程,错过还要再等3个月!...
- 【网络】IP地址格式转换(htonl、ntohl;inet_addr、inet_ntoa)
- python网页数据处理_python 处理html页面爬虫数据
- 利用PyInstaller打包exe文件
- Apache创建虚拟目录绑定域名
- Alex 的 Hadoop 菜鸟教程: 第3课 Hadoop 安装教程 - 非HA方式 (一台服务器)
- 无线渗透----扫描附近WiFi(windows系统)
- 计算机操作填充柄在哪里,Excel中2010版进行添加自动填充柄的操作方法
- java 发微信视频_分享java微信开发视频
- 2019 计蒜之道 初赛 第一场 A 商汤的AI伴游小精灵
- 虚幻引擎中的节流与防抖
- 备用手机如何自动转发短信和验证码
- 牛客网数据库8:获取员工其当前的薪水比其manager当前薪水还高的相关信息
- Android超简单时间轴的实现
热门文章
- 沃特世ACQUITY PREMIER色谱柱为色谱分析树立全新性能标杆
- Linux 用户(user)和用户组(group)管理概述 转自:http://fedora.linuxsir.org/main/?q=node/91
- 初心大陆-----python宝典 第三章
- 无线网络破解的一次奇妙之旅!
- 利用枚举类型变量求从5种颜色球中取3个不同颜色球的取法
- android 触摸屏 滑动,android开发:触摸屏触摸事件MotionEvent演示实例
- 2013年工作中遇到的20个问题(Bug):161-180
- Excel学习篇之求和
- lisp 阿基米德螺旋_用CAD如何画阿基米德螺线
- setTimeout代替setInterval