Commit 83a133b344664889571cbe839b8b73dd56d1ae67

Authored by YunaiV
1 parent ffdaf3a8

bpm:优化 BpmnModelUtils

yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/ModelUtils.java renamed to yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java
1 package cn.iocoder.yudao.framework.flowable.core.util; 1 package cn.iocoder.yudao.framework.flowable.core.util;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import org.flowable.bpmn.converter.BpmnXMLConverter;
3 import org.flowable.bpmn.model.Process; 5 import org.flowable.bpmn.model.Process;
4 import org.flowable.bpmn.model.*; 6 import org.flowable.bpmn.model.*;
5 7
6 -import java.util.ArrayList;  
7 -import java.util.HashSet;  
8 -import java.util.List;  
9 -import java.util.Set; 8 +import java.util.*;
10 9
11 /** 10 /**
12 * 流程模型转操作工具类 11 * 流程模型转操作工具类
13 */ 12 */
14 -public class ModelUtils { 13 +public class BpmnModelUtils {
15 14
16 /** 15 /**
17 * 根据节点,获取入口连线 16 * 根据节点,获取入口连线
@@ -20,14 +19,12 @@ public class ModelUtils { @@ -20,14 +19,12 @@ public class ModelUtils {
20 * @return 入口连线列表 19 * @return 入口连线列表
21 */ 20 */
22 public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) { 21 public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
23 - List<SequenceFlow> sequenceFlows = new ArrayList<>();  
24 if (source instanceof FlowNode) { 22 if (source instanceof FlowNode) {
25 - sequenceFlows = ((FlowNode) source).getIncomingFlows(); 23 + return ((FlowNode) source).getIncomingFlows();
26 } 24 }
27 - return sequenceFlows; 25 + return new ArrayList<>();
28 } 26 }
29 27
30 -  
31 /** 28 /**
32 * 根据节点,获取出口连线 29 * 根据节点,获取出口连线
33 * 30 *
@@ -35,19 +32,17 @@ public class ModelUtils { @@ -35,19 +32,17 @@ public class ModelUtils {
35 * @return 出口连线列表 32 * @return 出口连线列表
36 */ 33 */
37 public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) { 34 public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
38 - List<SequenceFlow> sequenceFlows = new ArrayList<>();  
39 if (source instanceof FlowNode) { 35 if (source instanceof FlowNode) {
40 - sequenceFlows = ((FlowNode) source).getOutgoingFlows(); 36 + return ((FlowNode) source).getOutgoingFlows();
41 } 37 }
42 - return sequenceFlows; 38 + return new ArrayList<>();
43 } 39 }
44 40
45 -  
46 /** 41 /**
47 * 获取流程元素信息 42 * 获取流程元素信息
48 * 43 *
49 - * @param model bpmnModel对象  
50 - * @param flowElementId 元素ID 44 + * @param model bpmnModel 对象
  45 + * @param flowElementId 元素 ID
51 * @return 元素信息 46 * @return 元素信息
52 */ 47 */
53 public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) { 48 public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
@@ -56,50 +51,92 @@ public class ModelUtils { @@ -56,50 +51,92 @@ public class ModelUtils {
56 } 51 }
57 52
58 /** 53 /**
  54 + * 获得 BPMN 流程中,指定的元素们
  55 + *
  56 + * @param model
  57 + * @param clazz 指定元素。例如说,{@link UserTask}、{@link Gateway} 等等
  58 + * @return 元素们
  59 + */
  60 + public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {
  61 + List<T> result = new ArrayList<>();
  62 + model.getProcesses().forEach(process -> {
  63 + process.getFlowElements().forEach(flowElement -> {
  64 + if (flowElement.getClass().isAssignableFrom(clazz)) {
  65 + result.add((T) flowElement);
  66 + }
  67 + });
  68 + });
  69 + return result;
  70 + }
  71 +
  72 + /**
  73 + * 比较 两个bpmnModel 是否相同
  74 + * @param oldModel 老的bpmn model
  75 + * @param newModel 新的bpmn model
  76 + */
  77 + public static boolean equals(BpmnModel oldModel, BpmnModel newModel) {
  78 + // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较
  79 + return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));
  80 + }
  81 +
  82 + /**
  83 + * 把 bpmnModel 转换成 byte[]
  84 + * @param model bpmnModel
  85 + */
  86 + public static byte[] getBpmnBytes(BpmnModel model) {
  87 + if (model == null) {
  88 + return new byte[0];
  89 + }
  90 + BpmnXMLConverter converter = new BpmnXMLConverter();
  91 + return converter.convertToXML(model);
  92 + }
  93 +
  94 + // ========== 遍历相关的方法 ==========
  95 +
  96 + /**
59 * 找到 source 节点之前的所有用户任务节点 97 * 找到 source 节点之前的所有用户任务节点
60 * 98 *
61 * @param source 起始节点 99 * @param source 起始节点
62 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 100 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
63 * @param userTaskList 已找到的用户任务节点 101 * @param userTaskList 已找到的用户任务节点
64 - * @return 102 + * @return 用户任务节点 数组
65 */ 103 */
66 - public static List<UserTask> getPreUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) { 104 + public static List<UserTask> getPreviousUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
67 userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; 105 userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
68 hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; 106 hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
69 -  
70 // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 107 // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
71 if (source instanceof StartEvent && source.getSubProcess() != null) { 108 if (source instanceof StartEvent && source.getSubProcess() != null) {
72 - userTaskList = getPreUserTaskList(source.getSubProcess(), hasSequenceFlow, userTaskList); 109 + userTaskList = getPreviousUserTaskList(source.getSubProcess(), hasSequenceFlow, userTaskList);
73 } 110 }
74 111
75 // 根据类型,获取入口连线 112 // 根据类型,获取入口连线
76 List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source); 113 List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
77 -  
78 - if (sequenceFlows != null) {  
79 - // 循环找到目标元素  
80 - for (SequenceFlow sequenceFlow : sequenceFlows) {  
81 - // 如果发现连线重复,说明循环了,跳过这个循环  
82 - if (hasSequenceFlow.contains(sequenceFlow.getId())) {  
83 - continue;  
84 - }  
85 - // 添加已经走过的连线  
86 - hasSequenceFlow.add(sequenceFlow.getId());  
87 - // 类型为用户节点,则新增父级节点  
88 - if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {  
89 - userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement());  
90 - }  
91 - // 类型为子流程,则添加子流程开始节点出口处相连的节点  
92 - if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {  
93 - // 获取子流程用户任务节点  
94 - List<UserTask> childUserTaskList = findChildProcessUserTasks((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null);  
95 - // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续  
96 - if (childUserTaskList != null && childUserTaskList.size() > 0) {  
97 - userTaskList.addAll(childUserTaskList);  
98 - } 114 + if (sequenceFlows == null) {
  115 + return userTaskList;
  116 + }
  117 + // 循环找到目标元素
  118 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  119 + // 如果发现连线重复,说明循环了,跳过这个循环
  120 + if (hasSequenceFlow.contains(sequenceFlow.getId())) {
  121 + continue;
  122 + }
  123 + // 添加已经走过的连线
  124 + hasSequenceFlow.add(sequenceFlow.getId());
  125 + // 类型为用户节点,则新增父级节点
  126 + if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
  127 + userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement());
  128 + }
  129 + // 类型为子流程,则添加子流程开始节点出口处相连的节点
  130 + if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
  131 + // 获取子流程用户任务节点
  132 + List<UserTask> childUserTaskList = findChildProcessUserTaskList((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null);
  133 + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
  134 + if (CollUtil.isNotEmpty(childUserTaskList)) {
  135 + userTaskList.addAll(childUserTaskList);
99 } 136 }
100 - // 继续迭代  
101 - userTaskList = getPreUserTaskList(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList);  
102 } 137 }
  138 + // 继续迭代
  139 + userTaskList = getPreviousUserTaskList(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList);
103 } 140 }
104 return userTaskList; 141 return userTaskList;
105 } 142 }
@@ -110,41 +147,41 @@ public class ModelUtils { @@ -110,41 +147,41 @@ public class ModelUtils {
110 * @param source 起始节点 147 * @param source 起始节点
111 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 148 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
112 * @param userTaskList 需要撤回的用户任务列表 149 * @param userTaskList 需要撤回的用户任务列表
113 - * @return 150 + * @return 用户任务节点
114 */ 151 */
115 - public static List<UserTask> findChildProcessUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) { 152 + public static List<UserTask> findChildProcessUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
116 hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; 153 hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
117 userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; 154 userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
118 155
119 // 根据类型,获取出口连线 156 // 根据类型,获取出口连线
120 List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source); 157 List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
121 -  
122 - if (sequenceFlows != null) {  
123 - // 循环找到目标元素  
124 - for (SequenceFlow sequenceFlow : sequenceFlows) {  
125 - // 如果发现连线重复,说明循环了,跳过这个循环  
126 - if (hasSequenceFlow.contains(sequenceFlow.getId())) {  
127 - continue;  
128 - }  
129 - // 添加已经走过的连线  
130 - hasSequenceFlow.add(sequenceFlow.getId());  
131 - // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加  
132 - if (sequenceFlow.getTargetFlowElement() instanceof UserTask) {  
133 - userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); 158 + if (sequenceFlows == null) {
  159 + return userTaskList;
  160 + }
  161 + // 循环找到目标元素
  162 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  163 + // 如果发现连线重复,说明循环了,跳过这个循环
  164 + if (hasSequenceFlow.contains(sequenceFlow.getId())) {
  165 + continue;
  166 + }
  167 + // 添加已经走过的连线
  168 + hasSequenceFlow.add(sequenceFlow.getId());
  169 + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
  170 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask) {
  171 + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
  172 + continue;
  173 + }
  174 + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
  175 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
  176 + List<UserTask> childUserTaskList = findChildProcessUserTaskList((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null);
  177 + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
  178 + if (CollUtil.isNotEmpty(childUserTaskList)) {
  179 + userTaskList.addAll(childUserTaskList);
134 continue; 180 continue;
135 } 181 }
136 - // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取  
137 - if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {  
138 - List<UserTask> childUserTaskList = findChildProcessUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null);  
139 - // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续  
140 - if (childUserTaskList != null && childUserTaskList.size() > 0) {  
141 - userTaskList.addAll(childUserTaskList);  
142 - continue;  
143 - }  
144 - }  
145 - // 继续迭代  
146 - userTaskList = findChildProcessUserTasks(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList);  
147 } 182 }
  183 + // 继续迭代
  184 + userTaskList = findChildProcessUserTaskList(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList);
