工作流审批业务代码详解(四)

10.任务节点/TaskController

1.查询所有任务

查询所有的任务节点,主要调用historyService API提供的方法,详细逻辑见注释。
在这里插入图片描述

    @GetMapping(value = "/list")
    public Result list(TaskQueryVo taskQueryVo) {
    
    
        // 使用historyServiceAPI构建可输入条件的查询工厂
        HistoricTaskInstanceQuery query = createHistoricTaskInstanceQuery(taskQueryVo);
        //执行API的查询与排序
        FlowablePage page = this.pageList(taskQueryVo, query, TaskListWrapper.class, allowedSortProperties,
                HistoricTaskInstanceQueryProperty.START);
        return Result.ok(page);
    }

2.已办任务

我的已办任务列表,主要调用historyService API提供的方法(同上),并加入查询条件,详细逻辑见注释。
在这里插入图片描述

    @GetMapping(value = "/listDone")
    public Result listDone(TaskQueryVo taskQueryVo) {
    
    
        //根据historyService api创建查询工厂
        HistoricTaskInstanceQuery query = createHistoricTaskInstanceQuery(taskQueryVo);
        // 组装参数 加入查询条件,条件为已经完成/自己提交的/自己审批的
        query.finished().or().taskAssignee(SecurityUtils.getUserId())
            .taskOwner(SecurityUtils.getUserId()).endOr();
        //执行API的查询与排序
        FlowablePage page = this.pageList(taskQueryVo, query, TaskListWrapper.class, allowedSortProperties,
                HistoricTaskInstanceQueryProperty.START);
        return Result.ok(page);
    }

3.我的待办

我的待办任务列表,主要调用historyService API提供的方法(同上),并加入查询条件,详细逻辑见注释。
在这里插入图片描述

    @GetMapping(value = "/listTodo")
    public Result listTodo(TaskQueryVo taskQueryVo) {
    
    
        String userId = SecurityUtils.getUserId();
        // 根据historyService api创建查询工厂
        TaskQuery query = createTaskQuery(taskQueryVo);
        // 拼写参数 组装查询条件 条件为待办 且审批人为自己
        query.taskCategory(FlowableConstant.CATEGORY_TODO);
        query.or().taskCandidateOrAssigned(userId).taskOwner(userId).endOr();
        // 调用API方法查询
        FlowablePage page = this.pageList(taskQueryVo, query, TaskTodoListWrapper.class, allowedSortProperties,
                TaskQueryProperty.CREATE_TIME);
        return Result.ok(page);
    }

4.查询任务详情

我的待办任务列表,查询任务节点信息,并拼装所有详细信息返回,详细逻辑见注释。
在这里插入图片描述

    @GetMapping(value = "/queryById")
    public Result queryById(@RequestParam String taskId) {
    
    
        //调用service方法
        TaskResponse task = flowableTaskService.getTask(taskId);
        return Result.ok(task);
    }

    @Override
    public TaskResponse getTask(String taskId) {
    
    
        String userId = SecurityUtils.getUserId();
        //查询当前任务信息,并验证是否有查看权限
        HistoricTaskInstance taskHis = permissionService.validateReadPermissionOnTask(taskId, userId, true, true);
        TaskResponse rep = null;
        ProcessDefinition processDefinition = null;
        String formKey = null;
        Object renderedTaskForm = null;
        HistoricTaskInstance parentTask = null;
        //验证流程定义
        if (StringUtils.isNotEmpty(taskHis.getProcessDefinitionId())) {
    
    
            //查询流程定义信息
            processDefinition = repositoryService.getProcessDefinition(taskHis.getProcessDefinitionId());
            //挂载的表单信息
            formKey = formService.getTaskFormKey(processDefinition.getId(), taskHis.getTaskDefinitionKey());
            if (taskHis.getEndTime() == null && formKey != null && formKey.length() > 0) {
    
    
                //获取表单json
                renderedTaskForm = formService.getRenderedTaskForm(taskId);
            }
        }
        if (StringUtils.isNotEmpty(taskHis.getParentTaskId())) {
    
    
            parentTask =
                historyService.createHistoricTaskInstanceQuery().taskId(taskHis.getParentTaskId()).singleResult();
        }
        rep = new TaskResponse(taskHis, processDefinition, parentTask, null);
        rep.setFormKey(formKey);
        rep.setRenderedTaskForm(renderedTaskForm);
        //补全身份信息
        fillPermissionInformation(rep, taskHis, userId);
        // 补全审批人信息
        populateAssignee(taskHis, rep);
        rep.setInvolvedPeople(getInvolvedUsers(taskId));
        Task task = null;
        if (taskHis.getEndTime() == null) {
    
    
            task = taskService.createTaskQuery().taskId(taskId).singleResult();
            rep.setSuspended(task.isSuspended());
            rep.setDelegationState(task.getDelegationState());
        }
        //将用有人加入实体
        rep.setOwnerName(this.getUserName(taskHis.getOwner()));
        //将审批人加入实体
        rep.setAssigneeName(this.getUserName(taskHis.getAssignee()));
        return rep;
    }

