最近项目的需求是对已审批的节点进行撤回操作,核心的思路是:
public Boolean processWithdraw(ProcessWithdrawParam processWithdrawParam) {
String taskId = processWithdrawParam.getTaskId();
String userId = processWithdrawParam.getUserId();
HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(taskId).taskAssignee(userId).singleResult();
if (null == task) {
throw new ApplicationException("撤回失败,失败原因:未查到任务信息或者你没有权限撤回该任务");
}
//获取流程模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
if (null == bpmnModel) {
throw new ApplicationException("撤回失败,失败原因:未查到流程信息!");
}
String processInstanceId = task.getProcessInstanceId();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (null == processInstance) {
throw new ApplicationException("撤回失败,失败原因:流程已经结束,或者最后节点已经审批过,不支持撤回!");
}
if (processInstance.isSuspended()) {
throw new ApplicationException("撤回失败,失败原因:流程已经被禁用,不支持撤回!");
}
UserTask currentUserTask = (UserTask)bpmnModel.getFlowElement(task.getTaskDefinitionKey());
if(currentUserTask == null){
throw new ApplicationException("撤回失败,失败原因:当前节点不存在,不支持撤回!");
}
List tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).listPage(0, 500);
if(CollectionUtil.isNotEmpty(tasks)){
identityService.setAuthenticatedUserId(userId);
for (Task t : tasks) {
taskService.addComment(t.getId(), processInstanceId, "WITHDRAW", processWithdrawParam.getWithdrawComment());
}
}
//执行命令,撤回审批
processEngine.getManagementService().executeCommand(new WithdrawApproveCmd(processInstanceId, currentUserTask, processWithdrawParam.getTenantId()));
return Boolean.TRUE;
}
/**
* 任务撤回命令类
*
* @author zhougl
* @version v1.0.0
* @since 2020/9/21 16:49
*/
public class WithdrawApproveCmd implements Command {
private static final String TASK_NOT_EXECUTE = "TASK_NOT_EXECUTE";
private static final String TASK_WITHDRAW = "TASK_WITHDRAW";
/**
* 流程实例Id
*/
private final String processInstanceId;
private final String tenantId;
private final UserTask userTask;
/**
* 所有后续流转任务节点
*/
private Set userTasks = new ConcurrentHashSet<>();
/**
* 保存撤回节点的变量map
*/
private Map> varMap = new ConcurrentHashMap<>();
public WithdrawApproveCmd(String processInstanceId, UserTask userTask, String tenantId) {
this.processInstanceId = processInstanceId;
this.tenantId = tenantId;
this.userTask = userTask;
takeFlowUserTask(userTask);
// 把当前任务节点也加到未完成节点(多实例的情况-存在未审批的其他实例,也需要删除)
userTasks.add(userTask);
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
// 处理已经完成的任务
handleCompletedTask(commandContext);
// 删除任务
handleFollowTask(userTasks, commandContext);
// 创建子执行流,开启任务
ExecutionEntity processExecution = executionEntityManager.findById(processInstanceId);
ExecutionEntity childExecution = executionEntityManager.createChildExecution(processExecution);
childExecution.setCurrentFlowElement(userTask);
// 设置执行变量
VariableInstanceEntityManager variableManager = commandContext.getVariableInstanceEntityManager();
List variableInstanceEntities = varMap.get(userTask.getId());
if(CollectionUtil.isNotEmpty(variableInstanceEntities)){
variableInstanceEntities.forEach(var -> {
var.setExecution(childExecution);
variableManager.insert(var);
});
}
commandContext.getExecutionEntityManager().insert(childExecution);
// 交给activiti流转
commandContext.getAgenda().planContinueProcessOperation(childExecution);
return null;
}
private void handleCompletedTask(CommandContext commandContext) {
HistoricTaskInstanceEntityManager historicTaskManager = commandContext.getHistoricTaskInstanceEntityManager();
HistoricActivityInstanceQueryImpl query =
new HistoricActivityInstanceQueryImpl().activityId(userTask.getId()).processInstanceId(processInstanceId).activityTenantId(tenantId).finished();
List activityInstances =
commandContext.getHistoricActivityInstanceEntityManager().findHistoricActivityInstancesByQueryCriteria(query, new Page(0, Integer.MAX_VALUE));
for (HistoricActivityInstance activity : activityInstances) {
HistoricActivityInstanceEntity activityEntity = (HistoricActivityInstanceEntity) activity;
activityEntity.setDeleted(true);
activityEntity.setDeleteReason(TASK_WITHDRAW);
commandContext.getHistoricActivityInstanceEntityManager().update(activityEntity);
historicTaskManager.delete(activity.getTaskId());
}
}
private void handleFollowTask(Set userTasks, CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
HistoricTaskInstanceEntityManager historicTaskManager = commandContext.getHistoricTaskInstanceEntityManager();
for (UserTask userTask : userTasks) {
String taskDefId = userTask.getId();
List executionEntities =
new ArrayList<>(executionEntityManager.findInactiveExecutionsByActivityIdAndProcessInstanceId(taskDefId, processInstanceId));
for (ExecutionEntity parentExecution : executionEntities) {
//关闭未完成的任务执行流
List childExecutions =
executionEntityManager.findChildExecutionsByParentExecutionId(parentExecution.getId());
for (ExecutionEntity childExecution : childExecutions) {
executionEntityManager.deleteExecutionAndRelatedData(childExecution, TASK_NOT_EXECUTE, false);
// 删除历史实例
HistoricTaskInstanceQueryImpl query = new HistoricTaskInstanceQueryImpl().executionId(childExecution.getId()).processInstanceId(processInstanceId);
List historicTaskInstancesByQueryCriteria =
historicTaskManager.findHistoricTaskInstancesByQueryCriteria(query);
if (CollectionUtil.isNotEmpty(historicTaskInstancesByQueryCriteria)) {
for (HistoricTaskInstance historicTaskInstancesByQueryCriterion :
historicTaskInstancesByQueryCriteria) {
commandContext.getHistoricTaskInstanceEntityManager().delete(historicTaskInstancesByQueryCriterion.getId());
}
}
}
//父执行流关闭
VariableInstanceEntityManager variableManager = commandContext.getVariableInstanceEntityManager();
List variableInstances =
variableManager.findVariableInstancesByExecutionId(parentExecution.getId());
varMap.put(parentExecution.getActivityId(),variableInstances);
variableInstances.forEach(variableManager::delete);
executionEntityManager.deleteExecutionAndRelatedData(parentExecution, TASK_NOT_EXECUTE, false);
}
}
}
private void takeFlowUserTask(FlowNode flowNode) {
List targetElement =
flowNode.getOutgoingFlows().stream().map(SequenceFlow::getTargetFlowElement).collect(Collectors.toList());
targetElement.forEach(flowElement -> {
if (flowElement instanceof UserTask) {
userTasks.add((UserTask) flowElement);
} else {
List collect =
((FlowNode) flowElement).getOutgoingFlows().stream().map(SequenceFlow::getTargetFlowElement).collect(Collectors.toList());
collect.forEach(childElement -> takeFlowUserTask((FlowNode) childElement));
}
});
}
}
注意事项:
在删除下一节点流程变量时,需要把下一节点的变量暂存起来,在重新创建执行流时,设置这些变量,因为多实例的创建需要依赖这些变量。