148 } 185 }
149 return userTaskList; 186 return userTaskList;
150 } 187 }
@@ -161,36 +198,36 @@ public class ModelUtils { @@ -161,36 +198,36 @@ public class ModelUtils {
161 */ 198 */
162 public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) { 199 public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) {
163 visitedElements = visitedElements == null ? new HashSet<>() : visitedElements; 200 visitedElements = visitedElements == null ? new HashSet<>() : visitedElements;
164 - //不能是开始事件和子流程 201 + // 不能是开始事件和子流程
165 if (source instanceof StartEvent && isInEventSubprocess(source)) { 202 if (source instanceof StartEvent && isInEventSubprocess(source)) {
166 return false; 203 return false;
167 } 204 }
168 205
169 // 根据类型,获取入口连线 206 // 根据类型,获取入口连线
170 List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source); 207 List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
171 - if (sequenceFlows != null && sequenceFlows.size() > 0) {  
172 - // 循环找到目标元素  
173 - for (SequenceFlow sequenceFlow : sequenceFlows) {  
174 - // 如果发现连线重复,说明循环了,跳过这个循环  
175 - if (visitedElements.contains(sequenceFlow.getId())) {  
176 - continue;  
177 - }  
178 - // 添加已经走过的连线  
179 - visitedElements.add(sequenceFlow.getId());  
180 - FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();  
181 - // 这条线路存在目标节点,这条线路完成,进入下个线路  
182 - if (target.getId().equals(sourceFlowElement.getId())) {  
183 - continue;  
184 - }  
185 - // 如果目标节点为并行网关,则不继续  
186 - if (sourceFlowElement instanceof ParallelGateway) {  
187 - return false;  
188 - }  
189 - // 否则就继续迭代  
190 - boolean isSequential = isSequentialReachable(sourceFlowElement, target, visitedElements);  
191 - if (!isSequential) {  
192 - return false;  
193 - } 208 + if (CollUtil.isEmpty(sequenceFlows)) {
  209 + return true;
  210 + }
  211 + // 循环找到目标元素
  212 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  213 + // 如果发现连线重复,说明循环了,跳过这个循环
  214 + if (visitedElements.contains(sequenceFlow.getId())) {
  215 + continue;
  216 + }
  217 + // 添加已经走过的连线
  218 + visitedElements.add(sequenceFlow.getId());
  219 + // 这条线路存在目标节点,这条线路完成,进入下个线路
  220 + FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
  221 + if (target.getId().equals(sourceFlowElement.getId())) {
  222 + continue;
  223 + }
  224 + // 如果目标节点为并行网关,则不继续
  225 + if (sourceFlowElement instanceof ParallelGateway) {
  226 + return false;
  227 + }
  228 + // 否则就继续迭代
  229 + if (!isSequentialReachable(sourceFlowElement, target, visitedElements)) {
  230 + return false;
194 } 231 }
195 } 232 }
196 return true; 233 return true;
@@ -200,9 +237,9 @@ public class ModelUtils { @@ -200,9 +237,9 @@ public class ModelUtils {
200 * 判断当前节点是否属于不同的子流程 237 * 判断当前节点是否属于不同的子流程
201 * 238 *
202 * @param flowElement 被判断的节点 239 * @param flowElement 被判断的节点
203 - * @return true表示属于子流程 240 + * @return true 表示属于子流程
204 */ 241 */
205 - protected static boolean isInEventSubprocess(FlowElement flowElement) { 242 + private static boolean isInEventSubprocess(FlowElement flowElement) {
206 FlowElementsContainer flowElementsContainer = flowElement.getParentContainer(); 243 FlowElementsContainer flowElementsContainer = flowElement.getParentContainer();
207 while (flowElementsContainer != null) { 244 while (flowElementsContainer != null) {
208 if (flowElementsContainer instanceof EventSubProcess) { 245 if (flowElementsContainer instanceof EventSubProcess) {
@@ -218,7 +255,6 @@ public class ModelUtils { @@ -218,7 +255,6 @@ public class ModelUtils {
218 return false; 255 return false;
219 } 256 }
220 257
221 -  
222 /** 258 /**
223 * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 259 * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找
224 * 260 *
@@ -226,12 +262,12 @@ public class ModelUtils { @@ -226,12 +262,12 @@ public class ModelUtils {
226 * @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点 262 * @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点
227 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 263 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
228 * @param userTaskList 需要撤回的用户任务列表 264 * @param userTaskList 需要撤回的用户任务列表
229 - * @return 265 + * @return 子级任务节点列表
230 */ 266 */
231 - public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList, Set<String> hasSequenceFlow, List<UserTask> userTaskList) { 267 + public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList,
  268 + Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
232 hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; 269 hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
233 userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; 270 userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
234 -  
235 // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 271 // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
236 if (source instanceof StartEvent && source.getSubProcess() != null) { 272 if (source instanceof StartEvent && source.getSubProcess() != null) {
237 userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList); 273 userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList);
@@ -239,34 +275,35 @@ public class ModelUtils { @@ -239,34 +275,35 @@ public class ModelUtils {
239 275
240 // 根据类型,获取出口连线 276 // 根据类型,获取出口连线
241 List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source); 277 List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
242 -  
243 - if (sequenceFlows != null) {  
244 - // 循环找到目标元素  
245 - for (SequenceFlow sequenceFlow : sequenceFlows) {  
246 - // 如果发现连线重复,说明循环了,跳过这个循环  
247 - if (hasSequenceFlow.contains(sequenceFlow.getId())) {  
248 - continue;  
249 - }  
250 - // 添加已经走过的连线  
251 - hasSequenceFlow.add(sequenceFlow.getId());  
252 - // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加  
253 - if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) {  
254 - userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); 278 + if (sequenceFlows == null) {
  279 + return userTaskList;
  280 + }
  281 + // 循环找到目标元素
  282 + for (SequenceFlow sequenceFlow : sequenceFlows) {
  283 + // 如果发现连线重复,说明循环了,跳过这个循环
  284 + if (hasSequenceFlow.contains(sequenceFlow.getId())) {
  285 + continue;
  286 + }
  287 + // 添加已经走过的连线
  288 + hasSequenceFlow.add(sequenceFlow.getId());
  289 + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
  290 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) {
  291 + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
  292 + continue;
  293 + }
  294 + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
  295 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
  296 + List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null);
  297 + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
  298 + if (CollUtil.isNotEmpty(childUserTaskList)) {
  299 + userTaskList.addAll(childUserTaskList);
255 continue; 300 continue;
256 } 301 }
257 - // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取  
258 - if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {  
259 - List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null);  
260 - // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续  
261 - if (childUserTaskList != null && childUserTaskList.size() > 0) {  
262 - userTaskList.addAll(childUserTaskList);  
263 - continue;  
264 - }  
265 - }  
266 - // 继续迭代  
267 - userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList);  
268 } 302 }
  303 + // 继续迭代
  304 + userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList);
269 } 305 }
270 return userTaskList; 306 return userTaskList;
271 } 307 }
  308 +
272 } 309 }
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java
1 package cn.iocoder.yudao.framework.flowable.core.util; 1 package cn.iocoder.yudao.framework.flowable.core.util;
2 2
3 -import org.flowable.bpmn.converter.BpmnXMLConverter;  
4 -import org.flowable.bpmn.model.BpmnModel;  
5 -import org.flowable.bpmn.model.FlowElement;  
6 import org.flowable.common.engine.impl.identity.Authentication; 3 import org.flowable.common.engine.impl.identity.Authentication;
7 4
8 -import java.util.ArrayList;  
9 -import java.util.Arrays;  
10 -import java.util.List;  
11 -  
12 /** 5 /**
13 * Flowable 相关的工具方法 6 * Flowable 相关的工具方法
14 * 7 *
@@ -26,49 +19,6 @@ public class FlowableUtils { @@ -26,49 +19,6 @@ public class FlowableUtils {
26 Authentication.setAuthenticatedUserId(null); 19 Authentication.setAuthenticatedUserId(null);
27 } 20 }
28 21
29 - // ========== BPMN 相关的工具方法 ==========  
30 -  
31 - /**  
32 - * 获得 BPMN 流程中,指定的元素们  
33 - *  
34 - * @param model  
35 - * @param clazz 指定元素。例如说,{@link org.flowable.bpmn.model.UserTask}、{@link org.flowable.bpmn.model.Gateway} 等等  
36 - * @return 元素们  
37 - */  
38 - public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {  
39 - List<T> result = new ArrayList<>();  
40 - model.getProcesses().forEach(process -> {  
41 - process.getFlowElements().forEach(flowElement -> {  
42 - if (flowElement.getClass().isAssignableFrom(clazz)) {  
43 - result.add((T) flowElement);  
44 - }  
45 - });  
46 - });  
47 - return result;  
48 - }  
49 -  
50 - /**  
51 - * 比较 两个bpmnModel 是否相同  
52 - * @param oldModel 老的bpmn model  
53 - * @param newModel 新的bpmn model  
54 - */  
55 - public static boolean equals(BpmnModel oldModel, BpmnModel newModel) {  
56 - // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较  
57 - return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));  
58 - }  
59 -  
60 - /**  
61 - * 把 bpmnModel 转换成 byte[]  
62 - * @param model bpmnModel  
63 - */  
64 - public static byte[] getBpmnBytes(BpmnModel model) {  
65 - if (model == null) {  
66 - return new byte[0];  
67 - }  
68 - BpmnXMLConverter converter = new BpmnXMLConverter();  
69 - return converter.convertToXML(model);  
70 - }  
71 -  
72 // ========== Execution 相关的工具方法 ========== 22 // ========== Execution 相关的工具方法 ==========
73 23
74 public static String formatCollectionVariable(String activityId) { 24 public static String formatCollectionVariable(String activityId) {
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
@@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil; @@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.common.util.object.PageUtils; 7 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
8 -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; 8 +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO;
10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; 10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; 11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
@@ -200,7 +200,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ @@ -200,7 +200,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
200 BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes()); 200 BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes());
201 BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); 201 BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId());
202 // 对比字节变化 202 // 对比字节变化
203 - if (!FlowableUtils.equals(oldModel, newModel)) { 203 + if (!BpmnModelUtils.equals(oldModel, newModel)) {
204 return false; 204 return false;
205 } 205 }
206 // 最终发现都一致,则返回 true 206 // 最终发现都一致,则返回 true
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
@@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 8 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
9 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; 9 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
10 -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; 10 +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; 11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; 12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
13 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; 13 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
@@ -114,7 +114,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -114,7 +114,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
114 return Collections.emptyList(); 114 return Collections.emptyList();
115 } 115 }
116 // 获得用户任务,只有用户任务才可以设置分配规则 116 // 获得用户任务,只有用户任务才可以设置分配规则
117 - List<UserTask> userTasks = FlowableUtils.getBpmnModelElements(model, UserTask.class); 117 + List<UserTask> userTasks = BpmnModelUtils.getBpmnModelElements(model, UserTask.class);
118 if (CollUtil.isEmpty(userTasks)) { 118 if (CollUtil.isEmpty(userTasks)) {
119 return Collections.emptyList(); 119 return Collections.emptyList();
120 } 120 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 7 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
9 import cn.iocoder.yudao.framework.common.util.object.PageUtils; 9 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
10 -import cn.iocoder.yudao.framework.flowable.core.util.ModelUtils; 10 +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
12 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; 12 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
13 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; 13 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
@@ -61,22 +61,23 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -61,22 +61,23 @@ public class BpmTaskServiceImpl implements BpmTaskService {
61 private TaskService taskService; 61 private TaskService taskService;
62 @Resource 62 @Resource
63 private HistoryService historyService; 63 private HistoryService historyService;
  64 + @Resource
  65 + private RuntimeService runtimeService;
64 66
65 @Resource 67 @Resource
66 private BpmProcessInstanceService processInstanceService; 68 private BpmProcessInstanceService processInstanceService;
67 @Resource 69 @Resource
68 - private AdminUserApi adminUserApi;  
69 - @Resource  
70 - private DeptApi deptApi;  
71 - @Resource  
72 - private BpmTaskExtMapper taskExtMapper; 70 + private BpmModelService bpmModelService;
73 @Resource 71 @Resource
74 private BpmMessageService messageService; 72 private BpmMessageService messageService;
  73 +
75 @Resource 74 @Resource
76 - private BpmModelService bpmModelService; 75 + private AdminUserApi adminUserApi;
77 @Resource 76 @Resource
78 - private RuntimeService runtimeService; 77 + private DeptApi deptApi;
79 78
  79 + @Resource
  80 + private BpmTaskExtMapper taskExtMapper;
80 81
81 @Override 82 @Override
82 public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { 83 public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
@@ -351,18 +352,18 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -351,18 +352,18 @@ public class BpmTaskServiceImpl implements BpmTaskService {
351 throw exception(TASK_NOT_EXISTS); 352 throw exception(TASK_NOT_EXISTS);
352 } 353 }
353 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); 354 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
354 - FlowElement source = ModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); 355 + FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
355 if (source == null) { 356 if (source == null) {
356 throw exception(TASK_NOT_EXISTS); 357 throw exception(TASK_NOT_EXISTS);
357 } 358 }
358 359
359 // 2.1 查询该任务的前置任务节点的 key 集合 360 // 2.1 查询该任务的前置任务节点的 key 集合
360 - List<UserTask> previousUserList = ModelUtils.getPreUserTaskList(source, null, null); 361 + List<UserTask> previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null);
361 if (CollUtil.isEmpty(previousUserList)) { 362 if (CollUtil.isEmpty(previousUserList)) {
362 return Collections.emptyList(); 363 return Collections.emptyList();
363 } 364 }
364 // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回 365 // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
365 - previousUserList.removeIf(userTask -> !ModelUtils.isSequentialReachable(source, userTask, null)); 366 + previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
366 return BpmTaskConvert.INSTANCE.convertList(previousUserList); 367 return BpmTaskConvert.INSTANCE.convertList(previousUserList);
367 } 368 }
368 369
@@ -395,15 +396,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -395,15 +396,15 @@ public class BpmTaskServiceImpl implements BpmTaskService {
395 // 1.1 获取流程模型信息 396 // 1.1 获取流程模型信息
396 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(processDefinitionId); 397 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(processDefinitionId);
397 // 1.3 获取当前任务节点元素 398 // 1.3 获取当前任务节点元素
398 - FlowElement source = ModelUtils.getFlowElementById(bpmnModel, sourceKey); 399 + FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, sourceKey);
399 // 1.3 获取跳转的节点元素 400 // 1.3 获取跳转的节点元素
400 - FlowElement target = ModelUtils.getFlowElementById(bpmnModel, targetKey); 401 + FlowElement target = BpmnModelUtils.getFlowElementById(bpmnModel, targetKey);
401 if (target == null) { 402 if (target == null) {
402 throw exception(TASK_TARGET_NODE_NOT_EXISTS); 403 throw exception(TASK_TARGET_NODE_NOT_EXISTS);
403 } 404 }
404 405
405 // 2.2 只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回 406 // 2.2 只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
406 - if (!ModelUtils.isSequentialReachable(source, target, null)) { 407 + if (!BpmnModelUtils.isSequentialReachable(source, target, null)) {
407 throw exception(TASK_RETURN_FAIL_SOURCE_TARGET_ERROR); 408 throw exception(TASK_RETURN_FAIL_SOURCE_TARGET_ERROR);
408 } 409 }
409 return target; 410 return target;
@@ -423,7 +424,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -423,7 +424,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
423 List<String> runTaskKeyList = convertList(taskList, Task::getTaskDefinitionKey); 424 List<String> runTaskKeyList = convertList(taskList, Task::getTaskDefinitionKey);
424 // 1.2 通过 targetElement 的出口连线,计算在 runTaskKeyList 有哪些 key 需要被撤回 425 // 1.2 通过 targetElement 的出口连线,计算在 runTaskKeyList 有哪些 key 需要被撤回
425 // 为什么不直接使用 runTaskKeyList 呢?因为可能存在多个审批分支,例如说:A -> B -> C 和 D -> F,而只要 C 撤回到 A,需要排除掉 F 426 // 为什么不直接使用 runTaskKeyList 呢?因为可能存在多个审批分支,例如说:A -> B -> C 和 D -> F,而只要 C 撤回到 A,需要排除掉 F
426 - List<UserTask> returnUserTaskList = ModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null); 427 + List<UserTask> returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null);
427 List<String> returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId); 428 List<String> returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId);
428 429
429 // 2. 给当前要被回退的 task 数组,设置回退意见 430 // 2. 给当前要被回退的 task 数组,设置回退意见