Activiti process rejected

Project address: activiti-workflow

There will be a rejection function in the general approval flow, and the interface provided by activiti does not reject it. This article implements the process rejection function by extending the interface provided by activiti. The main code is as follows

		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);
                }
            }
        }

The invokeSequenceFlows method, the specific code can be viewed in the project.



    /**
     * 处理撤回连线 可能存在分支
     * @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;
    }

Sort out some ideas, reject the option to pass in the definition ID of the target node, if not, select the next node of the start node by default. If there are multiple approval tasks at present, no other operations will be performed when the tasks executed this time are completed, and other tasks will be deleted after completion (without leaving approval traces).

The current approval process mainly processed by invokeSequenceFlows may have multiple tasks. The processing method is to add a parallel gateway to the task in front of the current node, connect the current approval node to the gateway, and the gateway to the target node. In this way, no matter how many approval tasks there are currently, the parallel gateway waits for all the previous nodes to complete before continuing to subsequent nodes, ensuring that the current approval tasks are all executed.

Probably the process is like this

Insert picture description here
This method is also used for withdrawal (initiator operation), there may be problems, and a lot of testing is required.

Guess you like

Origin blog.csdn.net/qq_34758074/article/details/106365223