共计 8781 个字符,预计需要花费 22 分钟才能阅读完成。
应用 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; | |
} | |
} |
正文完