activiti6自带的命令接口很强大,可以实现各种自定义功能。我们现在就可以利用这个命令接口,实现自由跳转任意节点功能。我们先来看看跳转任意节点的实现代码:
/**
* 跳转任意节点命令
* Create by Kalvin on 2020/5/1.
*/
public class JumpAnyWhereCmd implements Command<Void> {
private final RepositoryService repositoryService = SpringContextKit.getBean(RepositoryService.class);
private final String taskId;
private final String targetNodeId;
/**
* @param taskId 当前任务ID
* @param targetNodeId 目标节点定义ID
*/
public JumpAnyWhereCmd(String taskId, String targetNodeId) {
this.taskId = taskId;
this.targetNodeId = targetNodeId;
}
@Override
public Void execute(CommandContext commandContext) {
// 获取任务实例管理类
TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
// 获取当前任务实例
TaskEntity currentTask = taskEntityManager.findById(this.taskId);
// 获取当前节点的执行实例
ExecutionEntity execution = currentTask.getExecution();
String executionId = execution.getId();
// 获取流程定义id
String processDefinitionId = execution.getProcessDefinitionId();
// 获取目标节点
// Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
BpmnModel bpmnModel = this.repositoryService.getBpmnModel(processDefinitionId);
Process process = bpmnModel.getProcesses().get(0);
FlowElement flowElement = process.getFlowElement(this.targetNodeId);
// 获取历史管理
HistoryManager historyManager = commandContext.getHistoryManager();
// 通知当前活动结束(更新act_hi_actinst)
historyManager.recordActivityEnd(execution, this.comment);
// 通知任务节点结束(更新act_hi_taskinst)
historyManager.recordTaskEnd(this.taskId, this.comment);
// 删除正在执行的当前任务
taskEntityManager.delete(taskId);
// 此时设置执行实例的当前活动节点为目标节点
execution.setCurrentFlowElement(flowElement);
// 向operations中压入继续流程的操作类
commandContext.getAgenda().planContinueProcessOperation(execution);
return null;
}
}
好了,自由跳转任意节点功能已经实现了,但是我们是要实现驳回上一环节的功能,即跳转到上一环节节点。我们来看看参数【当前任务ID,目标节点ID】;当前任务ID就是当前流程任务ID,接下来我们需要获取到目标节点ID这个参数。
如果获取上一环节节点呢?我们可以通过获取整个流程定义信息,通过当前节点ID去递归往上查找类型为UserTask的任务节点,再通过历史节点实例数据过滤不符合的节点,即可得到上一环节任务节点。上代码:
// 获取上一环节节点信息
public static ProcessNode getPreOneIncomeNode(String currentNodeId, String processDefId) {
final List<ProcessNode> preNodes = new ArrayList<>();
ProcessKit.getIncomeNodesRecur(currentNodeId, processDefId, preNodes, false);
preNodes.forEach(node -> {
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
.processDefinitionId(processDefId).activityId(node.getNodeId()).finished().list();
if (CollectionUtil.isEmpty(historicActivityInstances)) {
preNodes.remove(node);
}
});
if (CollectionUtil.isEmpty(preNodes)) {
return null;
}
return preNodes.get(0);
}
public static void getIncomeNodesRecur(String currentNodeId, String processDefId, List<ProcessNode> incomeNodes, boolean isAll) {
Process process = ProcessKit.getProcess(processDefId);
FlowElement currentFlowElement = process.getFlowElement(currentNodeId);
List<SequenceFlow> incomingFlows = null;
if (currentFlowElement instanceof UserTask) {
incomingFlows = ((UserTask) currentFlowElement).getIncomingFlows();
} else if (currentFlowElement instanceof Gateway) {
incomingFlows = ((Gateway) currentFlowElement).getIncomingFlows();
} else if (currentFlowElement instanceof StartEvent) {
incomingFlows = ((StartEvent) currentFlowElement).getIncomingFlows();
}
if (incomingFlows != null && incomingFlows.size() > 0) {
incomingFlows.forEach(incomingFlow -> {
String expression = incomingFlow.getConditionExpression();
// 出线的上一节点
String sourceFlowElementID = incomingFlow.getSourceRef();
// 查询上一节点的信息
FlowElement preFlowElement = process.getFlowElement(sourceFlowElementID);
//用户任务
if (preFlowElement instanceof UserTask) {
incomeNodes.add(new ProcessNode(preFlowElement.getId(), preFlowElement.getName()));
if (isAll) {
getIncomeNodesRecur(preFlowElement.getId(), processDefId, incomeNodes, true);
}
}
//排他网关
else if (preFlowElement instanceof ExclusiveGateway) {
getIncomeNodesRecur(preFlowElement.getId(), processDefId, incomeNodes, isAll);
}
//并行网关
else if (preFlowElement instanceof ParallelGateway) {
getIncomeNodesRecur(preFlowElement.getId(), processDefId, incomeNodes, isAll);
}
});
}
}
ProcessNode preNode = getPreOneIncomeNode(currentNodeId, processDefId);
CommandExecutor commandExecutor = ((TaskServiceImpl) taskService).getCommandExecutor();
commandExecutor.execute(new JumpAnyWhereCmd(currentNodeId, preNode.getNodeId()));
到此,已完成了驳回上一环节功能的实现。
可到以下开源项目查看完整代码。
【kvf-admin】
此项目基于kvf-admin基础脚手架 + activiti6已集成大部分工作流核心API及功能,如下: