工作流(二)--复杂API

young 2,456 2022-08-01

节点跳转

参考:https://blog.csdn.net/qh870754310/article/details/99692923

可让工作流不按照流程图流程,进行任务节点的转换

Flowable内置了相关的API,跳转时需要当前节点的TaskDefinitionKey和要跳转到节点的TaskDefinitionKey

/**
 * 单节点跳转单节点
 */
public void jumpTaskNodeOneToOne(String processInstanceId, String fromNodeId, String toNodeId) {
   runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
         .moveActivityIdTo(fromNodeId, toNodeId).changeState();
}

/**
 * 多节点跳转单节点(并行节点跳单节点)
 */
public void jumpTaskNodeMoreToOne(String processInstanceId, List<String> fromNodeIds, String toNodeId) {
   runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
         .moveActivityIdsToSingleActivityId(fromNodeIds, toNodeId).changeState();
}

/**
 * 单节点跳多节点(单节点跳并行节点)
 */
public void jumpTaskNodeOneToMore(String processInstanceId, String fromNodeId, List<String> toNodeIds) {
   runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
         .moveSingleActivityIdToActivityIds(fromNodeId, toNodeIds).changeState();
}

获取流程中所有节点及连线

通过流程配置文件

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(lastVersionBpmnXml.getBpnmXml());
BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
InputStreamSource inputStreamProvider = new InputStreamSource(byteArrayInputStream);
BpmnModel bpmnModel = bpmnXMLConverter.convertToBpmnModel(inputStreamProvider, false, false);
Process mainProcess = bpmnModel.getMainProcess();
Collection<FlowElement> flowElements = mainProcess.getFlowElements();

通过流程定义ID

ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
Collection<FlowElement> flowElements = mainProcess.getFlowElements();

用户任务节点转多实例任务节点

创建UserTask转换为MultiTask的Command类

/**
 * 将当前userTask变为多实例
 */
public class ChangeUserTaskToMulitInProcessInstanceCmd extends AbstractDynamicInjectionCmd implements Command<Void> {
   protected String processInstanceId;
   protected DynamicUserTaskBuilder dynamicUserTaskBuilder;
   protected FlowElement currentFlowElement;


   public ChangeUserTaskToMulitInProcessInstanceCmd(String processInstanceId,
         DynamicUserTaskBuilder dynamicUserTaskBuilder, FlowElement currentFlowElement) {
      this.processInstanceId = processInstanceId;
      this.dynamicUserTaskBuilder = dynamicUserTaskBuilder;
      this.currentFlowElement = currentFlowElement;
   }

   @Override
   public Void execute(CommandContext commandContext) {
      createDerivedProcessDefinitionForProcessInstance(commandContext, processInstanceId);
      return null;
   }