5.转办任务

在审批时的转办业务,就是在当前审批加入一条过程意见,并重新设置新的审批人。详细逻辑见注释。
在这里插入图片描述

    @PutMapping(value = "/assign")
    public Result assign(@RequestBody TaskRequest taskRequest) {
    
    
        //调用service方法
        flowableTaskService.assignTask(taskRequest);
        return Result.ok();
    }

    public void assignTask(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String assignee = taskRequest.getUserId();
        String userId = SecurityUtils.getUserId();
        //获取任务信息
        Task task = permissionService.validateAssignPermissionOnTask(taskId, userId, assignee);
        //添加任务过程意见
        this.addComment(taskId, task.getProcessInstanceId(), userId, CommentTypeEnum.ZB, taskRequest.getMessage());
        //重新设置审批人
        taskService.setAssignee(task.getId(), assignee);
    }

6.委派任务

在审批过程中的委派业务,同上文,只不过需要调用提供的API,详细逻辑见注释。
在这里插入图片描述

    @PutMapping(value = "/delegate")
    public Result delegate(@RequestBody TaskRequest taskRequest) {
    
    
        //调用service方法
        flowableTaskService.delegateTask(taskRequest);
        return Result.ok();
    }

    public void delegateTask(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String delegater = taskRequest.getUserId();
        String userId =SecurityUtils.getUserId();
        //获取任务节点信息
        Task task = permissionService.validateDelegatePermissionOnTask(taskId, userId, delegater);
        //添加一条过程意见
        this.addComment(taskId, task.getProcessInstanceId(), userId, CommentTypeEnum.WP, taskRequest.getMessage());
        //调用API,委派人审批后,当前人需要再次审批
        taskService.delegateTask(task.getId(), delegater);
    }

7.认领任务

如类似组审批的情况,下一个节点可能很多人都能够审批该任务节点,这时候需要这些人中某一个认领该任务,认领后其他人在待办中不能在次查询到。API提供了认领的方法,详细逻辑见注释。
在这里插入图片描述

    @PutMapping(value = "/claim")
    public Result claim(@RequestBody TaskRequest taskRequest) {
    
    
        // 调用service提供方法
        flowableTaskService.claimTask(taskRequest);
        return Result.ok();
    }

     public void claimTask(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String userId = SecurityUtils.getUserId();
        //获取任务节点信息
        TaskInfo task = permissionService.validateReadPermissionOnTask2(taskId, userId, false, false);
        if (task.getAssignee() != null && task.getAssignee().length() > 0) {
    
    
            throw new FlowableNoPermissionException("User does not have permission");
        }
        //添加过程意见
        this.addComment(taskId, task.getProcessInstanceId(), userId, CommentTypeEnum.RL, taskRequest.getMessage());
        //认领任务(及指定审批人只能为当前任)个人认为是设置审批人为具体用户
        taskService.claim(taskId, userId);
    }

8.取消认领

