介绍
回退
操作是指,将流程退回到上一个节点,基本思路是通过审批历史服务HistoryService
找到审批审批的上一节点,而后跟通用回绝操作相似,将流程拨回到该节点,要留神的一个问题是,如果碰到并行审批,在并行线上回退应该回退到哪里呢?
如图,如果审批程序为主管审批->上级领导审批->董事长审批
,这时候总监审批执行回退操作,应该回退到哪个节点呢,显然不是董事长,因为这是两个并行互不烦扰的审批,失常应该回退到主管审批这里,所以回退操作应该是基于execution的回退。如果你对ecxecution不理解,你能够查看之前的文章SpringBoot Activiti6系列教程(六)-Execution阐明
因而,计划就是找到该execution的上个审批节点将流程回退到该节点。
实现
同样,咱们能够编写一个command的类实现回退
FlowToPreNodeCmd
import com.definesys.mpaas.common.exception.MpaasBusinessException;import org.activiti.bpmn.model.FlowElement;import org.activiti.bpmn.model.FlowNode;import org.activiti.bpmn.model.SequenceFlow;import org.activiti.engine.HistoryService;import org.activiti.engine.RepositoryService;import org.activiti.engine.history.HistoricActivityInstance;import org.activiti.engine.impl.interceptor.Command;import org.activiti.engine.impl.interceptor.CommandContext;import org.activiti.engine.impl.persistence.entity.ExecutionEntity;import org.activiti.engine.task.Task;import java.util.List;/** * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/9/24 6:11 PM * @history: 1.2019/9/24 created by jianfeng.zheng */public class FlowToPreNodeCmd implements Command<String> { private Task task; public FlowToPreNodeCmd(Task task) { this.task = task; } @Override public String execute(CommandContext context) { FlowElement element = this.getPreNode(this.task, context); if (element == null) { throw new MpaasBusinessException("该节点不能进行退回"); } SequenceFlow flow = this.findAcessSequenceFlow((FlowNode) element); ExecutionEntity executionEntity = context.getExecutionEntityManager().findById(task.getExecutionId()); executionEntity.setCurrentFlowElement(flow); context.getAgenda().planTakeOutgoingSequenceFlowsOperation(executionEntity, true); return executionEntity.getId(); } private FlowElement getPreNode(Task task, CommandContext context) { HistoryService historyService = context.getProcessEngineConfiguration().getHistoryService(); List<HistoricActivityInstance> items = historyService.createHistoricActivityInstanceQuery() .executionId(task.getExecutionId()) .activityType("userTask") .orderByHistoricActivityInstanceStartTime() .desc() .list(); if (items == null || items.size() == 0) { throw new MpaasBusinessException("未找到上一节点"); } String currentAct = task.getTaskDefinitionKey(); String preAct = null; for (int i = 0; i < items.size(); ++i) { HistoricActivityInstance item = items.get(i); if (currentAct.equals(item.getActivityId())) { continue; } preAct = item.getActivityId(); break; } if (preAct == null) { return null; } RepositoryService repositoryService = context.getProcessEngineConfiguration().getRepositoryService(); org.activiti.bpmn.model.Process process = repositoryService.getBpmnModel(task.getProcessDefinitionId()).getMainProcess(); FlowElement node = process.getFlowElement(preAct); return node; } private SequenceFlow findAcessSequenceFlow(FlowNode node) { List<SequenceFlow> flows = node.getIncomingFlows(); if (flows == null || flows.size() == 0) { throw new MpaasBusinessException("上一节点找不到入口"); } //找没有加条件的连线 for (SequenceFlow flow : flows) { if (flow.getConditionExpression() == null) { return flow; } } //如果都没有抉择第一条 return flows.get(0); }}
有两个中央须要留神
- 基于execution来进行查找,代码外面条件为
.executionId(task.getExecutionId())
- activiti从新执行一个流须要有一条“线”,无限思考没有加条件的线,保障流程可能流进咱们心愿的节点
下面仅仅只是流程回退的操作,要实现回退成果,还须要删除变量和以后的task。
@Overridepublic TaskResponse backwardTask(BPMContextInfo context, TaskResponse request, String user) { Task task = taskService.createTaskQuery().taskId(request.getTaskId()).singleResult(); managementService.executeCommand(new ExecutionVariableDeleteCmd(task.getExecutionId())); managementService.executeCommand(new FlowToPreNodeCmd(task)); managementService.executeCommand(new TaskDeleteCmd(request.getTaskId())); return this.taskResponse(task,task.getProcessInstanceId());}
这三个步骤程序不能扭转,第一步须要删除execution变量免得对新节点造成影响,最初一步才删除task,因为计算上一节点须要用到task,如果提前删除会造成task找不到。