   @Override
   protected void updateBpmnProcess(CommandContext commandContext, Process process, BpmnModel bpmnModel,
         ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity) {

      List<StartEvent> startEvents = process.findFlowElementsOfType(StartEvent.class);
      StartEvent initialStartEvent = null;
      for (StartEvent startEvent : startEvents) {
         if (startEvent.getEventDefinitions().size() == 0) {
            initialStartEvent = startEvent;
            break;

         } else if (initialStartEvent == null) {
            initialStartEvent = startEvent;
         }
      }
      if (currentFlowElement != null) {

         // BeanUtils.copyProperties(currentFlowElement, userTask);
         UserTask userTask = (UserTask) process.getFlowElement(currentFlowElement.getId());
         userTask.setTaskListeners(fillMultiTaskFlowableListeners());
            userTask.setName(dynamicUserTaskBuilder.getName());
         MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = new MultiInstanceLoopCharacteristics();
         // 配置节点人员办理顺序 串行:true 并行:false.
         multiInstanceLoopCharacteristics.setSequential(false);
         // 配置会签集合变量名称.
         multiInstanceLoopCharacteristics.setInputDataItem("${assigneeList}");
         // 配置会签集合遍历名称.
         multiInstanceLoopCharacteristics.setElementVariable("assignee");
         // 将下一节点元素转换为任务节点对象.

         // 设置下一节点处理人表达式 引用会签条件activiti:elementVariable="assignee".
         userTask.setAssignee("${assignee}");
         // 下一任务节点设置会签循环特征.
         userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
            multiInstanceLoopCharacteristics
                    .setCompletionCondition("${multiOneVoteVetoCompleteTask.accessCondition(execution)}");
         // 获取流程引擎配置实现类.
         ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) ProcessEngines
               .getDefaultProcessEngine().getProcessEngineConfiguration();
         // 创建新的任务实例.
         UserTaskActivityBehavior userTaskActivityBehavior =
               processEngineConfiguration.getActivityBehaviorFactory().createUserTaskActivityBehavior(userTask);
         // 创建BPMN 2.0规范中描述的多实例功能.
         ParallelMultiInstanceBehavior behavior =
               new ParallelMultiInstanceBehavior(userTask, userTaskActivityBehavior);
         // 设置下一节点多实例行为.
         userTask.setBehavior(behavior);
         // 设置多实例元素变量.
         behavior.setCollectionElementVariable("assignee");
         // 注入表达式.
         ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
         // 设置多实例集合表达式.
         behavior.setCollectionExpression(expressionManager.createExpression("${assigneeList}"));
          behavior.setCompletionCondition("${multiOneVoteVetoCompleteTask.accessCondition(execution)}");

          // 自动布局
         // new BpmnAutoLayout(bpmnModel).execute();

      } else {
		// 官方API中的代码,增加并行网关,新增的节点执行后结束流程

         ParallelGateway parallelGateway = new ParallelGateway();
         parallelGateway.setId(dynamicUserTaskBuilder.nextForkGatewayId(process.getFlowElementMap()));
         process.addFlowElement(parallelGateway);

         UserTask userTask = new UserTask();
         if (dynamicUserTaskBuilder.getId() != null) {
            userTask.setId(dynamicUserTaskBuilder.getId());
         } else {
            userTask.setId(dynamicUserTaskBuilder.nextTaskId(process.getFlowElementMap()));
         }
         dynamicUserTaskBuilder.setDynamicTaskId(userTask.getId());

         userTask.setName(dynamicUserTaskBuilder.getName());
         userTask.setAssignee(dynamicUserTaskBuilder.getAssignee());
         process.addFlowElement(userTask);

         EndEvent endEvent = new EndEvent();
         endEvent.setId(dynamicUserTaskBuilder.nextEndEventId(process.getFlowElementMap()));
         process.addFlowElement(endEvent);

         SequenceFlow flowToUserTask = new SequenceFlow(parallelGateway.getId(), userTask.getId());
         flowToUserTask.setId(dynamicUserTaskBuilder.nextFlowId(process.getFlowElementMap()));
         process.addFlowElement(flowToUserTask);

         SequenceFlow flowFromUserTask = new SequenceFlow(userTask.getId(), endEvent.getId());
         flowFromUserTask.setId(dynamicUserTaskBuilder.nextFlowId(process.getFlowElementMap()));
         process.addFlowElement(flowFromUserTask);

         SequenceFlow initialFlow = initialStartEvent.getOutgoingFlows().get(0);
         initialFlow.setSourceRef(parallelGateway.getId());

         SequenceFlow flowFromStart = new SequenceFlow(initialStartEvent.getId(), parallelGateway.getId());
         flowFromStart.setId(dynamicUserTaskBuilder.nextFlowId(process.getFlowElementMap()));
         process.addFlowElement(flowFromStart);
         // 跳整节点的布局
         GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(initialStartEvent.getId());
         if (elementGraphicInfo != null) {
            double yDiff = 0;
            double xDiff = 80;
            if (elementGraphicInfo.getY() < 173) {
               yDiff = 173 - elementGraphicInfo.getY();
               elementGraphicInfo.setY(173);
            }

            Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
            for (String locationId : locationMap.keySet()) {
               if (initialStartEvent.getId().equals(locationId)) {
                  continue;
               }

               GraphicInfo locationGraphicInfo = locationMap.get(locationId);
               locationGraphicInfo.setX(locationGraphicInfo.getX() + xDiff);
               locationGraphicInfo.setY(locationGraphicInfo.getY() + yDiff);
            }

            Map<String, List<GraphicInfo>> flowLocationMap = bpmnModel.getFlowLocationMap();
            for (String flowId : flowLocationMap.keySet()) {
               if (flowFromStart.getId().equals(flowId)) {
                  continue;
               }

               List<GraphicInfo> flowGraphicInfoList = flowLocationMap.get(flowId);
               for (GraphicInfo flowGraphicInfo : flowGraphicInfoList) {
                  flowGraphicInfo.setX(flowGraphicInfo.getX() + xDiff);
                  flowGraphicInfo.setY(flowGraphicInfo.getY() + yDiff);
               }
            }

            GraphicInfo forkGraphicInfo =
                  new GraphicInfo(elementGraphicInfo.getX() + 75, elementGraphicInfo.getY() - 5, 40, 40);
            bpmnModel.addGraphicInfo(parallelGateway.getId(), forkGraphicInfo);

            bpmnModel.addFlowGraphicInfoList(flowFromStart.getId(),
                  createWayPoints(elementGraphicInfo.getX() + 30, elementGraphicInfo.getY() + 15,
                        elementGraphicInfo.getX() + 75, elementGraphicInfo.getY() + 15));

            GraphicInfo newTaskGraphicInfo =
                  new GraphicInfo(elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 163, 80, 100);
            bpmnModel.addGraphicInfo(userTask.getId(), newTaskGraphicInfo);

            bpmnModel.addFlowGraphicInfoList(flowToUserTask.getId(),
                  createWayPoints(elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 5,
                        elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 123,
                        elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 123));

            GraphicInfo endGraphicInfo =
                  new GraphicInfo(elementGraphicInfo.getX() + 335, elementGraphicInfo.getY() - 137, 28, 28);
            bpmnModel.addGraphicInfo(endEvent.getId(), endGraphicInfo);

            bpmnModel.addFlowGraphicInfoList(flowFromUserTask.getId(),
                  createWayPoints(elementGraphicInfo.getX() + 285, elementGraphicInfo.getY() - 123,
                        elementGraphicInfo.getX() + 335, elementGraphicInfo.getY() - 123));
         }
      }