与上文相反,回去初始状态,主要调用API方法,详细逻辑见注释。

    @PutMapping(value = "/unclaim")
    public Result unclaim(@RequestBody TaskRequest taskRequest) {
    
    
        //调用service方法
        flowableTaskService.unclaimTask(taskRequest);
        return Result.ok();
    }

    public void unclaimTask(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String userId = SecurityUtils.getUserId();
        TaskInfo task = this.getTaskNotNull(taskId);
        if (!userId.equals(task.getAssignee())) {
    
    
            throw new FlowableNoPermissionException("User does not have permission");
        }
        if (FlowableConstant.CATEGORY_TO_READ.equals(task.getCategory())) {
    
    
            throw new FlowableNoPermissionException("User cannot unclaim the read task");
        }
        if (FlowableConstant.INITIATOR.equals(task.getTaskDefinitionKey())) {
    
    
            throw new FlowableNoPermissionException("Initiator cannot unclaim the task");
        }
        //添加流程意见
        this.addComment(taskId, task.getProcessInstanceId(), userId, CommentTypeEnum.QXRL, taskRequest.getMessage());
        //调用API
        taskService.unclaim(taskId);
        // 判断是否是协办取消认领
        if (permissionService.isTaskPending((Task)task)) {
    
    
            //调用API
            taskService.resolveTask(taskId, null);
        }
    }

9.完成任务

提交任务,主要为调用API的complete()方法,在方法上放为拼接api需要的参数,详细逻辑见注释。
在这里插入图片描述

    @PutMapping(value = "/complete")
    public Result complete(@RequestBody TaskRequest taskRequest) {
    
    
        //调用service方法
        flowableTaskService.completeTask(taskRequest);
        return Result.ok();
    }

public void completeTask(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String currUserId = SecurityUtils.getUserId()
        Task task = getTaskNotNull(taskId);
        //判断用户是否有权限审批
        if (!permissionService.isTaskOwnerOrAssignee(currUserId, task)) {
    
    
            if (StringUtils.isEmpty(task.getScopeType())
                && !permissionService.validateIfUserIsInitiatorAndCanCompleteTask(currUserId, task)) {
    
    
                throw new FlowableNoPermissionException("User does not have permission");
            }
        }
        Map<String, Object> completeVariables = null;
        //验证当前节点是否挂载了审批时的表单
        if (taskRequest.getValues() != null && !taskRequest.getValues().isEmpty()) {
    
    
            //获取挂载表单的输入值
            completeVariables = taskRequest.getValues();
            // 允许任务表单修改流程表单场景 begin
            // 与前端约定:流程表单变量名为 processInstanceFormData,且只有流程表单startFormKey=taskFormKey时才允许修改该变量的值,防止恶意节点修改流程表单内容
            if (completeVariables.containsKey(FlowableConstant.PROCESS_INSTANCE_FORM_DATA)) {
    
    
                String startFormKey = formService.getStartFormKey(task.getProcessDefinitionId());
                String taskFormKey =
                    formService.getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
                boolean modifyProcessInstanceFormData = CommonFlowableUtil.isNotEmptyStr(startFormKey)
                    && CommonFlowableUtil.isNotEmptyStr(taskFormKey) && startFormKey.equals(taskFormKey);
                if (!modifyProcessInstanceFormData) {
    
    
                    throw new FlowableNoPermissionException("User does not have permission");
                }
            }
            // 允许任务表单修改流程表单场景 end
            // 非会签用户节点,默认设置流程变量 __taskDefinitionKey__=currUserId,用于存储该节点执行人,且以最近的执行人为准
            UserTask userTask = (UserTask)FlowableUtils.getFlowElement(repositoryService, task.getProcessDefinitionId(),
                task.getTaskDefinitionKey());
            if (userTask != null && !userTask.hasMultiInstanceLoopCharacteristics()) {
    
    
                completeVariables.put("__" + task.getTaskDefinitionKey() + "__", currUserId);
            }
        } else {
    
    
            // 非会签用户节点,默认设置流程变量 __taskDefinitionKey__=currUserId,用于存储该节点执行人,且以最近的执行人为准
            UserTask userTask = (UserTask)FlowableUtils.getFlowElement(repositoryService, task.getProcessDefinitionId(),
                task.getTaskDefinitionKey());
            if (userTask != null && !userTask.hasMultiInstanceLoopCharacteristics()) {
    
    
                completeVariables = new HashMap<>(1);
                completeVariables.put("__" + task.getTaskDefinitionKey() + "__", currUserId);
            }
        }
        //添加流程意见
        this.addComment(taskId, task.getProcessInstanceId(), currUserId,
            FlowableConstant.INITIATOR.equals(task.getTaskDefinitionKey()) ? CommentTypeEnum.CXTJ : CommentTypeEnum.WC,
            taskRequest.getMessage());
        // 处理抄送
        if (CommonFlowableUtil.isNotEmptyObject(taskRequest.getCcToVos())) {
    
    
            managementService.executeCommand(new AddCcIdentityLinkCmd(task.getProcessInstanceId(), task.getId(),
                currUserId, taskRequest.getCcToVos()));
        }
        //添加审批人
        if (task.getAssignee() == null || !task.getAssignee().equals(currUserId)) {
    
    
            taskService.setAssignee(taskId, currUserId);
        }
        // 判断是否是协办完成还是正常流转
        if (permissionService.isTaskPending(task)) {
    
    
            taskService.resolveTask(taskId, completeVariables);
            // 如果当前执行人是任务所有人,直接完成任务
            if (currUserId.equals(task.getOwner())) {
    
    
                //调用api
                taskService.complete(taskId, completeVariables);
            }
        } else {
    
    
            //调用api
            taskService.complete(taskId, completeVariables);
        }
    }

