fix -- 采用DFS深搜获取流程未通过的节点(修复流程跟踪查询死循环问题)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.ruoyi.workflow.service.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -726,26 +725,6 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
// 获取流程发布Id信息
|
||||
String processDefinitionId = allActivityInstanceList.get(0).getProcessDefinitionId();
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
||||
if (ObjectUtil.isNull(bpmnModel)) {
|
||||
throw new ServiceException("流程模型不存在");
|
||||
}
|
||||
Map<String, List<String>> sequenceElementMap = new HashMap<>();
|
||||
Map<String, String> sequenceFlowMap = new HashMap<>();
|
||||
Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
|
||||
for (FlowElement flowElement : flowElements) {
|
||||
if (flowElement instanceof SequenceFlow) {
|
||||
SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
|
||||
String sourceRef = sequenceFlow.getSourceRef();
|
||||
String targetRef = sequenceFlow.getTargetRef();
|
||||
List<String> targetRefList = sequenceElementMap.get(sourceRef);
|
||||
if (CollUtil.isEmpty(targetRefList)) {
|
||||
sequenceElementMap.put(sourceRef, ListUtil.toList(targetRef));
|
||||
} else {
|
||||
targetRefList.add(targetRef);
|
||||
}
|
||||
sequenceFlowMap.put(sourceRef + targetRef, sequenceFlow.getId());
|
||||
}
|
||||
}
|
||||
// 查询所有已完成的元素
|
||||
List<HistoricActivityInstance> finishedElementList = allActivityInstanceList.stream()
|
||||
.filter(item -> ObjectUtil.isNotNull(item.getEndTime())).collect(Collectors.toList());
|
||||
@@ -765,30 +744,9 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
.filter(item -> ObjectUtil.isNull(item.getEndTime()))
|
||||
.map(HistoricActivityInstance::getActivityId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> rejectedTaskSet = new LinkedHashSet<>();
|
||||
Set<String> sourceTaskSet = unfinishedTaskSet;
|
||||
while (CollUtil.isNotEmpty(sourceTaskSet)) {
|
||||
Set<String> nextIdSet = new HashSet<>();
|
||||
for (String previousId : sourceTaskSet) {
|
||||
List<String> nextIdList = sequenceElementMap.get(previousId);
|
||||
if (CollUtil.isEmpty(nextIdList)) {
|
||||
continue;
|
||||
}
|
||||
nextIdList.forEach(nextId -> {
|
||||
if (finishedTaskSet.contains(nextId)) {
|
||||
nextIdSet.add(nextId);
|
||||
String rejectedSequenceFlow = sequenceFlowMap.get(previousId + nextId);
|
||||
if (finishedSequenceFlowSet.contains(rejectedSequenceFlow)) {
|
||||
nextIdSet.add(rejectedSequenceFlow);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
rejectedTaskSet.addAll(nextIdSet);
|
||||
sourceTaskSet = nextIdSet;
|
||||
}
|
||||
return new WfViewerVo(finishedTaskSet, finishedSequenceFlowSet, unfinishedTaskSet, rejectedTaskSet);
|
||||
// DFS 查询未通过的元素集合
|
||||
Set<String> rejectedSet = FlowableUtils.dfsFindRejects(bpmnModel, unfinishedTaskSet, finishedSequenceFlowSet, finishedTaskSet);
|
||||
return new WfViewerVo(finishedTaskSet, finishedSequenceFlowSet, unfinishedTaskSet, rejectedSet);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user