flowable 上一節(jié)點(diǎn)任務(wù)撤回-(5)嵌入式子流程

場(chǎng)景:本章主要描述 下一節(jié)點(diǎn) 嵌入式子流程 如何進(jìn)行回退操作。

嵌入式子流程

上一章:flowable 上一節(jié)點(diǎn)任務(wù)撤回-(4)多重網(wǎng)關(guān)
下一章:flowable 上一節(jié)點(diǎn)任務(wù)撤回-(6)調(diào)用式子流程

環(huán)境
springboot:2.2.0.RELEASE
flowable:6.4.2

git地址:https://github.com/oldguys/flowable-modeler-demo/tree/branch_with_flowable_examples

所有章節(jié):

  1. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(1)普通節(jié)點(diǎn)撤回
  2. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(2)會(huì)簽任務(wù)(已完成)
  3. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(3)會(huì)簽任務(wù)(正在執(zhí)行中)
  4. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(4)多重網(wǎng)關(guān)
  5. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(5)嵌入式子流程
  6. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(6)調(diào)用式子流程
嵌入式子流程

嵌入式子流程具有一定的特殊性,操作撤回的時(shí)候,比如 :

  1. 節(jié)點(diǎn) A 進(jìn)入子流程這種邊界事件
  2. 子流程中的 各節(jié)點(diǎn)的跳轉(zhuǎn) b-1 b-2 b-3

與之前一樣,對(duì)系統(tǒng)的各種數(shù)據(jù)進(jìn)行分析

BpmnModel
Process 與 SubProcess 共性
ACT_RU_EXECUTION
  1. 從debug數(shù)據(jù)中可以看到,SubProcess 中的節(jié)點(diǎn) 存在于 節(jié)點(diǎn) SubProcess 中,不能直接通過(guò) getElement 拿到

  2. 然后 Process和 SubProcess 都實(shí)現(xiàn)于接口 org.flowable.bpmn.model.FlowElementsContainer,并且調(diào)用的接口 是 FlowElementsContainer.getFlowElement(String id);

所以 可以從這兩處入手,進(jìn)行功能編寫(xiě)

NextSubProcessRollbackOperateStrategy: 從嵌入式子流程撤回到普通節(jié)點(diǎn)

步驟:

  1. 如果下一節(jié)點(diǎn)是子流程 判定 子流程中 是否具有 已完成任務(wù),如果具有,則不具備撤回條件。如果正常則無(wú)所謂。
  2. 像 之前一樣的步驟,構(gòu)建 Execution ,利用 Execution 生成 任務(wù)。(不過(guò)與普通任務(wù)不同 ,子流程前置 普通任務(wù)節(jié)點(diǎn)的 execution 已經(jīng)結(jié)束,不是同一個(gè),所以無(wú)法使用,需要根據(jù)邊界子節(jié)點(diǎn) 父級(jí)節(jié)點(diǎn) 進(jìn)行構(gòu)建)
  3. 處理掉已生成的 子流程任務(wù),另外,由上圖可以看出,子流程任務(wù) b-1 具有 頂級(jí) execution,這個(gè)也需要進(jìn)行移除,不然會(huì)導(dǎo)致流程無(wú)法歸檔。
  4. 清理掉相關(guān)依賴(lài)數(shù)據(jù)。

如果是嵌入式子流程 內(nèi)部節(jié)點(diǎn)間處理,則處理方式基本和 普通節(jié)點(diǎn)的處理方式一致,只需要判斷,如果 在 Process 找不到 flowElement,則在SubProcess進(jìn)行找就行。所以之前的操作類(lèi)直接滿(mǎn)足效果。

基于模板方法模式,構(gòu)建編寫(xiě)通用 RollbackOperateStrategy.process() 操作
    @Override
    public void process(CommandContext commandContext, String assignee, Map<String, Object> variables) {

        this.commandContext = commandContext;
        this.assignee = assignee;
        this.variables = variables;

        log.info("處理 existNextFinishedTask");
        existNextFinishedTask();
        log.info("配置任務(wù)執(zhí)行人 setAssignee");
        setAssignee();
        log.info("處理 createExecution");
        createExecution();
        log.info("處理 deleteRuntimeTasks");
        deleteRuntimeTasks();
        log.info("處理 deleteHisActInstance");
        deleteHisActInstance();
    }

判定是否具有已完成任務(wù),此處需要判定標(biāo)識(shí)是從 SubProcess 中獲取的


    @Override
    public void existNextFinishedTask() {

        Map<String, SubProcess> subProcessMap = paramsTemplate.getSubProcessMap();

        List<HistoricTaskInstance> historicTaskInstances = CommandContextUtil.getHistoricTaskService(commandContext)
                .findHistoricTaskInstancesByQueryCriteria(
                        (HistoricTaskInstanceQueryImpl) new HistoricTaskInstanceQueryImpl()
                                .taskCompletedAfter(paramsTemplate.getHisTask().getEndTime())
                                .finished()
                );

        String key = subProcessMap.keySet().iterator().next();
        this.subProcess = subProcessMap.get(key);

        subProcess.getFlowElements().forEach(obj -> subProcessItemKeySet.add(obj.getId()));
        if (!historicTaskInstances.isEmpty()) {
            historicTaskInstances.forEach(obj -> {
                if (subProcessItemKeySet.contains(obj.getTaskDefinitionKey())) {
                    LOGGER.error("出現(xiàn)已完成任務(wù),無(wú)法進(jìn)行流程節(jié)點(diǎn)撤回: [" + obj + "]");
                    throw new FlowableRuntimeException("出現(xiàn)已完成任務(wù),無(wú)法進(jìn)行流程節(jié)點(diǎn)撤回");
                }
            });
        }

    }

構(gòu)建 Execution:主要區(qū)別在于只能通過(guò)相鄰節(jié)點(diǎn)進(jìn)行獲取,不然當(dāng)出現(xiàn)多層級(jí)網(wǎng)關(guān)的時(shí)候,可能會(huì)出現(xiàn)層級(jí)錯(cuò)誤bug

  @Override
    public void createExecution() {

        HistoricTaskInstance hisTask = paramsTemplate.getHisTask();
        ExecutionEntity executionEntity = CommandContextUtil.getExecutionEntityManager(commandContext).findById(hisTask.getExecutionId());

        /**
         *  subProcess 作為下一節(jié)點(diǎn)的時(shí)候,hisTask的execution會(huì)被關(guān)閉調(diào)。所以需要重新創(chuàng)建
         */
        if (null == executionEntity) {
            LOGGER.info("hisTask:execution 為 null");

            List<ExecutionEntity> executionEntityList = CommandContextUtil
                    .getExecutionEntityManager(commandContext)
                    .findExecutionsByParentExecutionAndActivityIds(hisTask.getProcessInstanceId(), paramsTemplate.getNextFlowIdList());
            if (executionEntityList.isEmpty()) {
                throw new FlowableRuntimeException("沒(méi)有找到臨近節(jié)點(diǎn)");
            }
            executionEntity = executionEntityList.get(0);
        }
        // 創(chuàng)建主線(xiàn)
        ExecutionEntity newExecution = CommandContextUtil.getExecutionEntityManager(commandContext).createChildExecution(executionEntity.getParent());

        // 創(chuàng)建新任務(wù)
        createExecution(newExecution);
        // 移除歷史任務(wù)
        removeHisTask(hisTask);
    }

刪除歷史連線(xiàn)

    @Override
    public void deleteHisActInstance() {

        List<ActivityInstance> activityInstanceEntityList = CommandContextUtil.getActivityInstanceEntityManager(commandContext)
                .findActivityInstancesByQueryCriteria(
                        new ActivityInstanceQueryImpl()
                                .processInstanceId(paramsTemplate.getHisTask().getProcessInstanceId())
                );


        List<String> ids = new ArrayList<>();
        activityInstanceEntityList.forEach(obj -> {
            // 時(shí)間大于 任務(wù)創(chuàng)建時(shí)間 之后線(xiàn)條
            if (obj.getStartTime().getTime() > paramsTemplate.getHisTask().getCreateTime().getTime()
                    && subProcessItemKeySet.contains(obj.getActivityId())) {
                ids.add(obj.getId());
            }
            // 當(dāng)前任務(wù)的連線(xiàn) ID
            if (paramsTemplate.getHisTask().getTaskDefinitionKey().equals(obj.getActivityId())
                    && obj.getEndTime().getTime() > paramsTemplate.getHisTask().getCreateTime().getTime()
            ) {
                ids.add(obj.getId());
            }
        });

        LOGGER.debug("移除歷史任務(wù)連線(xiàn)");
        ids.forEach(obj -> historyActivityInstanceMapper.delete(obj));

    }

刪除正在進(jìn)行任務(wù)

    @Override
    public void deleteRuntimeTasks() {
        HistoricTaskInstance hisTask = paramsTemplate.getHisTask();

        List<TaskEntity> taskEntityList = CommandContextUtil.getTaskService(commandContext).findTasksByProcessInstanceId(hisTask.getProcessInstanceId());

        taskEntityList.forEach(obj -> {
            if (subProcessItemKeySet.contains(obj.getTaskDefinitionKey())) {
                LOGGER.info("移除正在執(zhí)行的下一節(jié)點(diǎn)任務(wù)");
                // 移除任務(wù)
                removeRuntimeTaskOperate(obj);
            }
        });

        // 獲取 subProcess 的 ExecutionEntity
        Collection<ExecutionEntity> executionEntities = CommandContextUtil
                .getExecutionEntityManager(commandContext)
                .findExecutionsByParentExecutionAndActivityIds(hisTask.getProcessInstanceId(), Collections.singletonList(subProcess.getId()));

        executionEntities.forEach(obj -> {
            LOGGER.info("移除 subProcess 層級(jí)execution");
            List<ExecutionEntity> children = CommandContextUtil
                    .getExecutionEntityManager(commandContext)
                    .findChildExecutionsByParentExecutionId(obj.getId());

            // 移除級(jí)聯(lián)子節(jié)點(diǎn)
            children.forEach(item -> CommandContextUtil
                    .getExecutionEntityManager(commandContext)
                    .delete(item));

            // 移除 subProcess 頂級(jí)
            CommandContextUtil
                    .getExecutionEntityManager(commandContext)
                    .delete(obj);
        });

    }

以上 完成對(duì) 上一節(jié)點(diǎn)任務(wù)撤回 架構(gòu)設(shè)計(jì) 及 第 5 種情況 解決方案講述。
git地址:https://github.com/oldguys/flowable-modeler-demo/tree/branch_with_flowable_examples

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容