1.处理抄送人

在浏览过程可以看到有抄送人处理,调用了自定义的类。主要是拼装抄送人的详细信息,并调用提供的API方法。

 public Void execute(CommandContext commandContext) {
    
    
        // 获取流程信息
        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
        ExecutionEntity processInstance = executionEntityManager.findById(processInstanceId);
        if (processInstance == null) {
    
    
            throw new FlowableObjectNotFoundException("Cannot find process instance with id " + processInstanceId,
                ExecutionEntity.class);
        }
        // 获取人员具体信息
        for (CcToVo ccTo : ccToVos) {
    
    
            IdentityLinkUtil.createProcessInstanceIdentityLink(processInstance, ccTo.getUserId(), null,
                FlowableConstant.CC);
        }
        this.createCcComment(commandContext);
        return null;
    }

    protected void createCcComment(CommandContext commandContext) {
    
    
        CommentEntityManager commentEntityManager = CommandContextUtil.getCommentEntityManager(commandContext);
        CommentEntity comment = (CommentEntity)commentEntityManager.create();
        // 拼装抄送人信息
        comment.setProcessInstanceId(processInstanceId);
        comment.setUserId(userId);
        comment.setType(FlowableConstant.CC);
        comment.setTime(CommandContextUtil.getProcessEngineConfiguration(commandContext).getClock().getCurrentTime());
        comment.setTaskId(taskId);
        comment.setAction("AddCcTo");
        String ccToStr = StringUtils.arrayToCommaDelimitedString((Object[])ccToVos);
        comment.setMessage(ccToStr);
        comment.setFullMessage(ccToStr);
        // 调用api
        commentEntityManager.insert(comment);
    }

10.终止流程

只有当前人和管理员能够终止流程(如表单填写错误等),拼装完流程信息后,直接调用API更改流程状态。详细逻辑见注释。
在这里插入图片描述

    @PutMapping(value = "/stopProcessInstance")
    public Result stopProcessInstance(@RequestBody TaskRequest taskRequest) {
    
    
        // 调用service提供方法
        flowableTaskService.stopProcessInstance(taskRequest);
        return Result.ok();
    }

    public void stopProcessInstance(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String userId = SecurityUtils.getUserId();
        //验证是否有权限结束流程
        ProcessInstance processInstance = permissionService.validateStopProcessInstancePermissionOnTask(taskId, userId);
        //获取bpmn的对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        if (bpmnModel != null) {
    
    
            Process process = bpmnModel.getMainProcess();
            List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
            //查询结束节点的个数
            if (endNodes != null && endNodes.size() > 0) {
    
    
                //添加过程意见
                this.addComment(taskId, processInstance.getProcessInstanceId(), userId, CommentTypeEnum.ZZ,
                    taskRequest.getMessage());
                //获取第一个结束节点id
                String endId = endNodes.get(0).getId();
                //获取流程定义信息
                List<Execution> executions =
                    runtimeService.createExecutionQuery().parentId(processInstance.getProcessInstanceId()).list();
                List<String> executionIds = new ArrayList<>();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                //调用api更改状态为未激活
                runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endId)
                    .changeState();
            }
        }
    }

11.发起流程-查询表单信息