      BaseDynamicSubProcessInjectUtil.processFlowElements(commandContext, process, bpmnModel,
            originalProcessDefinitionEntity, newDeploymentEntity);
   }

    private List<FlowableListener> fillMultiTaskFlowableListeners() {
        List<FlowableListener> list = new ArrayList<>();
        FlowableListener flowableListener = new FlowableListener();
        flowableListener.setEvent("complete");
        flowableListener.setImplementationType("expression");
        flowableListener.setImplementation("${afterMultiInstanceSubCompleteListener.notify(task)}");
        list.add(flowableListener);
        flowableListener =  new FlowableListener();
        flowableListener.setEvent("create");
        flowableListener.setImplementationType("expression");
        flowableListener.setImplementation("${beforeMultiUserTaskListener.notify(task)}");
        list.add(flowableListener);
        return list;
    }

   @Override
   protected void updateExecutions(CommandContext commandContext, ProcessDefinitionEntity processDefinitionEntity,
         ExecutionEntity processInstance, List<ExecutionEntity> childExecutions) {

      ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
      List<ExecutionEntity> oldExecution =
            executionEntityManager.findChildExecutionsByProcessInstanceId(processInstance.getProcessInstanceId());
      ExecutionEntity execution = executionEntityManager.createChildExecution(processInstance);
      BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionEntity.getId());

      org.flowable.task.service.TaskService taskService = CommandContextUtil.getTaskService(commandContext);
      List<TaskEntity> taskEntities = taskService.findTasksByProcessInstanceId(processInstanceId);
      // 删除当前活动任务
      for (TaskEntity taskEntity : taskEntities) {
         taskEntity.getIdentityLinks().stream().forEach(identityLinkEntity -> {
            if (identityLinkEntity.isGroup()) {
               taskEntity.deleteGroupIdentityLink(identityLinkEntity.getGroupId(), "candidate");
            } else {
               taskEntity.deleteUserIdentityLink(identityLinkEntity.getUserId(), "participant");
            }
         });
         if (taskEntity.getTaskDefinitionKey().equals(currentFlowElement.getId())) {

            taskService.deleteTask(taskEntity, false);
         }
      }
      // 设置活动后的节点
      // UserTask userTask = (UserTask)
      // bpmnModel.getProcessById(processDefinitionEntity.getKey()).getFlowElement(dynamicUserTaskBuilder.getId());
      UserTask userTask = (UserTask) bpmnModel.getProcessById(processDefinitionEntity.getKey())
            .getFlowElement(currentFlowElement.getId());
      execution.setCurrentFlowElement(userTask);
      Context.getAgenda().planContinueProcessOperation(execution);
   }

    @Override
    protected ProcessDefinitionEntity deployDerivedDeploymentEntity(CommandContext commandContext,
                                                                    DeploymentEntity deploymentEntity, ProcessDefinitionEntity originalProcessDefinitionEntity) {
        Map<String, Object> deploymentSettings = new HashMap<>();
        deploymentSettings.put(DeploymentSettings.IS_DERIVED_DEPLOYMENT, true);
        deploymentSettings.put(DeploymentSettings.DERIVED_PROCESS_DEFINITION_ID, originalProcessDefinitionEntity.getId());
        deploymentSettings.put(DeploymentSettings.IS_PROCESS_VALIDATION_ENABLED,false);
        deploymentSettings.put(DeploymentSettings.IS_BPMN20_XSD_VALIDATION_ENABLED,false);

        if (originalProcessDefinitionEntity.getDerivedFromRoot() != null) {
            deploymentSettings.put(DeploymentSettings.DERIVED_PROCESS_DEFINITION_ROOT_ID, originalProcessDefinitionEntity.getDerivedFromRoot());
        } else {
            deploymentSettings.put(DeploymentSettings.DERIVED_PROCESS_DEFINITION_ROOT_ID, originalProcessDefinitionEntity.getId());
        }

        deploymentEntity.setNew(true);
        List<EngineDeployer> deployers = CommandContextUtil.getProcessEngineConfiguration(commandContext).getDeploymentManager().getDeployers();
        for (EngineDeployer engineDeployer : deployers) {
            engineDeployer.deploy(deploymentEntity, deploymentSettings);
        }

        return deploymentEntity.getDeployedArtifacts(ProcessDefinitionEntity.class).get(0);
    }
}

