1. 工作流
简单地来讲,工作流就是在计算机的协助下实现流程的自动化控制 。目前,笔者熟知的主流的框架有:Camunda 、Flowable 、Activiti 、jBPM、还有我们国产的盘古BPM、云程 。其中,Camunda 、Flowable 都有商业版(企业版)和非商业版(社区开源版) 。
技术产品各有千秋,Flowable专注于流程引擎,Activiti现在专注于Cloud 。笔者最推荐Camunda,盘古BPM还没用过看起来应该也挺好用的 。

文章插图
关于Camunda补充几篇文章
- Camunda开源版与商业版的差异
- idea开发工作流使用camunda-model进行activiti7的开发
- 基于camunda如何实现会签:camunda会签流程配置与原理解析
笔者亲测,IntelliJ IDEA 2021.1 (Ultimate Edition) 不支持 actiBPM插件 。
强烈推荐用 camunda-modeler ,或者用 bpmn-js
首先,下载Camunda
https://camunda.com/download/

文章插图
解压以后,直接双击.exe文件运行
也可以在IDEA中把它作为外部工具用

文章插图

文章插图
笔者更习惯直接双击.exe打开
Activiti为Eclipse开发了一个BPM插件“Activiti Eclipse Designer”
https://www.activiti.org/userguide/index.html#activitiDesigner

文章插图
为了使用Activiti Designer,笔者又下载了Eclipse IDE,专门为了Activiti开发

文章插图

文章插图
3. Activiti7 快速开始
工作流的作用是实现流程的自动化控制 。使用Activiti这种工作流框架大致都分为以下几个步骤:
- 流程定义
- 部署流程定义
- 启动流程实例
- 查询代表任务
- 完成任务
- 结束流程
- BPM :业务流程管理
- BPMN :业务流程模型和符号
1 <dependency>2<groupId>org.activiti</groupId>3<artifactId>activiti-spring-boot-starter</artifactId>4<version>7.1.0.M6</version>5 </dependency>学习Activiti主要是学习这些Service的使用

