上篇博文,咱們完成一個任務SKIP的實現,說好要給各位看官帶來駁回實現的如今,就奉上具體實現和講解。(其實我感受個人註釋寫的已經很是清楚了,哈哈)java
依舊是,先說咱們的需求和思路。web
PS:數據庫
從6.0.0降到5.22.0版本的緣由由於項目中有一個版本衝突,致使的降級。後期仍是以新版本爲主。6.0版本的駁回有時間再來搞。ide
需求:測試
嗯,大體上就是這樣的一個需求,根據這個需求,其實我走了不少彎路,但都離不開兩點。this
思路:日誌
1. 將當前的任務節點的下一個任務節點指定爲指定的駁回任務節點 2. 將指定任務(目標任務)節點以後的流程軌跡,清空。
根據這個思路,我追了源碼,看了各類Service,Manager等等。由於別人的駁回流程我拿下來發現是有錯的,因此就本身研究了起來。如今就直接上代碼吧。呸。先上圖,沒圖誰會信你成功了呢?code
嗯 上面 就是一個測試過程,主要想表達一個意思:當前流程實例中的任務駁回以後,不影響別的流程實例。這裏有一張以前研究時的錯誤圖,能夠給你們看看。不噴哈~~排序
好了下面上代碼~~~~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這些類,還須要再研究研究~~