调用该类

private String doUserTaskAddToMulti(Task task, String processInstanceId) {
   String dynamicUserId = "ADD_TASK_" + UUID.randomUUID().toString().replaceAll("-", "");
   DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
   dynamicUserTaskBuilder.setId(dynamicUserId);
   dynamicUserTaskBuilder.setName(task.getName() + WorkflowConst.ADD_REVIEWER_SUFFIX);
   dynamicUserTaskBuilder.setAssignee(task.getAssignee());
   String processDefinitionId = task.getProcessDefinitionId();
   BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
   Process process = bpmnModel.getProcesses().get(0);
   try {
      processEngine.getManagementService().executeCommand(new ChangeUserTaskToMulitInProcessInstanceCmd(
            processInstanceId, dynamicUserTaskBuilder, process.getFlowElement(task.getTaskDefinitionKey())));
   } catch (Exception e) {
      log.error(WorkflowResultCode.WORKFLOW_ADD_TASK_FAIL.getMessage(), e);
      throw new ResultCodeException(WorkflowResultCode.WORKFLOW_ADD_TASK_FAIL, e);
   }
   return dynamicUserId;
}

调用之后,流程实例ID、流程定义ID、任务ID、流程部署ID均会产生变化,因在远UserTask上进行改造,故TaskDefinitionKey不变。