应用Flowable,退回到历史某一个节点,退回场景有:
1.指标节点和以后节点都不在并行网关上,或者指标节点和以后节点在同一个并行网关的同一个分支
2.退回到并行网关分支中的某一个节点上
3.并行网关中的某一个分支节点上发动退回,退回到并行网关后面的某一个节点上
4.流程外部子流程(SubProcess),子流程中退回到骨干流程中某一个节点
5.流程外部子流程(SubProcess),骨干流程退回到子流程中某一个节点
6.流程内部子流程(CallActivity),子流程中退回到骨干流程中某一个节点、骨干流程退回到子流程中某一个节点
我的思路,目前已实现 1~4 ,其中 5 能够退回到让子流程从新开始,但不是子流程中的某一个节点,残缺源码详见:
springboot:https://gitee.com/zjm16/zjmzx...
springcloud:https://gitee.com/zjm16/zjmzx...
具体流程图可参见残缺源码门路 zjmzxfzhl/src/main/resources/processes_test
下的流程文件
具体实现的java文件BackUserTaskCmd.java
package com.zjmzxfzhl.modules.flowable.common.cmd;import java.io.Serializable;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.stream.Collectors;import org.flowable.bpmn.model.FlowNode;import org.flowable.bpmn.model.Process;import org.flowable.bpmn.model.UserTask;import org.flowable.common.engine.api.FlowableException;import org.flowable.common.engine.api.FlowableObjectNotFoundException;import org.flowable.common.engine.impl.interceptor.Command;import org.flowable.common.engine.impl.interceptor.CommandContext;import org.flowable.engine.RuntimeService;import org.flowable.engine.impl.delegate.ActivityBehavior;import org.flowable.engine.impl.persistence.entity.ExecutionEntity;import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;import org.flowable.engine.impl.util.CommandContextUtil;import org.flowable.engine.impl.util.ProcessDefinitionUtil;import org.flowable.task.api.Task;import org.flowable.task.service.impl.persistence.entity.TaskEntity;import com.google.common.collect.Sets;import com.zjmzxfzhl.modules.flowable.constant.FlowableConstant;import com.zjmzxfzhl.modules.flowable.util.FlowableUtils;/** * @author 庄金明 * @date 2020年3月23日 */public class BackUserTaskCmd implements Command<String>, Serializable { public static final long serialVersionUID = 1L; protected RuntimeService runtimeService; protected String taskId; protected String targetActivityId; public BackUserTaskCmd(RuntimeService runtimeService, String taskId, String targetActivityId) { this.runtimeService = runtimeService; this.taskId = taskId; this.targetActivityId = targetActivityId; } @Override public String execute(CommandContext commandContext) { if (targetActivityId == null || targetActivityId.length() == 0) { throw new FlowableException("TargetActivityId cannot be empty"); } TaskEntity task = CommandContextUtil.getTaskService().getTask(taskId); if (task == null) { throw new FlowableObjectNotFoundException("task " + taskId + " doesn't exist", Task.class); } String sourceActivityId = task.getTaskDefinitionKey(); String processInstanceId = task.getProcessInstanceId(); String processDefinitionId = task.getProcessDefinitionId(); Process process = ProcessDefinitionUtil.getProcess(processDefinitionId); FlowNode sourceFlowElement = (FlowNode) process.getFlowElement(sourceActivityId, true); // 只反对从用户工作退回 if (!(sourceFlowElement instanceof UserTask)) { throw new FlowableException("Task with id:" + taskId + " is not a UserTask"); } FlowNode targetFlowElement = (FlowNode) process.getFlowElement(targetActivityId, true); // 退回节点到以后节点不可达到,不容许退回 if (!FlowableUtils.isReachable(process, targetFlowElement, sourceFlowElement)) { throw new FlowableException("Cannot back to [" + targetActivityId + "]"); } // ps:指标节点如果绝对以后节点是在子流程外部,则无奈间接退回,目前解决是只能退回到子流程开始节点 String[] sourceAndTargetRealActivityId = FlowableUtils.getSourceAndTargetRealActivityId(sourceFlowElement, targetFlowElement); // 理论应操作的以后节点ID String sourceRealActivityId = sourceAndTargetRealActivityId[0]; // 理论应操作的指标节点ID String targetRealActivityId = sourceAndTargetRealActivityId[1]; Map<String, Set<String>> specialGatewayNodes = FlowableUtils.getSpecialGatewayElements(process); // 以后节点处在的并行网关list List<String> sourceInSpecialGatewayList = new ArrayList<>(); // 指标节点处在的并行网关list List<String> targetInSpecialGatewayList = new ArrayList<>(); setSpecialGatewayList(sourceRealActivityId, targetRealActivityId, specialGatewayNodes, sourceInSpecialGatewayList, targetInSpecialGatewayList); // 理论应筛选的节点ID Set<String> sourceRealAcitivtyIds = null; // 若退回指标节点绝对以后节点在并行网关中,则要找到绝对以后节点最近的这个并行网关,后续做非凡解决 String targetRealSpecialGateway = null; // 1.指标节点和以后节点都不在并行网关中 if (targetInSpecialGatewayList.isEmpty() && sourceInSpecialGatewayList.isEmpty()) { sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId); } // 2.指标节点不在并行网关中、以后节点在并行网关中 else if (targetInSpecialGatewayList.isEmpty() && !sourceInSpecialGatewayList.isEmpty()) { sourceRealAcitivtyIds = specialGatewayNodes.get(sourceInSpecialGatewayList.get(0)); } // 3.指标节点在并行网关中、以后节点不在并行网关中 else if (!targetInSpecialGatewayList.isEmpty() && sourceInSpecialGatewayList.isEmpty()) { sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId); targetRealSpecialGateway = targetInSpecialGatewayList.get(0); } // 4.指标节点和以后节点都在并行网关中 else { int diffSpecialGatewayLevel = FlowableUtils.getDiffLevel(sourceInSpecialGatewayList, targetInSpecialGatewayList); // 在并行网关同一层且在同一分支 if (diffSpecialGatewayLevel == -1) { sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId); } else { // 以后节点最内层并行网关不被指标节点最内层并行网关蕴含 // 或了解为以后节点绝对指标节点在并行网关外 // 只筛选以后节点的execution if (sourceInSpecialGatewayList.size() == diffSpecialGatewayLevel) { sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId); } // 以后节点绝对指标节点在并行网关内,应筛选绝对指标节点最近的并行网关的所有节点的execution else { sourceRealAcitivtyIds = specialGatewayNodes.get(sourceInSpecialGatewayList.get(diffSpecialGatewayLevel)); } // 指标节点最内层并行网关蕴含以后节点最内层并行网关 // 或了解为指标节点绝对以后节点在并行网关外 // 不做解决 if (targetInSpecialGatewayList.size() == diffSpecialGatewayLevel) { } // 指标节点绝对以后节点在并行网关内 else { targetRealSpecialGateway = targetInSpecialGatewayList.get(diffSpecialGatewayLevel); } } } // 筛选须要解决的execution List<ExecutionEntity> realExecutions = this.getRealExecutions(commandContext, processInstanceId, task.getExecutionId(), sourceRealActivityId, sourceRealAcitivtyIds); // 执行退回,间接跳转到理论的 targetRealActivityId List<String> realExecutionIds = realExecutions.stream().map(ExecutionEntity::getId).collect(Collectors.toList()); runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId) .moveExecutionsToSingleActivityId(realExecutionIds, targetRealActivityId).changeState(); // 指标节点绝对以后节点处于并行网关内,须要非凡解决,须要手动生成并行网关汇聚节点(_end)的execution数据 if (targetRealSpecialGateway != null) { createTargetInSpecialGatewayEndExecutions(commandContext, realExecutions, process, targetInSpecialGatewayList, targetRealSpecialGateway); } return targetRealActivityId; } private void setSpecialGatewayList(String sourceActivityId, String targetActivityId, Map<String, Set<String>> specialGatewayNodes, List<String> sourceInSpecialGatewayList, List<String> targetInSpecialGatewayList) { for (Map.Entry<String, Set<String>> entry : specialGatewayNodes.entrySet()) { if (entry.getValue().contains(sourceActivityId)) { sourceInSpecialGatewayList.add(entry.getKey()); } if (entry.getValue().contains(targetActivityId)) { targetInSpecialGatewayList.add(entry.getKey()); } } } private void createTargetInSpecialGatewayEndExecutions(CommandContext commandContext, List<ExecutionEntity> excutionEntitys, Process process, List<String> targetInSpecialGatewayList, String targetRealSpecialGateway) { // 指标节点绝对以后节点处于并行网关,须要手动生成并行网关汇聚节点(_end)的execution数据 String parentExecutionId = excutionEntitys.iterator().next().getParentId(); ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext); ExecutionEntity parentExecutionEntity = executionEntityManager.findById(parentExecutionId); int index = targetInSpecialGatewayList.indexOf(targetRealSpecialGateway); for (; index < targetInSpecialGatewayList.size(); index++) { String targetInSpecialGateway = targetInSpecialGatewayList.get(index); String targetInSpecialGatewayEndId = targetInSpecialGateway + FlowableConstant.SPECIAL_GATEWAY_END_SUFFIX; FlowNode targetInSpecialGatewayEnd = (FlowNode) process.getFlowElement(targetInSpecialGatewayEndId, true); int nbrOfExecutionsToJoin = targetInSpecialGatewayEnd.getIncomingFlows().size(); // 解决指标节点所处的分支以外的分支,即 总分枝数-1 = nbrOfExecutionsToJoin - 1 for (int i = 0; i < nbrOfExecutionsToJoin - 1; i++) { ExecutionEntity childExecution = executionEntityManager.createChildExecution(parentExecutionEntity); childExecution.setCurrentFlowElement(targetInSpecialGatewayEnd); ActivityBehavior activityBehavior = (ActivityBehavior) targetInSpecialGatewayEnd.getBehavior(); activityBehavior.execute(childExecution); } } } private List<ExecutionEntity> getRealExecutions(CommandContext commandContext, String processInstanceId, String taskExecutionId, String sourceRealActivityId, Set<String> activityIds) { ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext); ExecutionEntity taskExecution = executionEntityManager.findById(taskExecutionId); List<ExecutionEntity> executions = executionEntityManager.findChildExecutionsByProcessInstanceId(processInstanceId); Set<String> parentExecutionIds = FlowableUtils.getParentExecutionIdsByActivityId(executions, sourceRealActivityId); String realParentExecutionId = FlowableUtils.getParentExecutionIdFromParentIds(taskExecution, parentExecutionIds); List<ExecutionEntity> childExecutions = executionEntityManager.findExecutionsByParentExecutionAndActivityIds(realParentExecutionId, activityIds); return childExecutions; }}