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


上篇博文,我們完成一個任務SKIP的實現,說好要給各位看官帶來駁回實現的現在,就奉上具體實現和講解。(其實我感覺我的注釋寫的已經非常清楚了,哈哈)

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

PS:

從6.0.0降到5.22.0版本的原因因為項目中有一個版本沖突,導致的降級。后期還是以新版本為主。6.0版本的駁回有時間再來搞。

需求:

  1. 流程中的審批任務節點可以駁回到之前的任意任務節點
  2. 駁回到指定節點的任務之后的軌跡不需要顯示

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

思路:

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

點擊並拖拽以移動

根據這個思路,我追了源碼,看了各種Service,Manager等等。因為別人的駁回流程我拿下來發現是有錯的,所以就自己研究了起來。現在就直接上代碼吧。呸。先上圖,沒圖誰會信你成功了呢?

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

1.啟動報銷流程

  1. 啟動后查詢流程軌跡

2.啟動后查詢流程軌跡

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

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

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

4.駁回任務到指定節點

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

5.駁回后查詢

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

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

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

7啟動一個新的流程實例

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

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

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

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

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

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

嗯 上面 就是一個測試過程,主要想表達一個意思:當前流程實例中的任務駁回之后,不影響別的流程實例。這里有一張之前研究時的錯誤圖,可以給大家看看。不噴哈~~

研究過程中的錯誤

好了下面上代碼~~~~

代碼:

每一個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這些類,還需要再研究研究~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM