Activiti 5.22.0 之自由駁回任務實現(親測)

上篇博文,咱們完成一個任務SKIP的實現,說好要給各位看官帶來駁回實現的如今,就奉上具體實現和講解。(其實我感受個人註釋寫的已經很是清楚了,哈哈)java

依舊是,先說咱們的需求和思路。web

PS:數據庫

從6.0.0降到5.22.0版本的緣由由於項目中有一個版本衝突,致使的降級。後期仍是以新版本爲主。6.0版本的駁回有時間再來搞。ide

需求:測試

  1. 流程中的審批任務節點能夠駁回到以前的任意任務節點
  2. 駁回到指定節點的任務以後的軌跡不須要顯示

嗯,大體上就是這樣的一個需求,根據這個需求,其實我走了不少彎路,但都離不開兩點。this

思路:日誌

1. 將當前的任務節點的下一個任務節點指定爲指定的駁回任務節點
2. 將指定任務(目標任務)節點以後的流程軌跡,清空。

點擊並拖拽以移動

根據這個思路,我追了源碼,看了各類Service,Manager等等。由於別人的駁回流程我拿下來發現是有錯的,因此就本身研究了起來。如今就直接上代碼吧。呸。先上圖,沒圖誰會信你成功了呢?code

  1. 啓動報銷流程 返回的是下個任務編號

1.啓動報銷流程

  1. 啓動後查詢流程軌跡

2.啓動後查詢流程軌跡

  1. 查詢流程中歷史任務節點信息

3.查詢流程中歷史任務節點信息

  1. 駁回任務到指定任務節點

4.駁回任務到指定節點

  1. 駁回後查詢流程軌跡圖

5.駁回後查詢

  1. 查詢駁回的歷史任務信息

6.查詢駁回的歷史任務信息

  1. 啓動一個新的流程實例

7啓動一個新的流程實例

  1. 查詢新的流程實例的軌跡

8.查詢新的流程實例的軌跡

  1. 完成新的流程實例任務,模擬審批經過

9.完成新的流程實例任務,模擬審批經過

  1. 查詢新流程實例對應完成任務後的軌跡

10.查詢新流程實例對應完成任務後的軌跡

嗯 上面 就是一個測試過程,主要想表達一個意思:當前流程實例中的任務駁回以後,不影響別的流程實例。這裏有一張以前研究時的錯誤圖,能夠給你們看看。不噴哈~~排序

研究過程當中的錯誤

好了下面上代碼~~~~get

代碼:

每個region endregion是一個代碼塊。在IDEA中是能夠摺疊的。C#中的習慣吧算是 能讓代碼更好看些。。。。(我的認爲)

/**
 * 駁回任務方封裝
 *
 * @param destinationTaskID 駁回的任務ID 目標任務ID
 * @param messageContent  駁回的理由
 * @param currentTaskID  當前正要執行的任務ID
 * @return 駁回結果 攜帶下個任務編號
 */