发起流程时,渲染需要填写的表单信息。主要为调用API,详细逻辑见注释。
在这里插入图片描述

    @GetMapping(value = "/renderedTaskForm")
    public ResultrenderedTaskForm(@RequestParam String taskId) {
    
    
        // 验证用户
        permissionService.validateReadPermissionOnTask2(taskId, SecurityUtils.getUserId(), true,
            true);
        // 执行查询 调用api
        Object renderedTaskForm = formService.getRenderedTaskForm(taskId);
        return Result.ok(renderedTaskForm);
    }

12.执行审批弹窗页面

主要输出为申请人表单与需要填写的审批表单信息。使用API查询信息,并拼装返回。详细逻辑见注释。
在这里插入图片描述

    @GetMapping(value = "/executeTaskData")
    public Result<ExecuteTaskDataVo> executeTaskData(@RequestParam String taskId) {
    
    
        // 验证权限
        Task task = permissionService.validateReadPermissionOnTask2(taskId,
            SecurityUtils.getUserId(), true, true);
        //查询bpmn信息
        Process process = repositoryService.getBpmnModel(task.getProcessDefinitionId()).getMainProcess();
        UserTask userTask = (UserTask)process.getFlowElement(task.getTaskDefinitionKey(), true);
        if (userTask == null) {
    
    
            throw new FlowableObjectNotFoundException("Can not find userTask by id " + task.getTaskDefinitionKey());
        }
        //拼装审批人表单和当前审批需要的表单
        String startFormKey = formService.getStartFormKey(task.getProcessDefinitionId());
        String taskFormKey = formService.getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
        Object renderedStartForm = formService.getRenderedStartForm(task.getProcessDefinitionId());
        Object renderedTaskForm = formService.getRenderedTaskForm(taskId);
        Map<String, Object> variables = runtimeService.getVariables(task.getProcessInstanceId());
        //获取流程实例信息
        ProcessInstance processInstance =
            runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        Boolean showBusinessKey = isShowBusinessKey(task.getProcessDefinitionId());
        //组装输出参数
        ExecuteTaskDataVo executeTaskDataVo = new ExecuteTaskDataVo();
        executeTaskDataVo.setStartUserId(processInstance.getStartUserId());
        executeTaskDataVo.setStartFormKey(startFormKey);
        executeTaskDataVo.setTaskFormKey(taskFormKey);
        executeTaskDataVo.setRenderedStartForm(renderedStartForm);
        executeTaskDataVo.setRenderedTaskForm(renderedTaskForm);
        executeTaskDataVo.setVariables(variables);
        executeTaskDataVo.setShowBusinessKey(showBusinessKey);
        // 当前任务是发起者
        if (FlowableConstant.INITIATOR.equals(task.getTaskDefinitionKey())) {
    
    
            executeTaskDataVo.setInitiator(true);
        }
        String buttons = FlowableUtils.getFlowableAttributeValue(userTask, FlowableConstant.BUTTONS);
        if (buttons != null) {
    
    
            executeTaskDataVo.setButtons(buttons.split(","));
        }
        historyService.createHistoricVariableInstanceQuery().processInstanceId("ss").variableNameLike("ss");
        return Result.ok(executeTaskDataVo);
    }

13.退回任务

在审批过程中,可以将任务退回到之前的某一个节点。
在这里插入图片描述

1.可退回任务列表

在退回时,可以指定具体的节点,那么需要查询之前节点列表,并组装成实体返回。

    @GetMapping(value = "/backNodes")
    public Result backNodes(@RequestParam String taskId) {
    
    
        Resultresult = new Result<>();
        // 调用service方法
        List<FlowNodeResponse> datas = flowableTaskService.getBackNodes(taskId);
        return Result.ok(datas);
    }

    public void stopProcessInstance(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String userId = SecurityUtils.getUserId();
        // 验证是否有权限结束流程
        ProcessInstance processInstance = permissionService.validateStopProcessInstancePermissionOnTask(taskId, userId);
        // 获取bpmn的对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        if (bpmnModel != null) {
    
    
            Process process = bpmnModel.getMainProcess();
            List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
            // 查询结束节点的个数
            if (endNodes != null && endNodes.size() > 0) {
    
    
                // 添加过程意见
                this.addComment(taskId, processInstance.getProcessInstanceId(), userId, CommentTypeEnum.ZZ,
                    taskRequest.getMessage());
                // 获取第一个结束节点id
                String endId = endNodes.get(0).getId();
                // 获取流程定义信息
                List<Execution> executions =
                    runtimeService.createExecutionQuery().parentId(processInstance.getProcessInstanceId()).list();
                List<String> executionIds = new ArrayList<>();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                // 调用api更改状态为未激活
                runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endId)
                    .changeState();
            }
        }
    }

