所谓驳回,其实就是返回到上个执行节点,但是这个里面又分两种情况
单个执行人assignee的情况
第一种情况比较简单,直接在流程图里用一个变量控制,比如audit为true时代表审核通过,走下一个节点,audit为false时代表驳回,返回上一个节点,这时直接连线到上一个节点,然后设置条件为${audit == false}即可。
多个候选人candidate user的情况
第二种情况就比较麻烦。用第一种情况的方法是不行的。为什么不行?有人说用上面的方法不是可以回到上次执行的节点吗?是的,虽然可以回到上次的节点,但是状态还是初始状态,即assignee为空的状态,我们知道,candidate需要先拾取任务,然后才能完成任务。举个例子,candidate user为张三和李四两个人,张三拾取任务后完成任务,到下一步后被驳回,这时上面的方法回到上一步时,为任务未拾取的状态,这时李四还可以拾取任务并完成。这样显然是不对的,驳回时应该打回到张三,也就是返回上一个节点时应该指定assignee为张三才对。
要实现上述效果,就要进行一些底层的操作了。大概思路如下:
- 取得当前节点的信息
- 取得当前节点的上一个节点的信息
- 保存当前节点的流向
- 新建流向,由当前节点指向上一个节点
- 将当前节点的流向设置为上面新建的流向
- 当前节点完成任务
- 将当前节点的流向还原
- 取得之前上个节点的执行人
- 设置上个节点的assignee为之前的执行人
好了,talk is cheap, show me the code,下面直接上代码(已测试通过)
如有问题,欢迎指正!
/** * * 退回到上一节点 * * @param task 当前任务 */ public void backProcess(Task task) throws Exception { String processInstanceId = task.getProcessInstanceId(); // 取得所有历史任务按时间降序排序 List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .orderByTaskCreateTime() .desc() .list(); if (ObjectUtils.isEmpty(htiList) || htiList.size() < 2) { return; } // list里的第二条代表上一个任务 HistoricTaskInstance lastTask = htiList.get(1); // list里第二条代表当前任务 HistoricTaskInstance curTask = htiList.get(0); // 当前节点的executionId String curExecutionId = curTask.getExecutionId(); // 上个节点的taskId String lastTaskId = lastTask.getId(); // 上个节点的executionId String lastExecutionId = lastTask.getExecutionId(); if (null == lastTaskId) { throw new Exception("LAST TASK IS NULL"); } String processDefinitionId = lastTask.getProcessDefinitionId(); BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); String lastActivityId = null; List<HistoricActivityInstance> haiFinishedList = historyService.createHistoricActivityInstanceQuery() .executionId(lastExecutionId).finished().list(); for (HistoricActivityInstance hai : haiFinishedList) { if (lastTaskId.equals(hai.getTaskId())) { // 得到ActivityId,只有HistoricActivityInstance对象里才有此方法 lastActivityId = hai.getActivityId(); break; } } // 得到上个节点的信息 FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivityId); // 取得当前节点的信息 Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult(); String curActivityId = execution.getActivityId(); FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId); //记录当前节点的原活动方向 List<SequenceFlow> oriSequenceFlows = new ArrayList<>(); oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows()); //清理活动方向 curFlowNode.getOutgoingFlows().clear(); //建立新方向 List<SequenceFlow> newSequenceFlowList = new ArrayList<>(); SequenceFlow newSequenceFlow = new SequenceFlow(); newSequenceFlow.setId("newSequenceFlowId"); newSequenceFlow.setSourceFlowElement(curFlowNode); newSequenceFlow.setTargetFlowElement(lastFlowNode); newSequenceFlowList.add(newSequenceFlow); curFlowNode.setOutgoingFlows(newSequenceFlowList); // 完成任务 taskService.complete(task.getId()); //恢复原方向 curFlowNode.setOutgoingFlows(oriSequenceFlows); org.activiti.engine.task.Task nextTask = taskService .createTaskQuery().processInstanceId(processInstanceId).singleResult(); // 设置执行人 if(nextTask!=null) { taskService.setAssignee(nextTask.getId(), lastTask.getAssignee()); } }