Activiti7 入門篇

1.  工作流

簡單地來講,工作流就是在電腦的協助下實現流程的自動化控制。目前,筆者熟知的主流的框架有:Camunda 、Flowable 、Activiti 、jBPM、還有我們國產的盤古BPM。其中,Camunda 、Flowable 都有商業版(企業版)和非商業版(社區開源版)。

技術產品各有千秋,Flowable專註於流程引擎,Activiti現在專註於Cloud。筆者最推薦Camunda,盤古BPM還沒用過看起來應該也挺好用的。

關於Camunda補充幾篇文章

2.  流程設計器

筆者親測,IntelliJ IDEA 2021.1 (Ultimate Edition)  不支援 actiBPM插件。

強烈推薦用 camunda-modeler ,或者用 bpmn-js

首先,下載Camunda

//camunda.com/download/

解壓以後,直接雙擊.exe文件運行

也可以在IDEA中把它作為外部工具用

筆者更習慣直接雙擊.exe打開

Activiti為Eclipse開發了一個BPM插件「Activiti Eclipse Designer」

//www.activiti.org/userguide/index.html#activitiDesigner

為了使用Activiti Designer,筆者又下載了Eclipse IDE,專門為了Activiti開發

3.  Activiti7 快速開始

工作流的作用是實現流程的自動化控制。使用Activiti這種工作流框架大致都分為以下幾個步驟:

  1. 流程定義
  2. 部署流程定義
  3. 啟動流程實例
  4. 查詢代表任務
  5. 完成任務
  6. 結束流程

術語補充:

  • 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;
 2 
 3 import org.activiti.engine.ProcessEngine;
 4 import org.activiti.engine.ProcessEngineConfiguration;
 5 import org.activiti.engine.ProcessEngines;
 6 import org.junit.jupiter.api.Test;
 7 
 8 /**
 9  * @Author ChengJianSheng
10  * @Date 2021/7/6
11  */
12 public class ProcessEngineTests {
13 
14     @Test
15     public void testProcessEngine1() {
16         ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
17         System.out.println(processEngine);
18     }
19 
20     @Test
21     public void testProcessEngine2() {
22         ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
23         ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
24         System.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="//www.springframework.org/schema/beans"
 3        xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="//www.springframework.org/schema/beans //www.springframework.org/schema/beans/spring-beans.xsd">
 5 
 6     <bean id="processEngineConfiguration" name="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
 7         <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
 8         <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&amp;characterEncoding=utf8"/>
 9         <property name="jdbcUsername" value="root"/>
10         <property name="jdbcPassword" value="123456"/>
11         <property name="databaseSchemaUpdate" value="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="//www.omg.org/spec/BPMN/20100524/MODEL"
 3              xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
 4              xmlns:xsd="//www.w3.org/2001/XMLSchema"
 5              xmlns:activiti="//activiti.org/bpmn"
 6              xmlns:bpmndi="//www.omg.org/spec/BPMN/20100524/DI"
 7              xmlns:omgdc="//www.omg.org/spec/DD/20100524/DC"
 8              xmlns:omgdi="//www.omg.org/spec/DD/20100524/DI"
 9              typeLanguage="//www.w3.org/2001/XMLSchema"
10              expressionLanguage="//www.w3.org/1999/XPath"
11              targetNamespace="//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();
 2 
 3 RepositoryService repositoryService = processEngine.getRepositoryService();
 4 
 5 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();
 2 
 3 //  查詢流程部署
 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();
 2 
 3 Map<String, Object> variables = new HashMap<>();
 4 variables.put("assignee1", "zhangsan");
 5 variables.put("assignee2", "lisi");
 7 
 8 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     //  完成任務
7     taskService.complete(task.getId());
8 }

現在,已經完成了zhangsan和lisi的任務,流程已經走到人事審批了,看錶

 

接下來,查詢tom和jerry的任務時,就不能用taskAssignee(“tom”)這樣了,因為人事審批這個節點設置的是兩個候選者,他們都可以看到任務,但是最終只能由一個人去完成

首先,需要聲明任務由誰負責,然後再完成,不然任務不會分配給任何人

 1 TaskService taskService = processEngine.getTaskService();
 2 
 3 //  查詢待辦任務
 4 Task task = taskService.createTaskQuery()
 5         .processDefinitionKey("holiday")
 6         .taskCandidateUser("tom")
 7         .singleResult();
 8 
 9 //  聲明任務的責任人是誰
10 taskService.claim(task.getId(), "tom");
11 
12 //  完成任務
13 taskService.complete(task.getId());

在tom拾取了這個任務以後,當前任務就分配給了tom

假設,拾取任務以後不想辦理了,可以選擇將自己當前的任務指派給其他人辦理,或者再還回去

當我們把任務指派給jack以後

 1 /**
 2  * 指派
 3  */
 4 
 5 //  指派的第一種方式
 6 taskService.setAssignee(task.getId(), "jack");
 7 
 8 //  指派的第二種方式
 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();
 7 
 8 //  拾取任務
 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) {
6     System.out.println(historicActivityInstance.getActivityName() + ":" + historicActivityInstance.getAssignee());
7 }