文章插图
3.1. 创建ProcessEngine
1 package com.cjs.example.activiti; 23 import org.activiti.engine.ProcessEngine; 4 import org.activiti.engine.ProcessEngineConfiguration; 5 import org.activiti.engine.ProcessEngines; 6 import org.junit.jupiter.api.Test; 78 /** 9* @Author ChengJianSheng10* @Date 2021/7/611*/12 public class ProcessEngineTests {13 14@Test15public void testProcessEngine1() {16ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();17System.out.println(processEngine);18}19 20@Test21public void testProcessEngine2() {22ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");23ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();24System.out.println(processEngine);25}26 27 }ProcessEngineConfiguration是用来创建ProcessEngine,默认情况下,会读取classpath下的activiti.cfg.xml文件,当然也可以不叫这个名字
这里,由于还没有与Spring Boot整合,也不是一个Web环境,所以,姑且先建一个这样的文件吧,真正开发的时候肯定不是这样做的
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 56<bean id="processEngineConfiguration" name="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> 7<property name="jdbcDriver" value="https://tazarkount.com/read/com.mysql.jdbc.Driver"/> 8<property name="jdbcUrl" value="https://tazarkount.com/read/jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf8"/> 9<property name="jdbcUsername" value="https://tazarkount.com/read/root"/>10<property name="jdbcPassword" value="https://tazarkount.com/read/123456"/>11<property name="databaseSchemaUpdate" value="https://tazarkount.com/read/true"/>12</bean>13 </beans>只要ProcessEngine被成功创建,就会生成25张表

文章插图
这里我们可以看出,Activiti最本质最核心的东西就是将流程定义转换成表记录,表面上看好像是一个图片,其实它是一个xml文件,通过解析xml文件,进而将其转成表数据,后续从表中读数据就可以了 。
3.2. 流程定义
用 Camunda Modeler 或者 Activiti Eclipse Designer 画好流程图

文章插图
1 <?xml version="1.0" encoding="UTF-8"?> 2 <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4xmlns:xsd="http://www.w3.org/2001/XMLSchema" 5xmlns:activiti="http://activiti.org/bpmn" 6xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 7xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 8xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" 9typeLanguage="http://www.w3.org/2001/XMLSchema"10expressionLanguage="http://www.w3.org/1999/XPath"11targetNamespace="http://www.activiti.org/test">12 13<process id="holiday" name="holiday" isExecutable="true">14<startEvent id="startevent1" name="Start"></startEvent>15<userTask id="usertask1" name="填写请假单" activiti:assignee="${assignee1}"></userTask>16<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>17<userTask id="usertask2" name="部门经理审批" activiti:assignee="${assignee2}"></userTask>18<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>19<userTask id="usertask3" name="人事审批" activiti:candidateUsers="tom,jerry"></userTask>20<sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>21<endEvent id="endevent1" name="End"></endEvent>22<sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>23</process>24 25<bpmndi:BPMNDiagram id="BPMNDiagram_holiday">26<bpmndi:BPMNPlane bpmnElement="holiday" id="BPMNPlane_holiday">27<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">28<omgdc:Bounds height="35.0" width="35.0" x="130.0" y="220.0"></omgdc:Bounds>29</bpmndi:BPMNShape>30<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">31<omgdc:Bounds height="55.0" width="105.0" x="210.0" y="210.0"></omgdc:Bounds>32</bpmndi:BPMNShape>33<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">34<omgdc:Bounds height="55.0" width="105.0" x="360.0" y="210.0"></omgdc:Bounds>35</bpmndi:BPMNShape>36<bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">37<omgdc:Bounds height="55.0" width="105.0" x="510.0" y="210.0"></omgdc:Bounds>38</bpmndi:BPMNShape>39<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">40<omgdc:Bounds height="35.0" width="35.0" x="660.0" y="220.0"></omgdc:Bounds>41</bpmndi:BPMNShape>42<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">43<omgdi:waypoint x="165.0" y="237.0"></omgdi:waypoint>44<omgdi:waypoint x="210.0" y="237.0"></omgdi:waypoint>45</bpmndi:BPMNEdge>46<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">47<omgdi:waypoint x="315.0" y="237.0"></omgdi:waypoint>48<omgdi:waypoint x="360.0" y="237.0"></omgdi:waypoint>49</bpmndi:BPMNEdge>50<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">51<omgdi:waypoint x="465.0" y="237.0"></omgdi:waypoint>52<omgdi:waypoint x="510.0" y="237.0"></omgdi:waypoint>53</bpmndi:BPMNEdge>54<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">55<omgdi:waypoint x="615.0" y="237.0"></omgdi:waypoint>56<omgdi:waypoint x="660.0" y="237.0"></omgdi:waypoint>57</bpmndi:BPMNEdge>58</bpmndi:BPMNPlane>59</bpmndi:BPMNDiagram>60 61 </definitions>

文章插图
1 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 23 RepositoryService repositoryService = processEngine.getRepositoryService(); 45 Deployment deployment = repositoryService.createDeployment() 6.addClasspathResource("diagram/holiday.bpmn") 7.addClasspathResource("diagram/holiday.png") 8.name("请假流程") 9.key("holiday")10.deploy();11 12 13 //Deployment deployment = repositoryService.createDeployment()14 //.addZipInputStream()15 //.name()16 //.key()17 //.deploy();18 19 System.out.println(deployment.getId());也可以把这两个文件放在一起打包程一个zip压缩包

文章插图

文章插图

文章插图
可以看到,act_re_procdef表中关联了act_re_deployment的ID,act_ge_bytearray表中也关联了act_re_deployment的ID
processDefinitionId是holiday:1:4
deploymentId是1
1 RepositoryService repositoryService = processEngine.getRepositoryService(); 23 //查询流程部署 4 Deployment deployment = repositoryService.createDeploymentQuery().deploymentKey("holiday").singleResult(); 5 //查询流程定义 6 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult(); 7 //流程定义是否被挂起/暂停 8 boolean suspended = processDefinition.isSuspended(); 9 //删除部署10 repositoryService.deleteDeployment(deployment.getId());11 //激活流程定义12 repositoryService.activateProcessDefinitionById(processDefinition.getId());13 //挂起/暂停流程定义14 repositoryService.suspendProcessDefinitionById(processDefinition.getId());15 //查看流程图图片16 InputStream is = repositoryService.getResourceAsStream(deployment.getId(), processDefinition.getDiagramResourceName());3.3. 流程实例

文章插图
1 RuntimeService runtimeService = processEngine.getRuntimeService(); 23 Map<String, Object> variables = new HashMap<>(); 4 variables.put("assignee1", "zhangsan"); 5 variables.put("assignee2", "lisi"); 78 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday", variables); 9 10 System.out.println(processInstance.getProcessInstanceId());11 System.out.println(processInstance.getProcessDefinitionId());

文章插图

文章插图

文章插图

文章插图
3.5. 任务
1 TaskService taskService = processEngine.getTaskService();2 //查询待办任务3 List<Task> taskList = taskService.createTaskQuery().taskAssignee("zhangsan").list();4 5 for (Task task : taskList) {6//完成任务7taskService.complete(task.getId());8 }现在,已经完成了zhangsan和lisi的任务,流程已经走到人事审批了,看表

文章插图

文章插图

文章插图

文章插图

文章插图
接下来,查询tom和jerry的任务时,就不能用taskAssignee("tom")这样了,因为人事审批这个节点设置的是两个候选者,他们都可以看到任务,但是最终只能由一个人去完成

文章插图
首先,需要声明任务由谁负责,然后再完成,不然任务不会分配给任何人
1 TaskService taskService = processEngine.getTaskService(); 23 //查询待办任务 4 Task task = taskService.createTaskQuery() 5.processDefinitionKey("holiday") 6.taskCandidateUser("tom") 7.singleResult(); 89 //声明任务的责任人是谁10 taskService.claim(task.getId(), "tom");11 12 //完成任务13 taskService.complete(task.getId());在tom拾取了这个任务以后,当前任务就分配给了tom

文章插图

文章插图

文章插图
假设,拾取任务以后不想办理了,可以选择将自己当前的任务指派给其他人办理,或者再还回去
当我们把任务指派给jack以后
1 /** 2* 指派 3*/ 45 //指派的第一种方式 6 taskService.setAssignee(task.getId(), "jack"); 78 //指派的第二种方式 9 taskService.deleteCandidateUser(task.getId(), "tom");10 taskService.addCandidateUser(task.getId(), "jack");

文章插图

文章插图

文章插图
还可以将任务委派给他人做
委派:是将任务节点分给其他人处理,等其他人处理好之后,委派任务会自动回到委派人的任务中
1 //将任务进行委派2 taskService.delegateTask(task.getId(), "rose");3 //被委派人办理任务后,委派人标记任务已完成4 taskService.resolveTask(task.getId());将任务重新放回去
1 /**2* 将任务重新放回去3*/4 //第一种写法5 taskService.unclaim(task.getId());6 //第二种写法7 taskService.setAssignee(task.getId(), null);完整代码片段如下:
1 //查询待办任务 2 Task task = taskService.createTaskQuery() 3.processDefinitionKey("holiday") 4 //.taskCandidateUser("tom") 5.taskAssignee("jack") 6.singleResult(); 78 //拾取任务 9 taskService.claim(task.getId(), "tom");10 11 //指派12 taskService.setAssignee(task.getId(), "jack");13 14 taskService.deleteCandidateUser(task.getId(), "tom");15 taskService.addCandidateUser(task.getId(), "jack");16 17 //重新放回去18 taskService.setAssignee(task.getId(), null);19 taskService.unclaim(task.getId());20 21 //完成任务22 taskService.complete(task.getId());人事审批后,整个流程就结束了

文章插图
一个流程实例走完以后,后续只能通过历史记录去查询它了
1 HistoryService historyService = processEngine.getHistoryService();2 //历史查询3 List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()4.processInstanceId("7501").orderByHistoricActivityInstanceStartTime().asc().list();5 for (HistoricActivityInstance historicActivityInstance : list) {6System.out.println(historicActivityInstance.getActivityName() + ":" + historicActivityInstance.getAssignee());7 }3.6. 网关
前面的请假流程比较简单(PS:故意简单设置的),接下来再看一下稍微复杂一点的报销流程(PS:也是故意复杂设置的)

文章插图
1 <?xml version="1.0" encoding="UTF-8"?>2 <definitions3xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"4xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"5xmlns:xsd="http://www.w3.org/2001/XMLSchema"6xmlns:activiti="http://activiti.org/bpmn"7xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"8xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"9xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" 10typeLanguage="http://www.w3.org/2001/XMLSchema" 11expressionLanguage="http://www.w3.org/1999/XPath" 12targetNamespace="http://www.activiti.org/test"> 1314<process id="expense" name="expense" isExecutable="true"> 15<documentation>报销流程</documentation> 16<startEvent id="startevent1" name="Start"></startEvent> 17<userTask id="usertask1" name="填写报销单" activiti:assignee="${expense.username}"></userTask> 18<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> 19<userTask id="usertask2" name="部门经理审批" activiti:assignee="${deptManager}"></userTask> 20<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow> 21<exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway"></exclusiveGateway> 22<sequenceFlow id="flow3" sourceRef="usertask2" targetRef="exclusivegateway2"></sequenceFlow> 23<userTask id="usertask3" name="人事审批" activiti:assignee="${cho}"></userTask> 24<sequenceFlow id="flow6" sourceRef="exclusivegateway2" targetRef="usertask3"> 25<conditionExpression xsi:type="tFormalExpression"><![CDATA[${expense.amount <= 500}]]></conditionExpression> 26</sequenceFlow> 27<userTask id="usertask4" name="总经理审批" activiti:assignee="${ceo}"></userTask> 28<sequenceFlow id="flow8" sourceRef="usertask4" targetRef="usertask3"></sequenceFlow> 29<sequenceFlow id="flow10" sourceRef="exclusivegateway2" targetRef="usertask4"> 30<conditionExpression xsi:type="tFormalExpression"><![CDATA[${expense.amount > 500}]]></conditionExpression> 31</sequenceFlow> 32<userTask id="usertask5" name="打印申请单" activiti:assignee="zhangsan"></userTask> 33<userTask id="usertask6" name="粘贴发票" activiti:assignee="lisi"></userTask> 34<parallelGateway id="parallelgateway1" name="Parallel Gateway"></parallelGateway> 35<sequenceFlow id="flow11" sourceRef="usertask3" targetRef="parallelgateway1"></sequenceFlow> 36<sequenceFlow id="flow12" sourceRef="parallelgateway1" targetRef="usertask5"></sequenceFlow> 37<sequenceFlow id="flow13" sourceRef="parallelgateway1" targetRef="usertask6"></sequenceFlow> 38<parallelGateway id="parallelgateway2" name="Parallel Gateway"></parallelGateway> 39<sequenceFlow id="flow15" sourceRef="usertask5" targetRef="parallelgateway2"></sequenceFlow> 40<sequenceFlow id="flow16" sourceRef="usertask6" targetRef="parallelgateway2"></sequenceFlow> 41<userTask id="usertask7" name="财务打款" activiti:assignee="${cfo}"></userTask> 42<sequenceFlow id="flow17" sourceRef="parallelgateway2" targetRef="usertask7"></sequenceFlow> 43<endEvent id="endevent1" name="End"></endEvent> 44<sequenceFlow id="flow18" sourceRef="usertask7" targetRef="endevent1"></sequenceFlow> 45</process> 46<bpmndi:BPMNDiagram id="BPMNDiagram_expense"> 47<bpmndi:BPMNPlane bpmnElement="expense" id="BPMNPlane_expense"> 48<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> 49<omgdc:Bounds height="35.0" width="35.0" x="70.0" y="255.0"></omgdc:Bounds> 50</bpmndi:BPMNShape> 51<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"> 52<omgdc:Bounds height="55.0" width="105.0" x="140.0" y="245.0"></omgdc:Bounds> 53</bpmndi:BPMNShape> 54<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"> 55<omgdc:Bounds height="55.0" width="105.0" x="280.0" y="245.0"></omgdc:Bounds> 56</bpmndi:BPMNShape> 57<bpmndi:BPMNShape bpmnElement="exclusivegateway2" id="BPMNShape_exclusivegateway2"> 58<omgdc:Bounds height="40.0" width="40.0" x="430.0" y="252.0"></omgdc:Bounds> 59</bpmndi:BPMNShape> 60<bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"> 61<omgdc:Bounds height="55.0" width="105.0" x="520.0" y="245.0"></omgdc:Bounds> 62</bpmndi:BPMNShape> 63<bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4"> 64<omgdc:Bounds height="55.0" width="105.0" x="520.0" y="130.0"></omgdc:Bounds> 65</bpmndi:BPMNShape> 66<bpmndi:BPMNShape bpmnElement="usertask5" id="BPMNShape_usertask5"> 67<omgdc:Bounds height="55.0" width="105.0" x="750.0" y="159.0"></omgdc:Bounds> 68</bpmndi:BPMNShape> 69<bpmndi:BPMNShape bpmnElement="usertask6" id="BPMNShape_usertask6"> 70<omgdc:Bounds height="55.0" width="105.0" x="750.0" y="320.0"></omgdc:Bounds> 71</bpmndi:BPMNShape> 72<bpmndi:BPMNShape bpmnElement="parallelgateway1" id="BPMNShape_parallelgateway1"> 73<omgdc:Bounds height="40.0" width="40.0" x="680.0" y="252.0"></omgdc:Bounds> 74</bpmndi:BPMNShape> 75<bpmndi:BPMNShape bpmnElement="parallelgateway2" id="BPMNShape_parallelgateway2"> 76<omgdc:Bounds height="40.0" width="40.0" x="880.0" y="252.0"></omgdc:Bounds> 77</bpmndi:BPMNShape> 78<bpmndi:BPMNShape bpmnElement="usertask7" id="BPMNShape_usertask7"> 79<omgdc:Bounds height="55.0" width="105.0" x="961.0" y="245.0"></omgdc:Bounds> 80</bpmndi:BPMNShape> 81<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"> 82<omgdc:Bounds height="35.0" width="35.0" x="1100.0" y="255.0"></omgdc:Bounds> 83</bpmndi:BPMNShape> 84<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> 85<omgdi:waypoint x="105.0" y="272.0"></omgdi:waypoint> 86<omgdi:waypoint x="140.0" y="272.0"></omgdi:waypoint> 87</bpmndi:BPMNEdge> 88<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"> 89<omgdi:waypoint x="245.0" y="272.0"></omgdi:waypoint> 90<omgdi:waypoint x="280.0" y="272.0"></omgdi:waypoint> 91</bpmndi:BPMNEdge> 92<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3"> 93<omgdi:waypoint x="385.0" y="272.0"></omgdi:waypoint> 94<omgdi:waypoint x="430.0" y="272.0"></omgdi:waypoint> 95</bpmndi:BPMNEdge> 96<bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"> 97<omgdi:waypoint x="470.0" y="272.0"></omgdi:waypoint> 98<omgdi:waypoint x="520.0" y="272.0"></omgdi:waypoint> 99</bpmndi:BPMNEdge>100<bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">101<omgdi:waypoint x="572.0" y="185.0"></omgdi:waypoint>102<omgdi:waypoint x="572.0" y="245.0"></omgdi:waypoint>103</bpmndi:BPMNEdge>104<bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">105<omgdi:waypoint x="450.0" y="252.0"></omgdi:waypoint>106<omgdi:waypoint x="450.0" y="157.0"></omgdi:waypoint>107<omgdi:waypoint x="520.0" y="157.0"></omgdi:waypoint>108</bpmndi:BPMNEdge>109<bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">110<omgdi:waypoint x="625.0" y="272.0"></omgdi:waypoint>111<omgdi:waypoint x="680.0" y="272.0"></omgdi:waypoint>112</bpmndi:BPMNEdge>113<bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12">114<omgdi:waypoint x="700.0" y="252.0"></omgdi:waypoint>115<omgdi:waypoint x="700.0" y="186.0"></omgdi:waypoint>116<omgdi:waypoint x="750.0" y="186.0"></omgdi:waypoint>117</bpmndi:BPMNEdge>118<bpmndi:BPMNEdge bpmnElement="flow13" id="BPMNEdge_flow13">119<omgdi:waypoint x="700.0" y="292.0"></omgdi:waypoint>120<omgdi:waypoint x="700.0" y="347.0"></omgdi:waypoint>121<omgdi:waypoint x="750.0" y="347.0"></omgdi:waypoint>122</bpmndi:BPMNEdge>123<bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15">124<omgdi:waypoint x="855.0" y="186.0"></omgdi:waypoint>125<omgdi:waypoint x="900.0" y="186.0"></omgdi:waypoint>126<omgdi:waypoint x="900.0" y="252.0"></omgdi:waypoint>127</bpmndi:BPMNEdge>128<bpmndi:BPMNEdge bpmnElement="flow16" id="BPMNEdge_flow16">129<omgdi:waypoint x="855.0" y="347.0"></omgdi:waypoint>130<omgdi:waypoint x="900.0" y="347.0"></omgdi:waypoint>131<omgdi:waypoint x="900.0" y="292.0"></omgdi:waypoint>132</bpmndi:BPMNEdge>133<bpmndi:BPMNEdge bpmnElement="flow17" id="BPMNEdge_flow17">134<omgdi:waypoint x="920.0" y="272.0"></omgdi:waypoint>135<omgdi:waypoint x="961.0" y="272.0"></omgdi:waypoint>136</bpmndi:BPMNEdge>137<bpmndi:BPMNEdge bpmnElement="flow18" id="BPMNEdge_flow18">138<omgdi:waypoint x="1066.0" y="272.0"></omgdi:waypoint>139<omgdi:waypoint x="1100.0" y="272.0"></omgdi:waypoint>140</bpmndi:BPMNEdge>141</bpmndi:BPMNPlane>142</bpmndi:BPMNDiagram>143 </definitions>引入了排他网关(Exclusive Gateway)和并行网关(Parallel Gateway)
1 @Data2 public class Expense implements Serializable {3//申请人4private String username;5//报销金额6private Integer amount;7 }启动流程实例
1 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 23 RepositoryService repositoryService = processEngine.getRepositoryService(); 4 RuntimeService runtimeService = processEngine.getRuntimeService(); 5 TaskService taskService = processEngine.getTaskService(); 67 //部署流程定义 8 Deployment deployment = repositoryService.createDeployment() 9.addClasspathResource("diagram/expense.bpmn")10.addClasspathResource("diagram/expense.png")11.name("报销流程")12.key("expense")13.deploy();14 15 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()16.deploymentId(deployment.getId())17.singleResult();18 System.out.println(processDefinition.getId());19 20 Expense expense = new Expense();21 expense.setUsername("chengcheng");22 expense.setAmount(520);23 24 Map<String, Object> variables = new HashMap<>();25 variables.put("expense", expense);26 variables.put("deptManager", "tom");27 variables.put("ceo", "jerry");28 variables.put("cho", "rose");29 variables.put("cfo", "jack");30 31 //启动流程实例32 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("expense", variables);33 System.out.println(processInstance.getId());34 35 //查询cheng的待办任务36 Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskAssignee("chengcheng").singleResult();37 if (null != task) {38taskService.complete(task.getId());39 }40 41 //完成tom的待办任务42 task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();43 String assignee = task.getAssignee();44 Assertions.assertEquals("tom", assignee);45 taskService.complete(task.getId());46 47 //判断当前任务走到总经理审批48 task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();49 assignee = task.getAssignee();50 Assertions.assertEquals("jerry", assignee);51 taskService.complete(task.getId());52 53 //完成rose的任务54 task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskAssignee("rose").singleResult();55 if (null != task) {56taskService.complete(task.getId());57 }58 59 //断言当前有2个激活的任务60 List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();61 taskList.forEach(x->{62System.out.println(x.getName() + " : " + x.getAssignee());63 });64 Assertions.assertEquals(2, taskList.size());

文章插图

文章插图

文章插图
当我们完成了zhangsan和lisi的任务以后

文章插图

文章插图

文章插图
接下来,演示包含网关(Inclusive Gateway)

文章插图
1 <?xml version="1.0" encoding="UTF-8"?>2 <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4xmlns:xsd="http://www.w3.org/2001/XMLSchema"5xmlns:activiti="http://activiti.org/bpmn"6xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"7xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"8xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"9typeLanguage="http://www.w3.org/2001/XMLSchema" 10expressionLanguage="http://www.w3.org/1999/XPath" 11targetNamespace="http://www.activiti.org/test"> 1213<process id="HealthExamination" name="HealthExamination" isExecutable="true"> 14<startEvent id="startevent1" name="Start"></startEvent> 15<userTask id="usertask1" name="填写体检申请" activiti:assignee="${username}"></userTask> 16<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> 17<inclusiveGateway id="inclusivegateway1" name="Inclusive Gateway"></inclusiveGateway> 18<userTask id="usertask2" name="常规体检" activiti:assignee="${username}"></userTask> 19<userTask id="usertask3" name="癌症筛查" activiti:assignee="${username}"></userTask> 20<userTask id="usertask4" name="乙肝检查" activiti:assignee="${username}"></userTask> 21<sequenceFlow id="flow2" sourceRef="inclusivegateway1" 22targetRef="usertask2"> 23<conditionExpression xsi:type="tFormalExpression"><![CDATA[${userType == 1 || userType ==2}]]></conditionExpression> 24</sequenceFlow> 25<sequenceFlow id="flow4" sourceRef="inclusivegateway1" 26targetRef="usertask3"> 27<conditionExpression xsi:type="tFormalExpression"><![CDATA[${userType == 2}]]></conditionExpression> 28</sequenceFlow> 29<sequenceFlow id="flow5" sourceRef="inclusivegateway1" 30targetRef="usertask4"> 31<conditionExpression xsi:type="tFormalExpression"><![CDATA[${userType == 1 || userType ==2}]]></conditionExpression> 32</sequenceFlow> 33<sequenceFlow id="flow6" sourceRef="usertask1" targetRef="inclusivegateway1"></sequenceFlow> 34<inclusiveGateway id="inclusivegateway2" name="Inclusive Gateway"></inclusiveGateway> 35<sequenceFlow id="flow8" sourceRef="usertask4" targetRef="inclusivegateway2"></sequenceFlow> 36<sequenceFlow id="flow9" sourceRef="usertask2" targetRef="inclusivegateway2"></sequenceFlow> 37<sequenceFlow id="flow10" sourceRef="usertask3" targetRef="inclusivegateway2"></sequenceFlow> 38<userTask id="usertask5" name="吃早餐" activiti:assignee="${username}"></userTask> 39<endEvent id="endevent1" name="End"></endEvent> 40<sequenceFlow id="flow11" sourceRef="usertask5" targetRef="endevent1"></sequenceFlow> 41<sequenceFlow id="flow12" sourceRef="inclusivegateway2" targetRef="usertask5"></sequenceFlow> 42</process> 4344<bpmndi:BPMNDiagram id="BPMNDiagram_HealthExamination"> 45<bpmndi:BPMNPlane bpmnElement="HealthExamination" id="BPMNPlane_HealthExamination"> 46<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> 47<omgdc:Bounds height="35.0" width="35.0" x="100.0" y="254.0"></omgdc:Bounds> 48</bpmndi:BPMNShape> 49<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"> 50<omgdc:Bounds height="55.0" width="105.0" x="180.0" y="244.0"></omgdc:Bounds> 51</bpmndi:BPMNShape> 52<bpmndi:BPMNShape bpmnElement="inclusivegateway1" id="BPMNShape_inclusivegateway1"> 53<omgdc:Bounds height="40.0" width="40.0" x="370.0" y="251.0"></omgdc:Bounds> 54</bpmndi:BPMNShape> 55<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"> 56<omgdc:Bounds height="55.0" width="105.0" x="490.0" y="150.0"></omgdc:Bounds> 57</bpmndi:BPMNShape> 58<bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"> 59<omgdc:Bounds height="55.0" width="105.0" x="490.0" y="340.0"></omgdc:Bounds> 60</bpmndi:BPMNShape> 61<bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4"> 62<omgdc:Bounds height="55.0" width="105.0" x="490.0" y="244.0"></omgdc:Bounds> 63</bpmndi:BPMNShape> 64<bpmndi:BPMNShape bpmnElement="inclusivegateway2" id="BPMNShape_inclusivegateway2"> 65<omgdc:Bounds height="40.0" width="40.0" x="690.0" y="251.0"></omgdc:Bounds> 66</bpmndi:BPMNShape> 67<bpmndi:BPMNShape bpmnElement="usertask5" id="BPMNShape_usertask5"> 68<omgdc:Bounds height="55.0" width="105.0" x="800.0" y="244.0"></omgdc:Bounds> 69</bpmndi:BPMNShape> 70<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"> 71<omgdc:Bounds height="35.0" width="35.0" x="950.0" y="254.0"></omgdc:Bounds> 72</bpmndi:BPMNShape> 73<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> 74<omgdi:waypoint x="135.0" y="271.0"></omgdi:waypoint> 75<omgdi:waypoint x="180.0" y="271.0"></omgdi:waypoint> 76</bpmndi:BPMNEdge> 77<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"> 78<omgdi:waypoint x="390.0" y="251.0"></omgdi:waypoint> 79<omgdi:waypoint x="390.0" y="177.0"></omgdi:waypoint> 80<omgdi:waypoint x="490.0" y="177.0"></omgdi:waypoint> 81</bpmndi:BPMNEdge> 82<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"> 83<omgdi:waypoint x="390.0" y="291.0"></omgdi:waypoint> 84<omgdi:waypoint x="390.0" y="367.0"></omgdi:waypoint> 85<omgdi:waypoint x="490.0" y="367.0"></omgdi:waypoint> 86</bpmndi:BPMNEdge> 87<bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5"> 88<omgdi:waypoint x="410.0" y="271.0"></omgdi:waypoint> 89<omgdi:waypoint x="490.0" y="271.0"></omgdi:waypoint> 90</bpmndi:BPMNEdge> 91<bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"> 92<omgdi:waypoint x="285.0" y="271.0"></omgdi:waypoint> 93<omgdi:waypoint x="370.0" y="271.0"></omgdi:waypoint> 94</bpmndi:BPMNEdge> 95<bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8"> 96<omgdi:waypoint x="595.0" y="271.0"></omgdi:waypoint> 97<omgdi:waypoint x="690.0" y="271.0"></omgdi:waypoint> 98</bpmndi:BPMNEdge> 99<bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">100<omgdi:waypoint x="595.0" y="177.0"></omgdi:waypoint>101<omgdi:waypoint x="710.0" y="177.0"></omgdi:waypoint>102<omgdi:waypoint x="710.0" y="251.0"></omgdi:waypoint>103</bpmndi:BPMNEdge>104<bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">105<omgdi:waypoint x="595.0" y="367.0"></omgdi:waypoint>106<omgdi:waypoint x="710.0" y="367.0"></omgdi:waypoint>107<omgdi:waypoint x="710.0" y="291.0"></omgdi:waypoint>108</bpmndi:BPMNEdge>109<bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">110<omgdi:waypoint x="905.0" y="271.0"></omgdi:waypoint>111<omgdi:waypoint x="950.0" y="271.0"></omgdi:waypoint>112</bpmndi:BPMNEdge>113<bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12">114<omgdi:waypoint x="730.0" y="271.0"></omgdi:waypoint>115<omgdi:waypoint x="800.0" y="271.0"></omgdi:waypoint>116</bpmndi:BPMNEdge>117</bpmndi:BPMNPlane>118</bpmndi:BPMNDiagram>119 </definitions>用一个userType=1的用户测试一下
1 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 23 RepositoryService repositoryService = processEngine.getRepositoryService(); 4 RuntimeService runtimeService = processEngine.getRuntimeService(); 5 TaskService taskService = processEngine.getTaskService(); 67 Deployment deployment = repositoryService.createDeployment() 8.addClasspathResource("diagram/HealthExamination.bpmn") 9.addClasspathResource("diagram/HealthExamination.png")10.name("体检流程")11.key("HealthExamination")12.deploy();13 14 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()15.deploymentId(deployment.getId())16.singleResult();17 System.out.println(processDefinition.getId());18 19 20 Map<String, Object> variables = new HashMap<>();21 variables.put("username", "cheng");22 variables.put("userType", 1);23 24 //启动流程实例25 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("HealthExamination", variables);26 System.out.println(processInstance.getId());27 28 //查询cheng的待办任务29 Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskAssignee("cheng").singleResult();30 if (null != task) {31taskService.complete(task.getId());32 }33 34 //断言进入包含网关之后cheng有两个待办任务,因为他的userType=135 List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();36 Assertions.assertEquals(2, taskList.size());

文章插图

文章插图

文章插图
1 Map<String, Object> variables = new HashMap<>(); 2 variables.put("username", "chengcheng"); 3 variables.put("userType", 2); 45 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("HealthExamination", variables); 67 Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskAssignee("chengcheng").singleResult(); 8 if (null != task) { 9taskService.complete(task.getId());10 }11 12 List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();13 Assertions.assertEquals(3, taskList.size());

文章插图

文章插图
相关文档
https://www.activiti.org/
https://camunda.com/bpmn/
https://bpmn.io/
http://www.pangubpm.com/
【activities怎么读 Activiti7 入门篇】http://www.yunchengxc.com/
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
