springboot + flowable工作流

背景:项目涉及到审批,用工作流会合适一点。由于之前未接触过,因此选用在activiti基础上开发的flowable进行

需求:在springboot中引入flowable并封装操作(初次使用,仅供参考)

方法:

   一、引入依赖

<dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter</artifactId>
            <version>6.4.2</version>
        </dependency>

    

   二、封装操作工具(FlowableUtil)

  1 import com.hztech.framework.util.SpringBeanUtil;
  2 import com.ruoyi.common.exception.CustomException;
  3 import org.flowable.engine.ProcessEngine;
  4 import org.flowable.engine.RuntimeService;
  5 import org.flowable.engine.TaskService;
  6 import org.flowable.engine.runtime.ProcessInstance;
  7 import org.flowable.task.api.Task;
  8 import org.jetbrains.annotations.NotNull;
  9 
 10 import java.util.ArrayList;
 11 import java.util.HashMap;
 12 import java.util.List;
 13 
 14 /**
 15  * @ClassName FlowableUtil
 16  * @Description 工作流工具
 17  * @Author 包海鹏
 18  * @Date 2020/4/27 14:45
 19  * @Version 1.0
 20  **/
 21 public class FlowableUtil {
 22 
 23     /**
 24      * 流程运行控制服务
 25      */
 26     private RuntimeService runtimeService;
 27 
 28     /**
 29      * 任务管理服务
 30      */
 31     private TaskService taskService;
 32 
 33     /**
 34      * 流程引擎
 35      */
 36     private ProcessEngine processEngine;
 37 
 38     /**
 39      * 初始化获取实例
 40      */
 41     public FlowableUtil() {
 42         runtimeService = SpringBeanUtil.getBean(RuntimeService.class);
 43         taskService = SpringBeanUtil.getBean(TaskService.class);
 44         processEngine = SpringBeanUtil.getBean(ProcessEngine.class);
 45     }
 46 
 47 
 48     /**
 49      * 启动流程
 50      *
 51      * @param processKey  流程定义key(流程图ID)
 52      * @param businessKey 业务key
 53      * @param map         参数键值对
 54      * @return 流程实例ID
 55      * @Author 包海鹏
 56      */
 57     public String start(String processKey, String businessKey, HashMap<String, Object> map) {
 58 
 59         ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, businessKey, map);
 60         return processInstance.getId();
 61     }
 62 
 63     /**
 64      * 终止流程
 65      *
 66      * @param processInstanceId 流程实例ID
 67      * @param reason            终止理由
 68      * @Author 包海鹏
 69      */
 70     public void stop(String processInstanceId, String reason) {
 71 
 72         runtimeService.deleteProcessInstance(processInstanceId, reason);
 73     }
 74 
 75 
 76     /**
 77      * 获取指定用户的任务列表(创建时间倒序)
 78      *
 79      * @param userId 用户ID
 80      * @return 任务列表
 81      * @Author 包海鹏
 82      */
 83     public List<Task> getListByUserId(String userId) {
 84 
 85         List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
 86         for (Task task : tasks) {
 87             System.out.println(task.toString());
 88         }
 89         return tasks;
 90     }
 91 
 92     /**
 93      * 获取指定用户组的任务列表
 94      *
 95      * @param group 用户组
 96      * @return 任务列表
 97      * @Author 包海鹏
 98      */
 99     public List<Task> getListByGroup(String group) {
100 
101         List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup(group).orderByTaskCreateTime().desc().list();
102         for (Task task : tasks) {
103             System.out.println(task.toString());
104         }
105         return tasks;
106     }
107 
108 
109     /**
110      * 完成指定任务
111      *
112      * @param taskId 任务ID
113      * @param map    变量键值对
114      * @Author 包海鹏
115      */
116     public void complete(String taskId, HashMap<String, Object> map) {
117 
118         Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
119         if (task == null) {
120             throw new CustomException("流程不存在");
121         }
122         taskService.complete(taskId, map);
123     }
124 
125     /**
126      * 获取指定任务列表中的特定任务
127      *
128      * @param list        任务列表
129      * @param businessKey 业务key
130      * @return 任务
131      * @Author 包海鹏
132      */
133     public Task getOneByBusinessKey(@NotNull List<Task> list, String businessKey) {
134 
135         Task task = null;
136         for (Task t : list) {
137             // 通过任务对象获取流程实例
138             ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult();
139             if (businessKey.equals(pi.getBusinessKey())) {
140                 task = t;
141             }
142         }
143         return task;
144     }
145 
146     /**
147      * 创建流程并完成第一个任务
148      *
149      * @param processKey  流程定义key(流程图ID)
150      * @param businessKey 业务key
151      * @param map         变量键值对
152      * @Author 包海鹏
153      */
154     public void startAndComplete(String processKey, String businessKey, HashMap<String, Object> map) {
155 
156         String processInstanceId = start(processKey, businessKey, map);
157         Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(processInstanceId).singleResult();
158         taskService.complete(task.getId(), map);
159 
160     }
161 
162     /**
163      * 退回到指定任务节点
164      *
165      * @param currentTaskId 当前任务ID
166      * @param targetTaskKey 目标任务节点key
167      * @Author 包海鹏
168      */
169     public void backToStep(String currentTaskId, String targetTaskKey) {
170 
171         Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();
172         if (currentTask == null) {
173             throw new CustomException("当前任务节点不存在");
174         }
175         List<String> currentTaskKeys = new ArrayList<>();
176         currentTaskKeys.add(currentTask.getTaskDefinitionKey());
177         runtimeService.createChangeActivityStateBuilder().processInstanceId(currentTask.getProcessInstanceId()).moveActivityIdsToSingleActivityId(currentTaskKeys, targetTaskKey);
178     }
179 }

   二、封装业务工具(ExitUtil、PlanUtil)

 1 import com.hztech.mscm.util.FlowableUtil;
 2 import org.flowable.task.api.Task;
 3 
 4 import java.util.HashMap;
 5 import java.util.List;
 6 
 7 /**
 8  * @ClassName PlanUtil
 9  * @Description 出库模块工作流工具
10  * @Author 包海鹏
11  * @Date 2020/3/11 15:37
12  * @Version 1.0
13  **/
14 public class ExitUtil {
15 
16     private static final String EXIT_PROCESS_KEY = "exit";
17 
18 
19     /**
20      * 提交
21      *
22      * @param inputUserId      申请人ID
23      * @param audiUserId 审核人ID
24      * @param exitId           出库单ID
25      */
26     public static void submit(String inputUserId, String audiUserId, String exitId) {
27 
28         if (inputUserId.isEmpty() || audiUserId.isEmpty() || exitId.isEmpty()) {
29             throw new RuntimeException("【saveAndSubmit】参数缺失!");
30         }
31 
32         HashMap<String, Object> map = new HashMap<>();
33         map.put("inputUserId", inputUserId);
34         map.put("audiUserId", audiUserId);
35         FlowableUtil util = new FlowableUtil();
36         util.startAndComplete(EXIT_PROCESS_KEY, exitId, map);
37     }
38 
39     /**
40      * 通过-审核
41      *
42      * @param userId        审核操作人ID
43      * @param exitId        出库单ID
44      */
45     public static void successApplyDepartment(String userId,  String exitId) {
46 
47         HashMap<String, Object> map = new HashMap<>();
48         map.put("outcome", "YES");
49         apply(userId, exitId, map);
50     }
51 
52     /**
53      * 拒绝-审核
54      *
55      * @param userId 审核操作人ID
56      * @param exitId 采购计划ID
57      */
58     public static void failApplyDepartment(String userId, String exitId) {
59 
60         HashMap<String, Object> map = new HashMap<>();
61         map.put("outcome", "NO");
62         apply(userId, exitId, map);
63     }
64 
65 
66     /**
67      * 申请处理方法
68      *
69      * @param userId 申请操作人ID
70      * @param exitId 出库单ID
71      * @param map    变量组
72      */
73     private static void apply(String userId, String exitId, HashMap<String, Object> map) {
74 
75         FlowableUtil util = new FlowableUtil();
76         List<Task> list = util.getTaskList(userId);
77         Task task = util.getOneTask(list, exitId);
78         if (null != task) {
79             util.complete(task.getId(), map);
80         }
81 
82     }
83 }
  1 import com.hztech.mscm.util.FlowableUtil;
  2 import org.flowable.task.api.Task;
  3 
  4 import java.util.HashMap;
  5 import java.util.List;
  6 
  7 /**
  8  * @ClassName PlanUtil
  9  * @Description 采购模块工作流工具
 10  * @Author 包海鹏
 11  * @Date 2020/3/11 15:37
 12  * @Version 1.0
 13  **/
 14 public class PlanUtil {
 15 
 16     private static final String PLAN_PROCESS_KEY = "plan";
 17 
 18 
 19     /**
 20      * 提交
 21      *
 22      * @param inputUserId      采购申请人ID
 23      * @param departmentUserId 部门审核人ID
 24      * @param planId           采购计划ID
 25      */
 26     public static void submit(String inputUserId, String departmentUserId, String planId) {
 27 
 28         if (inputUserId.isEmpty() || departmentUserId.isEmpty() || planId.isEmpty()) {
 29             throw new RuntimeException("【saveAndSubmit】参数缺失!");
 30         }
 31 
 32         HashMap<String, Object> map = new HashMap<>();
 33         map.put("inputUserId", inputUserId);
 34         map.put("departmentUserId", departmentUserId);
 35         FlowableUtil util = new FlowableUtil();
 36         util.startAndComplete(PLAN_PROCESS_KEY, planId, map);
 37     }
 38 
 39     /**
 40      * 通过-部门审核
 41      *
 42      * @param userId        审核操作人ID
 43      * @param companyUserId 公司审批人ID
 44      * @param planId        采购计划ID
 45      */
 46     public static void successApplyDepartment(String userId, String companyUserId, String planId) {
 47 
 48         HashMap<String, Object> map = new HashMap<>();
 49         map.put("companyUserId", companyUserId);
 50         map.put("outcome", "YES");
 51         apply(userId, planId, map);
 52     }
 53 
 54     /**
 55      * 拒绝-部门审核
 56      *
 57      * @param userId 审核操作人ID
 58      * @param planId 采购计划ID
 59      */
 60     public static void failApplyDepartment(String userId, String planId) {
 61 
 62         HashMap<String, Object> map = new HashMap<>();
 63         map.put("outcome", "NO");
 64         apply(userId, planId, map);
 65     }
 66 
 67     /**
 68      * 通过-公司审批
 69      *
 70      * @param userId 审批操作人ID
 71      * @param planId 采购计划ID
 72      */
 73     public static void successApplyCompany(String userId, String planId) {
 74 
 75         HashMap<String, Object> map = new HashMap<>();
 76         map.put("outcome", "YES");
 77         apply(userId, planId, map);
 78     }
 79 
 80     /**
 81      * 拒绝-公司审批
 82      *
 83      * @param userId 审批操作人ID
 84      * @param planId 采购计划ID
 85      */
 86     public static void failApplyCompany(String userId, String planId) {
 87 
 88         HashMap<String, Object> map = new HashMap<>();
 89         map.put("outcome", "NO");
 90         apply(userId, planId, map);
 91     }
 92 
 93     /**
 94      * 申请处理方法
 95      *
 96      * @param userId 申请操作人ID
 97      * @param planId 采购计划ID
 98      * @param map    变量组
 99      */
100     private static void apply(String userId, String planId, HashMap<String, Object> map) {
101 
102         FlowableUtil util = new FlowableUtil();
103         List<Task> list = util.getTaskList(userId);
104         Task task = util.getOneTask(list, planId);
105         if (null != task) {
106             util.complete(task.getId(), map);
107         }
108 
109     }
110 }

   三、放置流程图

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <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:flowable="http://flowable.org/bpmn" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
 3   <process id="exit" name="出库" isExecutable="true">
 4     <startEvent id="startEvent1"></startEvent>
 5     <userTask id="sid-84B1745B-2537-454B-BA36-2C857AAA1970" name="创建出库单" flowable:assignee="${inputUserId}">
 6       <extensionElements>
 7         <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
 8       </extensionElements>
 9     </userTask>
