項目地址:activiti-workflow
在通用審批流中都會有駁回的功能,activiti提供的接口並沒有駁回。本文通過對activiti提供接口的擴展實現流程駁回功能,主要代碼如下
String processInstanceId = taskCurrent.getProcessInstanceId();
FlowElement targetFlowElement = null;
if (StringUtil.isNotEmpty(processRejectParam.getTargetNodeId())) {
//找到目標節點元素
targetFlowElement = bpmnModel.getMainProcess().getFlowElement(processRejectParam.getTargetNodeId());
} else {
//開始節點的下一個節點
targetFlowElement = BpmnUtil.startEventNextTaskId(bpmnModel);
}
//當前待審批節點定義Id集合
List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
if (CollectionUtil.isNotEmpty(taskList)) {
BpmnModel newBpmnModel = bpmnModel;
Map<String, List<SequenceFlow>> stringListMap = BpmnUtil.invokeSequenceFlows(newBpmnModel, taskList, targetFlowElement);
for (Task task : taskList) {
//記錄原活動方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
//當前節點
oriSequenceFlows.addAll(stringListMap.get(task.getTaskDefinitionKey()));
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());
try {
Map<String, Object> variables = new HashMap<>();
//當前操作節點
if(task.getId().equals(taskCurrent.getId())){
//設置當前審批人爲提交人
taskService.setAssignee(task.getId(), userId);
// 保存任務評價
if (StringUtil.isNotEmpty(rejectComment)) {
taskService.addComment(task.getId(), task.getProcessInstanceId(), rejectComment);
}
//設置節點狀態
taskService.setVariablesLocal(task.getId(), variables);
//完成
taskService.complete(task.getId());
}else{
//完成
taskService.complete(task.getId());
//刪除任務
historyService.deleteHistoricTaskInstance(task.getId());
}
} catch (Exception e) {
e.printStackTrace();
throw new ProcessException("流程撤回異常,異常原因:" + e.getMessage());
} finally {
//恢復原方向
currentFlowNode.setOutgoingFlows(oriSequenceFlows);
}
}
}
invokeSequenceFlows方法,具體代碼在項目中查看。
/**
* 處理撤回連線 可能存在分支
* @param bpmnModel
* @param taskList
* @param targetFlowElement
* @return
*/
public static Map<String,List<SequenceFlow>> invokeSequenceFlows(BpmnModel bpmnModel , List<Task> taskList, FlowElement targetFlowElement) {
Map<String,List<SequenceFlow>> flowElements = new HashMap<>(2);
//並行網關
ParallelGateway parallelGateway = new ParallelGateway();
parallelGateway.setId("parallelGateway" + targetFlowElement.getId());
parallelGateway.setBehavior(new ParallelGatewayActivityBehavior());
List<SequenceFlow> parallelSequenceFlowInCome = new ArrayList<>();
for (Task task : taskList) {
//當前節點
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());
flowElements.put(currentFlowNode.getId(),currentFlowNode.getOutgoingFlows());
//重新繪製流程圖,從當前節點到到並行網關
List<SequenceFlow> parallelSequenceFlowList = new ArrayList<>();
SequenceFlow parallelSequenceFlow = new SequenceFlow();
parallelSequenceFlow.setId("newSequenceFlowId" + System.currentTimeMillis());
parallelSequenceFlow.setSourceFlowElement(currentFlowNode);
parallelSequenceFlow.setTargetFlowElement(parallelGateway);
parallelSequenceFlowList.add(parallelSequenceFlow);
parallelSequenceFlowInCome.add(parallelSequenceFlow);
currentFlowNode.setOutgoingFlows(parallelSequenceFlowList);
}
//重新繪製流程圖,從並行網關到開始節點
List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
//繪製連線,加入流程信息,並組裝到流程圖
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId" + targetFlowElement.getId());
newSequenceFlow.setSourceFlowElement(parallelGateway);
newSequenceFlow.setTargetFlowElement(targetFlowElement);
newSequenceFlowList.add(newSequenceFlow);
parallelGateway.setIncomingFlows(parallelSequenceFlowInCome);
parallelGateway.setOutgoingFlows(newSequenceFlowList);
return flowElements;
}
整理一些思路,駁回可選擇傳入目標節點的定義ID,如果沒有就默認選擇開始節點的下一個節點。如果當前存在多個審批任務此次執行的任務完成不做其他操作,其他任務完成後刪除(不留下審批痕跡)。
invokeSequenceFlows主要處理的當前審批可能存在多個任務,處理方式爲,在當前節點前面任務增加一個並行網關,將當前審批節點連線到網關,網關連線到目標節點。這樣處理,不管當前有多少審批任務,由於並行網關是等待前面所有節點全部之下完成纔會繼續後續節點,保證當前審批任務全執行完成。
大概過程是這樣
該方法也使用於撤回(發起人操作),可能存在問題,還需大量測試。