2.执行回退

使用提供的api更改任务状态,在之前除了很多验证判断,详细逻辑见注释。

    @PutMapping(value = "/back")
    public Result back(@RequestBody TaskRequest taskRequest) {
    
    
        // 调用service方法
        flowableTaskService.backTask(taskRequest);
        return Result.ok();
    }

public void backTask(TaskRequest taskRequest) {
    
    
        String taskId = taskRequest.getTaskId();
        String userId = SecurityUtils.getUserId();
        Task task = permissionService.validateExcutePermissionOnTask(taskId, userId);
        // 验证是否有权限回退
        permissionService.validateTaskHasButtonPermission(task, ButtonsEnum.BACK);
        String backSysMessage = "退回到" + taskRequest.getActivityName() + "。";
        // 添加流程意见
        this.addComment(taskId, task.getProcessInstanceId(), userId, CommentTypeEnum.TH,
            backSysMessage + taskRequest.getMessage());
        // 执行BackUserTaskCmd方法
        String targetRealActivityId = managementService
            .executeCommand(new BackUserTaskCmd(runtimeService, taskRequest.getTaskId(), taskRequest.getActivityId()));
        // 退回发起者处理,退回到发起者,默认设置任务执行人为发起者
        if (FlowableConstant.INITIATOR.equals(targetRealActivityId)) {
    
    
            //获取开始人的username
            String initiator = runtimeService.createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId()).singleResult().getStartUserId();
            //获取开始节点信息
            List<Task> newTasks = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
            for (Task newTask : newTasks) {
    
    
                // 约定:发起者节点为 __initiator__
                if (FlowableConstant.INITIATOR.equals(newTask.getTaskDefinitionKey())) {
    
    
                    if (CommonFlowableUtil.isEmpty(newTask.getAssignee())) {
    
    
                        //设置审批人信息
                        taskService.setAssignee(newTask.getId(), initiator);
                    }
                }
            }
        }
    }