10     <sequenceFlow id="sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C" sourceRef="startEvent1" targetRef="sid-84B1745B-2537-454B-BA36-2C857AAA1970"></sequenceFlow>
11     <userTask id="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" name="审核" flowable:assignee="${audiUserId}">
12       <extensionElements>
13         <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
14       </extensionElements>
15     </userTask>
16     <sequenceFlow id="sid-51E82709-526B-49A3-95D1-483934328025" sourceRef="sid-84B1745B-2537-454B-BA36-2C857AAA1970" targetRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E"></sequenceFlow>
17     <endEvent id="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44"></endEvent>
18     <sequenceFlow id="sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7" sourceRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" targetRef="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44">
19       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome="NO"}]]></conditionExpression>
20     </sequenceFlow>
21     <sequenceFlow id="sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2" sourceRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" targetRef="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44">
22       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome="YES"}]]></conditionExpression>
23     </sequenceFlow>
24   </process>
25   <bpmndi:BPMNDiagram id="BPMNDiagram_exit">
26     <bpmndi:BPMNPlane bpmnElement="exit" id="BPMNPlane_exit">
27       <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
28         <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
29       </bpmndi:BPMNShape>
30       <bpmndi:BPMNShape bpmnElement="sid-84B1745B-2537-454B-BA36-2C857AAA1970" id="BPMNShape_sid-84B1745B-2537-454B-BA36-2C857AAA1970">
31         <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds>
32       </bpmndi:BPMNShape>
33       <bpmndi:BPMNShape bpmnElement="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" id="BPMNShape_sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E">
34         <omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds>
35       </bpmndi:BPMNShape>
36       <bpmndi:BPMNShape bpmnElement="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44" id="BPMNShape_sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44">
37         <omgdc:Bounds height="28.0" width="28.0" x="540.0" y="164.0"></omgdc:Bounds>
38       </bpmndi:BPMNShape>
39       <bpmndi:BPMNEdge bpmnElement="sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7" id="BPMNEdge_sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7">
40         <omgdi:waypoint x="370.0" y="217.95000000000002"></omgdi:waypoint>
41         <omgdi:waypoint x="370.0" y="273.0"></omgdi:waypoint>
42         <omgdi:waypoint x="554.0" y="273.0"></omgdi:waypoint>
43         <omgdi:waypoint x="554.0" y="191.94993609491092"></omgdi:waypoint>
44       </bpmndi:BPMNEdge>
45       <bpmndi:BPMNEdge bpmnElement="sid-51E82709-526B-49A3-95D1-483934328025" id="BPMNEdge_sid-51E82709-526B-49A3-95D1-483934328025">
46         <omgdi:waypoint x="274.9499999999907" y="178.0"></omgdi:waypoint>
47         <omgdi:waypoint x="319.9999999999807" y="178.0"></omgdi:waypoint>
48       </bpmndi:BPMNEdge>
49       <bpmndi:BPMNEdge bpmnElement="sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C" id="BPMNEdge_sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C">
50         <omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint>
51         <omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint>
52       </bpmndi:BPMNEdge>
53       <bpmndi:BPMNEdge bpmnElement="sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2" id="BPMNEdge_sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2">
54         <omgdi:waypoint x="419.9499999999156" y="178.0"></omgdi:waypoint>
55         <omgdi:waypoint x="540.0" y="178.0"></omgdi:waypoint>
56       </bpmndi:BPMNEdge>
57     </bpmndi:BPMNPlane>
58   </bpmndi:BPMNDiagram>
59 </definitions>
<?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:flowable="http://flowable.org/bpmn" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
  <process id="plan" name="采购" isExecutable="true">
    <documentation>采购流程</documentation>
    <startEvent id="startEvent1"></startEvent>
    <userTask id="makePlan" name="编写采购单" flowable:assignee="${inputUserId}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB" sourceRef="startEvent1" targetRef="makePlan"></sequenceFlow>
    <userTask id="department" name="部门审核" flowable:assignee="${departmentUserId}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="company" name="公司审批" flowable:assignee="${companyUserId}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <endEvent id="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5" name="结束"></endEvent>
    <sequenceFlow id="f1" sourceRef="makePlan" targetRef="department"></sequenceFlow>
    <sequenceFlow id="departmentYes" name="通过" sourceRef="department" targetRef="company">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="YES"}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="companyYes" name="通过" sourceRef="company" targetRef="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="YES"}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="departmentNo" name="拒绝" sourceRef="department" targetRef="makePlan">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="NO"}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="companyNo" name="拒绝" sourceRef="company" targetRef="makePlan">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="NO"}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_plan">
    <bpmndi:BPMNPlane bpmnElement="plan" id="BPMNPlane_plan">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="makePlan" id="BPMNShape_makePlan">
        <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="department" id="BPMNShape_department">
        <omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="company" id="BPMNShape_company">
        <omgdc:Bounds height="80.0" width="100.0" x="465.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5" id="BPMNShape_sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5">
        <omgdc:Bounds height="28.0" width="28.0" x="610.0" y="164.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="companyYes" id="BPMNEdge_companyYes">
        <omgdi:waypoint x="564.95" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="610.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="companyNo" id="BPMNEdge_companyNo">
        <omgdi:waypoint x="515.0" y="138.0"></omgdi:waypoint>
        <omgdi:waypoint x="515.0" y="56.0"></omgdi:waypoint>
        <omgdi:waypoint x="225.0" y="56.0"></omgdi:waypoint>
        <omgdi:waypoint x="225.0" y="138.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB" id="BPMNEdge_sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB">
        <omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="departmentYes" id="BPMNEdge_departmentYes">
        <omgdi:waypoint x="419.94999999999067" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="464.9999999999807" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="departmentNo" id="BPMNEdge_departmentNo">
        <omgdi:waypoint x="370.0" y="217.95000000000002"></omgdi:waypoint>
        <omgdi:waypoint x="370.0" y="296.0"></omgdi:waypoint>
        <omgdi:waypoint x="225.0" y="296.0"></omgdi:waypoint>
        <omgdi:waypoint x="225.0" y="217.95000000000002"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="f1" id="BPMNEdge_f1">
        <omgdi:waypoint x="274.9499999999907" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="319.9999999999807" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
原文地址:https://www.cnblogs.com/java-bhp/p/12522423.html