public ResponseResult rejectTask(String destinationTaskID, String currentTaskID, String messageContent) {
        // region 目標任務實例 historicDestinationTaskInstance 帶流程變量,任務變量
        HistoricTaskInstance historicDestinationTaskInstance = historyService
                            .createHistoricTaskInstanceQuery()
                            .taskId(destinationTaskID)
                            .includeProcessVariables()
                            .includeTaskLocalVariables()
                            .singleResult();
            // endregion
            // region 正在執行的任務實例 historicCurrentTaskInstance 帶流程變量,任務變量
            HistoricTaskInstance historicCurrentTaskInstance = historyService
                            .createHistoricTaskInstanceQuery()
                            .taskId(currentTaskID)
                            .includeProcessVariables()
                            .includeTaskLocalVariables()
                            .singleResult();
            // endregion
            // 流程定義ID
            String processDefinitionId = historicCurrentTaskInstance.getProcessDefinitionId();
            // 流程實例ID
            String processInstanceId = historicCurrentTaskInstance.getProcessInstanceId();
            // 流程定義實體
            ProcessDefinitionEntity processDefinition =
                    (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinitionId);
            // region 根據任務建立時間正序排序獲取歷史任務實例集合 historicTaskInstanceList 含流程變量,任務變量
            List<HistoricTaskInstance> historicTaskInstanceList = historyService
                    .createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .includeProcessVariables()
                    .includeTaskLocalVariables()
                    .orderByTaskCreateTime()
                    .asc()
                    .list();
            // endregion
            // region 歷史活動節點實例集合 historicActivityInstanceList
            List<HistoricActivityInstance> historicActivityInstanceList =
                    historyService
                            .createHistoricActivityInstanceQuery()
                            .processInstanceId(processInstanceId)
                            .orderByHistoricActivityInstanceStartTime()
                            .asc()
                            .list();
            // endregion
            // 獲取目標任務的節點信息
            ActivityImpl destinationActivity = processDefinition
                    .findActivity(historicDestinationTaskInstance.getTaskDefinitionKey());
            // 定義一個歷史任務集合,完成任務後任務刪除此集合中的任務
            List<HistoricTaskInstance> deleteHistoricTaskInstanceList = new ArrayList<>();
            // 定義一個歷史活動節點集合,完成任務後要添加的歷史活動節點集合
            List<HistoricActivityInstanceEntity> insertHistoricTaskActivityInstanceList = new ArrayList<>();
            // 目標任務編號
            Integer destinationTaskInstanceId = Integer.valueOf(destinationTaskID);
            // 有序
            for (HistoricTaskInstance historicTaskInstance : historicTaskInstanceList) {
                Integer historicTaskInstanceId = Integer.valueOf(historicTaskInstance.getId());
                if (destinationTaskInstanceId <= historicTaskInstanceId) {
                    deleteHistoricTaskInstanceList.add(historicTaskInstance);
                }
            }
            // 有序
            for (int i = 0; i < historicActivityInstanceList.size() - 1; i++) {
                HistoricActivityInstance historicActivityInstance = historicActivityInstanceList.get(i);
                // 歷史活動節點的任務編號
                Integer historicActivityInstanceTaskId;
                String taskId = historicActivityInstance.getTaskId();
                if (taskId != null) {
                    historicActivityInstanceTaskId = Integer.valueOf(taskId);
                    if (historicActivityInstanceTaskId <= destinationTaskInstanceId) {
                        insertHistoricTaskActivityInstanceList.add((HistoricActivityInstanceEntity) historicActivityInstance);
                    }
                } else {
                    if (historicActivityInstance.getActivityType().equals(ProcessConstant.START_EVENT)) {
                        insertHistoricTaskActivityInstanceList.add((HistoricActivityInstanceEntity) historicActivityInstance);
                    } else if (historicActivityInstance.getActivityType().equals(ProcessConstant.EXCLUSIVE_GATEWAY)) {
                        insertHistoricTaskActivityInstanceList.add((HistoricActivityInstanceEntity) historicActivityInstance);
                    }
                }
            }
            // 獲取流程定義的節點信息
            List<ActivityImpl> processDefinitionActivities = processDefinition.getActivities();
            // 用於保存正在執行的任務節點信息
            ActivityImpl currentActivity = null;
            // 用於保存原來的任務節點的出口信息
            PvmTransition pvmTransition = null;
            // 保存原來的流程節點出口信息
            for (ActivityImpl activity : processDefinitionActivities) {
                if (historicCurrentTaskInstance.getTaskDefinitionKey().equals(activity.getId())) {
                    currentActivity = activity;
                    // 備份
                    pvmTransition = activity.getOutgoingTransitions().get(0);
                    // 清空當前任務節點的出口信息
                    activity.getOutgoingTransitions().clear();
                }
            }
            // 執行流程轉向
            processEngine.getManagementService().executeCommand(
                    new RejectTaskCMD(historicDestinationTaskInstance, historicCurrentTaskInstance, destinationActivity));
            // 獲取正在執行的任務的流程變量
            Map<String, Object> taskLocalVariables = historicCurrentTaskInstance.getTaskLocalVariables();
            // 獲取目標任務的流程變量,修改任務不自動跳過,要求審批
            Map<String, Object> processVariables = historicDestinationTaskInstance.getProcessVariables();
            // 獲取流程發起人編號
            Integer employeeId = (Integer) processVariables.get(ProcessConstant.PROCESS_START_PERSON);
            processVariables.put(ProcessConstant.SKIP_EXPRESSION, false);
            taskLocalVariables.put(ProcessConstant.SKIP_EXPRESSION, false);
            // 設置駁回緣由
            taskLocalVariables.put(ProcessConstant.REJECT_REASON, messageContent);
            // region 流程變量轉換
            // 修改下個任務的任務辦理人
            processVariables.put(ProcessConstant.DEAL_PERSON_ID, processVariables.get(ProcessConstant.CURRENT_PERSON_ID));
            // 修改下個任務的任務辦理人姓名
            processVariables.put(ProcessConstant.DEAL_PERSON_NAME, processVariables.get(ProcessConstant.CURRENT_PERSON_NAME));
            // 修改下個任務的任務辦理人
            taskLocalVariables.put(ProcessConstant.DEAL_PERSON_ID, processVariables.get(ProcessConstant.CURRENT_PERSON_ID));
            // 修改下個任務的任務辦理人姓名
            taskLocalVariables.put(ProcessConstant.DEAL_PERSON_NAME, processVariables.get(ProcessConstant.CURRENT_PERSON_NAME));
            // endregion
            // 完成當前任務,任務走向目標任務
            String nextTaskId = processService.completeTaskByTaskID(currentTaskID, processVariables, taskLocalVariables);
            if (currentActivity != null) {
                // 清空臨時轉向信息
                currentActivity.getOutgoingTransitions().clear();
            }
            if (currentActivity != null) {
                // 恢復原來的走向
                currentActivity.getOutgoingTransitions().add(pvmTransition);
            }
            // 刪除歷史任務
            for (HistoricTaskInstance historicTaskInstance : deleteHistoricTaskInstanceList) {
                historyService.deleteHistoricTaskInstance(historicTaskInstance.getId());
            }
            // 刪除活動節點
            processEngine.getManagementService().executeCommand(
                    (Command<List<HistoricActivityInstanceEntity>>) commandContext -> {
                        HistoricActivityInstanceEntityManager historicActivityInstanceEntityManager =
                                commandContext.getHistoricActivityInstanceEntityManager();
                        // 刪除全部的歷史活動節點
                        historicActivityInstanceEntityManager
                                .deleteHistoricActivityInstancesByProcessInstanceId(processInstanceId);
                        // 提交到數據庫
                        commandContext.getDbSqlSession().flush();
                        // 添加歷史活動節點的
                        for (HistoricActivityInstanceEntity historicActivityInstance : insertHistoricTaskActivityInstanceList) {
                            historicActivityInstanceEntityManager.insertHistoricActivityInstance(historicActivityInstance);
                        }
                        // 提交到數據庫
                        commandContext.getDbSqlSession().flush();
                        return null;
                    }
            );
        // 返回下個任務的任務ID
        return ResponseResultUtil.success(nextTaskId);
    }