public class BackUserTaskCmd implements Command<String>, Serializable {
    
    
public String execute(CommandContext commandContext) {
    
    
        if (targetActivityId == null || targetActivityId.length() == 0) {
    
    
            throw new FlowableException("TargetActivityId cannot be empty");
        }
        /// v6.5.1.28
        TaskEntity task = CommandContextUtil.getProcessEngineConfiguration().getTaskServiceConfiguration()
            .getTaskService().getTask(taskId);
        if (task == null) {
    
    
            throw new FlowableObjectNotFoundException("task " + taskId + " doesn't exist", Task.class);
        }
        // 获取task具体信息
        String sourceActivityId = task.getTaskDefinitionKey();
        String processInstanceId = task.getProcessInstanceId();
        String processDefinitionId = task.getProcessDefinitionId();
        Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
        FlowNode sourceFlowElement = (FlowNode)process.getFlowElement(sourceActivityId, true);
        // 只支持从用户任务退回
        if (!(sourceFlowElement instanceof UserTask)) {
    
    
            throw new FlowableException("Task with id:" + taskId + " is not a UserTask");
        }
        FlowNode targetFlowElement = (FlowNode)process.getFlowElement(targetActivityId, true);
        // 退回节点到当前节点不可达到,不允许退回
        if (!FlowableUtils.isReachable(process, targetFlowElement, sourceFlowElement)) {
    
    
            throw new FlowableException("Cannot back to [" + targetActivityId + "]");
        }
        // ps:目标节点如果相对当前节点是在子流程内部,则无法直接退回,目前处理是只能退回到子流程开始节点
        String[] sourceAndTargetRealActivityId =
            FlowableUtils.getSourceAndTargetRealActivityId(sourceFlowElement, targetFlowElement);
        // 实际应操作的当前节点ID
        String sourceRealActivityId = sourceAndTargetRealActivityId[0];
        // 实际应操作的目标节点ID
        String targetRealActivityId = sourceAndTargetRealActivityId[1];
        Map<String, Set<String>> specialGatewayNodes = FlowableUtils.getSpecialGatewayElements(process);
        // 当前节点处在的并行网关list
        List<String> sourceInSpecialGatewayList = new ArrayList<>();
        // 目标节点处在的并行网关list
        List<String> targetInSpecialGatewayList = new ArrayList<>();
        setSpecialGatewayList(sourceRealActivityId, targetRealActivityId, specialGatewayNodes,
            sourceInSpecialGatewayList, targetInSpecialGatewayList);
        // 实际应筛选的节点ID
        Set<String> sourceRealAcitivtyIds = null;
        // 若退回目标节点相对当前节点在并行网关中,则要找到相对当前节点最近的这个并行网关,后续做特殊处理
        String targetRealSpecialGateway = null;
        // 1.目标节点和当前节点都不在并行网关中
        if (targetInSpecialGatewayList.isEmpty() && sourceInSpecialGatewayList.isEmpty()) {
    
    
            sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
        }
        // 2.目标节点不在并行网关中、当前节点在并行网关中
        else if (targetInSpecialGatewayList.isEmpty() && !sourceInSpecialGatewayList.isEmpty()) {
    
    
            sourceRealAcitivtyIds = specialGatewayNodes.get(sourceInSpecialGatewayList.get(0));
        }
        // 3.目标节点在并行网关中、当前节点不在并行网关中
        else if (!targetInSpecialGatewayList.isEmpty() && sourceInSpecialGatewayList.isEmpty()) {
    
    
            sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
            targetRealSpecialGateway = targetInSpecialGatewayList.get(0);
        }
        // 4.目标节点和当前节点都在并行网关中
        else {
    
    
            int diffSpecialGatewayLevel =
                FlowableUtils.getDiffLevel(sourceInSpecialGatewayList, targetInSpecialGatewayList);
            // 在并行网关同一层且在同一分支
            if (diffSpecialGatewayLevel == -1) {
    
    
                sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
            } else {
    
    
                // 当前节点最内层并行网关不被目标节点最内层并行网关包含
                // 或理解为当前节点相对目标节点在并行网关外
                // 只筛选当前节点的execution
                if (sourceInSpecialGatewayList.size() == diffSpecialGatewayLevel) {
    
    
                    sourceRealAcitivtyIds = Sets.newHashSet(sourceRealActivityId);
                }
                // 当前节点相对目标节点在并行网关内,应筛选相对目标节点最近的并行网关的所有节点的execution
                else {
    
    
                    sourceRealAcitivtyIds =
                        specialGatewayNodes.get(sourceInSpecialGatewayList.get(diffSpecialGatewayLevel));
                }
                // 目标节点最内层并行网关包含当前节点最内层并行网关
                // 或理解为目标节点相对当前节点在并行网关外
                // 不做处理
                if (targetInSpecialGatewayList.size() == diffSpecialGatewayLevel) {
    
    
                }
                // 目标节点相对当前节点在并行网关内
                else {
    
    
                    targetRealSpecialGateway = targetInSpecialGatewayList.get(diffSpecialGatewayLevel);
                }
            }
        }
        // 筛选需要处理的execution
        List<ExecutionEntity> realExecutions = this.getRealExecutions(commandContext, processInstanceId,
            task.getExecutionId(), sourceRealActivityId, sourceRealAcitivtyIds);
        // 执行退回,直接跳转到实际的 targetRealActivityId
        List<String> realExecutionIds =
            realExecutions.stream().map(ExecutionEntity::getId).collect(Collectors.toList());
        //执行API
        runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
            .moveExecutionsToSingleActivityId(realExecutionIds, targetRealActivityId).changeState();
        // 目标节点相对当前节点处于并行网关内,需要特殊处理,需要手动生成并行网关汇聚节点(_end)的execution数据
        if (targetRealSpecialGateway != null) {
    
    
            createTargetInSpecialGatewayEndExecutions(commandContext, realExecutions, process,
                targetInSpecialGatewayList, targetRealSpecialGateway);
        }
        return targetRealActivityId;
    }
    }

11.任务授权/TaskIdentityLinkController

任务授权不是必须业务流程,省略。

猜你喜欢

转载自blog.csdn.net/qq_20143059/article/details/120777644