使用Flowable助隧,退回到歷史某一個節(jié)點违孝,退回場景有:
1.目標節(jié)點和當前節(jié)點都不在并行網(wǎng)關上个从,或者目標節(jié)點和當前節(jié)點在同一個并行網(wǎng)關的同一個分支
2.退回到并行網(wǎng)關分支中的某一個節(jié)點上
3.并行網(wǎng)關中的某一個分支節(jié)點上發(fā)起退回搔扁,退回到并行網(wǎng)關前面的某一個節(jié)點上
4.流程內(nèi)部子流程(SubProcess)践啄,子流程中退回到主干流程中某一個節(jié)點
5.流程內(nèi)部子流程(SubProcess)赚哗,主干流程退回到子流程中某一個節(jié)點
6.流程外部子流程(CallActivity)她紫,子流程中退回到主干流程中某一個節(jié)點、主干流程退回到子流程中某一個節(jié)點
我的思路屿储,目前已實現(xiàn) 1~4 贿讹,其中 5 可以退回到讓子流程重新開始,但不是子流程中的某一個節(jié)點够掠,完整源碼詳見:
springboot:https://gitee.com/zjm16/zjmzxfzhl
springcloud:https://gitee.com/zjm16/zjmzxfzhl-cloud
詳細流程圖可參見完整源碼路徑 zjmzxfzhl/src/main/resources/processes_test
下的流程文件
具體實現(xiàn)的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);
// 退回節(jié)點到當前節(jié)點不可達到民褂,不允許退回
if (!FlowableUtils.isReachable(process, targetFlowElement, sourceFlowElement)) {
throw new FlowableException("Cannot back to [" + targetActivityId + "]");
}
// ps:目標節(jié)點如果相對當前節(jié)點是在子流程內(nèi)部,則無法直接退回,目前處理是只能退回到子流程開始節(jié)點
String[] sourceAndTargetRealActivityId = FlowableUtils.getSourceAndTargetRealActivityId(sourceFlowElement, targetFlowElement);
// 實際應操作的當前節(jié)點ID
String sourceRealActivityId = sourceAndTargetRealActivityId[0];
// 實際應操作的目標節(jié)點ID
String targetRealActivityId = sourceAndTargetRealActivityId[1];
Map<String, Set<String>> specialGatewayNodes = FlowableUtils.getSpecialGatewayElements(process);
// 當前節(jié)點處在的并行網(wǎng)關list
List<String> sourceInSpecialGatewayList = new ArrayList<>();
// 目標節(jié)點處在的并行網(wǎng)關list
List<String> targetInSpecialGatewayList = new ArrayList<>();
setSpecialGatewayList(sourceRealActivityId, targetRealActivityId, specialGatewayNodes, sourceInSpecialGatewayList,
targetInSpecialGatewayList);
// 實際應篩選的節(jié)點ID
Set<String> sourceRealAcitivtyIds = null;
// 若退回目標節(jié)點相對當前節(jié)點在并行網(wǎng)關中赊堪,則要找到相對當前節(jié)點最近的這個并行網(wǎng)關面殖,后續(xù)做特殊處理
String targetRealSpecialGateway = null;
// 1.目標節(jié)點和當前節(jié)點都不在并行網(wǎng)關中
if (targetInSpecialGatewayList.isEmpty() && sourceInSpecialGatewayList.isEmpty()) {
sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
}
// 2.目標節(jié)點不在并行網(wǎng)關中、當前節(jié)點在并行網(wǎng)關中
else if (targetInSpecialGatewayList.isEmpty() && !sourceInSpecialGatewayList.isEmpty()) {
sourceRealAcitivtyIds = specialGatewayNodes.get(sourceInSpecialGatewayList.get(0));
}
// 3.目標節(jié)點在并行網(wǎng)關中哭廉、當前節(jié)點不在并行網(wǎng)關中
else if (!targetInSpecialGatewayList.isEmpty() && sourceInSpecialGatewayList.isEmpty()) {
sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
targetRealSpecialGateway = targetInSpecialGatewayList.get(0);
}
// 4.目標節(jié)點和當前節(jié)點都在并行網(wǎng)關中
else {
int diffSpecialGatewayLevel = FlowableUtils.getDiffLevel(sourceInSpecialGatewayList, targetInSpecialGatewayList);
// 在并行網(wǎng)關同一層且在同一分支
if (diffSpecialGatewayLevel == -1) {
sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
} else {
// 當前節(jié)點最內(nèi)層并行網(wǎng)關不被目標節(jié)點最內(nèi)層并行網(wǎng)關包含
// 或理解為當前節(jié)點相對目標節(jié)點在并行網(wǎng)關外
// 只篩選當前節(jié)點的execution
if (sourceInSpecialGatewayList.size() == diffSpecialGatewayLevel) {
sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
}
// 當前節(jié)點相對目標節(jié)點在并行網(wǎng)關內(nèi)脊僚,應篩選相對目標節(jié)點最近的并行網(wǎng)關的所有節(jié)點的execution
else {
sourceRealAcitivtyIds = specialGatewayNodes.get(sourceInSpecialGatewayList.get(diffSpecialGatewayLevel));
}
// 目標節(jié)點最內(nèi)層并行網(wǎng)關包含當前節(jié)點最內(nèi)層并行網(wǎng)關
// 或理解為目標節(jié)點相對當前節(jié)點在并行網(wǎng)關外
// 不做處理
if (targetInSpecialGatewayList.size() == diffSpecialGatewayLevel) {
}
// 目標節(jié)點相對當前節(jié)點在并行網(wǎng)關內(nèi)
else {
targetRealSpecialGateway = targetInSpecialGatewayList.get(diffSpecialGatewayLevel);
}
}
}
// 篩選需要處理的execution
List<ExecutionEntity> realExecutions = this.getRealExecutions(commandContext, processInstanceId, task.getExecutionId(), sourceRealActivityId,
sourceRealAcitivtyIds);
// 執(zhí)行退回,直接跳轉(zhuǎn)到實際的 targetRealActivityId
List<String> realExecutionIds = realExecutions.stream().map(ExecutionEntity::getId).collect(Collectors.toList());
runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
.moveExecutionsToSingleActivityId(realExecutionIds, targetRealActivityId).changeState();
// 目標節(jié)點相對當前節(jié)點處于并行網(wǎng)關內(nèi)遵绰,需要特殊處理辽幌,需要手動生成并行網(wǎng)關匯聚節(jié)點(_end)的execution數(shù)據(jù)
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) {
// 目標節(jié)點相對當前節(jié)點處于并行網(wǎng)關,需要手動生成并行網(wǎng)關匯聚節(jié)點(_end)的execution數(shù)據(jù)
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();
// 處理目標節(jié)點所處的分支以外的分支,即 總分枝數(shù)-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;
}
}