我本身都知道有很差的地方,可是別的方法我沒有實現成功,因此先這樣作吧。過年的時候再好好看看改改。

下面是RejectTaskCMD這個類的代碼:

package com.edu.hart.web.manage.process;

import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;

/**
 * 任務駁回方法支持
 *
 * @author create by 葉雲軒 at 2018/1/15 09:32
 */
public class RejectTaskCMD implements Command<Object>, Serializable {
    /**
 * RejectTaskCMD 日誌控制器
 * Create by 葉雲軒 at 2018/1/19 09:43
 * Concat at yCountJavaXuan@outlook.com
 */
    private static final Logger LOGGER = LoggerFactory.getLogger(RejectTaskCMD.class);
    /**
 * 歷史信息中的當前任務實例
 */
    private HistoricTaskInstance currentTaskInstance;
    /**
 * 歷史信息中的目標任務實例
 */
    private HistoricTaskInstance destinationTaskInstance;
    /**
 * 目標任務節點
 */
    private ActivityImpl destinationActivity;

    /**
 * 構造方法
 *
 * @param currentTaskInstance  當前任務實例
 * @param destinationTaskInstance 目標任務實例
 * @param destinationActivity  目標節點
 */
    public RejectTaskCMD(HistoricTaskInstance currentTaskInstance
            , HistoricTaskInstance destinationTaskInstance
            , ActivityImpl destinationActivity) {
        this.currentTaskInstance = currentTaskInstance;
        this.destinationTaskInstance = destinationTaskInstance;
        this.destinationActivity = destinationActivity;
    }

    @Override
    public Object execute(CommandContext commandContext) {
        // 流程實例ID
        String processInstanceId = destinationTaskInstance.getProcessInstanceId();
        // 執行管理器
        ExecutionEntityManager executionEntityManager =
                commandContext.getExecutionEntityManager();
        // select * from ACT_RU_EXECUTION where ID_ = ? 查詢當前流程實例中正在執行的惟一任務 --追源碼時發現這個方法的做用,就記錄了下來,省的本身遺忘掉
        ExecutionEntity executionEntity = executionEntityManager.findExecutionById(processInstanceId);
        // 當前活躍的節點信息
        ActivityImpl currentActivity = executionEntity.getActivity();
        // 建立一個出口轉向
        TransitionImpl outgoingTransition = currentActivity.createOutgoingTransition();
        // 封裝目標節點到轉向實體
        outgoingTransition.setDestination(destinationActivity);
        // 流程轉向
        executionEntity.setTransition(outgoingTransition);
        return null;
    }
}

嗯,就是這樣來完成任意節點駁回的。當前先這樣實現了,6.0版本沒有了Pvm這些類,還須要再研究研究~~

相關文章
相關標籤/搜索