3.6.  網關

前面的請假流程比較簡單(PS:故意簡單設置的),接下來再看一下稍微複雜一點的報銷流程(PS:也是故意複雜設置的)

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <definitions
  3     xmlns="//www.omg.org/spec/BPMN/20100524/MODEL"
  4     xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
  5     xmlns:xsd="//www.w3.org/2001/XMLSchema"
  6     xmlns:activiti="//activiti.org/bpmn"
  7     xmlns:bpmndi="//www.omg.org/spec/BPMN/20100524/DI"
  8     xmlns:omgdc="//www.omg.org/spec/DD/20100524/DC"
  9     xmlns:omgdi="//www.omg.org/spec/DD/20100524/DI"
 10     typeLanguage="//www.w3.org/2001/XMLSchema"
 11     expressionLanguage="//www.w3.org/1999/XPath"
 12     targetNamespace="//www.activiti.org/test">
 13     
 14     <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 @Data
2 public class Expense implements Serializable {
3     //  申請人
4     private String username;
5     //  報銷金額
6     private Integer amount;
7 }

啟動流程實例

 1 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
 2 
 3 RepositoryService repositoryService = processEngine.getRepositoryService();
 4 RuntimeService runtimeService = processEngine.getRuntimeService();
 5 TaskService taskService = processEngine.getTaskService();
 6 
 7 //  部署流程定義
 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) {
38     taskService.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) {
56     taskService.complete(task.getId());
57 }
58 
59 //  斷言當前有2個激活的任務
60 List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
61 taskList.forEach(x->{
62     System.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="//www.omg.org/spec/BPMN/20100524/MODEL" 
  3     xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
  4     xmlns:xsd="//www.w3.org/2001/XMLSchema"
  5     xmlns:activiti="//activiti.org/bpmn"
  6     xmlns:bpmndi="//www.omg.org/spec/BPMN/20100524/DI"
  7     xmlns:omgdc="//www.omg.org/spec/DD/20100524/DC"
  8     xmlns:omgdi="//www.omg.org/spec/DD/20100524/DI"
  9     typeLanguage="//www.w3.org/2001/XMLSchema"
 10     expressionLanguage="//www.w3.org/1999/XPath"
 11     targetNamespace="//www.activiti.org/test">
 12     
 13     <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"
 22             targetRef="usertask2">
 23             <conditionExpression xsi:type="tFormalExpression"><![CDATA[${userType == 1 || userType ==2}]]></conditionExpression>
 24         </sequenceFlow>
 25         <sequenceFlow id="flow4" sourceRef="inclusivegateway1"
 26             targetRef="usertask3">
 27             <conditionExpression xsi:type="tFormalExpression"><![CDATA[${userType == 2}]]></conditionExpression>
 28         </sequenceFlow>
 29         <sequenceFlow id="flow5" sourceRef="inclusivegateway1"
 30             targetRef="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>
 43     
 44     <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();
 2 
 3 RepositoryService repositoryService = processEngine.getRepositoryService();
 4 RuntimeService runtimeService = processEngine.getRuntimeService();
 5 TaskService taskService = processEngine.getTaskService();
 6 
 7 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) {
31     taskService.complete(task.getId());
32 }
33 
34 //  斷言進入包含網關之後cheng有兩個待辦任務,因為他的userType=1
35 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);
 4 
 5 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("HealthExamination", variables);
 6 
 7 Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskAssignee("chengcheng").singleResult();
 8 if (null != task) {
 9     taskService.complete(task.getId());
10 }
11 
12 List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
13 Assertions.assertEquals(3, taskList.size());

 

 

相關文檔

//www.activiti.org/ 

//camunda.com/bpmn/

//bpmn.io/

//www.pangubpm.com/ 

 

Tags: