fix -- 采用DFS深搜获取流程未通过的节点(修复流程跟踪查询死循环问题)

This commit is contained in:
konbai
2022-04-14 00:39:23 +08:00
parent 1b8a2ebe51
commit cf30d29f9b
2 changed files with 118 additions and 45 deletions

View File

@@ -1,5 +1,7 @@
package com.ruoyi.flowable.flow;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.*;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
@@ -586,4 +588,117 @@ public class FlowableUtils {
log.info("清洗后的历史节点数据:" + lastHistoricTaskInstanceList);
return lastHistoricTaskInstanceList;
}
/**
* 深搜递归获取流程未通过的节点
* @param bpmnModel 流程模型
* @param unfinishedTaskSet 未结束的任务节点
* @param finishedSequenceFlowSet 已经完成的连线
* @param finishedTaskSet 已完成的任务节点
* @return
*/
public static Set<String> dfsFindRejects(BpmnModel bpmnModel, Set<String> unfinishedTaskSet, Set<String> finishedSequenceFlowSet, Set<String> finishedTaskSet) {
if (ObjectUtil.isNull(bpmnModel)) {
throw new ServiceException("流程模型不存在");
}
Collection<FlowElement> allElements = getAllElements(bpmnModel.getMainProcess().getFlowElements(), null);
Set<String> rejectedSet = new HashSet<>();
for (FlowElement flowElement : allElements) {
// 用户节点且未结束元素
if (flowElement instanceof UserTask && unfinishedTaskSet.contains(flowElement.getId())) {
List<String> hasSequenceFlow = iteratorFindFinishes(flowElement, null);
List<String> rejects = iteratorFindRejects(flowElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, null);
rejectedSet.addAll(rejects);
}
}
return rejectedSet;
}
/**
* 迭代获取父级节点列表,向前找
* @param source 起始节点
* @param hasSequenceFlow 已经经过的连线的ID用于判断线路是否重复
* @return
*/
public static List<String> iteratorFindFinishes(FlowElement source, List<String> hasSequenceFlow) {
hasSequenceFlow = hasSequenceFlow == null ? new ArrayList<>() : hasSequenceFlow;
// 根据类型,获取入口连线
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
if (sequenceFlows != null) {
// 循环找到目标元素
for (SequenceFlow sequenceFlow: sequenceFlows) {
// 如果发现连线重复,说明循环了,跳过这个循环
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
continue;
}
// 添加已经走过的连线
hasSequenceFlow.add(sequenceFlow.getId());
FlowElement finishedElement = sequenceFlow.getSourceFlowElement();
// 类型为子流程,则添加子流程开始节点出口处相连的节点
if (finishedElement instanceof SubProcess) {
FlowElement firstElement = (StartEvent) ((SubProcess) finishedElement).getFlowElements().toArray()[0];
// 获取子流程的连线
hasSequenceFlow.addAll(iteratorFindFinishes(firstElement, null));
}
// 继续迭代
hasSequenceFlow = iteratorFindFinishes(finishedElement, hasSequenceFlow);
}
}
return hasSequenceFlow;
}
/**
* 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找
* @param source 起始节点
* @param finishedSequenceFlowSet 已经完成的连线
* @param finishedTaskSet 已经完成的任务节点
* @param hasSequenceFlow 已经经过的连线的 ID用于判断线路是否重复
* @param rejectedList 未通过的元素
* @return
*/
public static List<String> iteratorFindRejects(FlowElement source, Set<String> finishedSequenceFlowSet, Set<String> finishedTaskSet
, List<String> hasSequenceFlow, List<String> rejectedList) {
hasSequenceFlow = hasSequenceFlow == null ? new ArrayList<>() : hasSequenceFlow;
rejectedList = rejectedList == null ? new ArrayList<>() : rejectedList;
// 根据类型,获取出口连线
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
if (sequenceFlows != null) {
// 循环找到目标元素
for (SequenceFlow sequenceFlow: sequenceFlows) {
// 如果发现连线重复,说明循环了,跳过这个循环
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
continue;
}
// 添加已经走过的连线
hasSequenceFlow.add(sequenceFlow.getId());
FlowElement targetElement = sequenceFlow.getTargetFlowElement();
// 添加未完成的节点
if (finishedTaskSet.contains(targetElement.getId())) {
rejectedList.add(targetElement.getId());
}
// 添加未完成的连线
if (finishedSequenceFlowSet.contains(sequenceFlow.getId())) {
rejectedList.add(sequenceFlow.getId());
}
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
if (targetElement instanceof SubProcess) {
FlowElement firstElement = (FlowElement) (((SubProcess) targetElement).getFlowElements().toArray()[0]);
List<String> childList = iteratorFindRejects(firstElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, null);
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
if (childList != null && childList.size() > 0) {
rejectedList.addAll(childList);
continue;
}
}
// 继续迭代
rejectedList = iteratorFindRejects(targetElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, rejectedList);
}
}
return rejectedList;
}
}