上篇博文,我們完成一個任務SKIP的實現,說好要給各位看官帶來駁回實現的現在,就奉上具體實現和講解。(其實我感覺我的注釋寫的已經非常清楚了,哈哈)
依舊是,先說我們的需求和思路。
PS:
從6.0.0降到5.22.0版本的原因因為項目中有一個版本沖突,導致的降級。后期還是以新版本為主。6.0版本的駁回有時間再來搞。
需求:
- 流程中的審批任務節點可以駁回到之前的任意任務節點
- 駁回到指定節點的任務之后的軌跡不需要顯示
嗯,大致上就是這樣的一個需求,根據這個需求,其實我走了很多彎路,但都離不開兩點。
思路:
1. 將當前的任務節點的下一個任務節點指定為指定的駁回任務節點
2. 將指定任務(目標任務)節點之后的流程軌跡,清空。
根據這個思路,我追了源碼,看了各種Service,Manager等等。因為別人的駁回流程我拿下來發現是有錯的,所以就自己研究了起來。現在就直接上代碼吧。呸。先上圖,沒圖誰會信你成功了呢?
- 啟動報銷流程 返回的是下個任務編號
- 啟動后查詢流程軌跡
- 查詢流程中歷史任務節點信息
- 駁回任務到指定任務節點
- 駁回后查詢流程軌跡圖
- 查詢駁回的歷史任務信息
- 啟動一個新的流程實例
- 查詢新的流程實例的軌跡
- 完成新的流程實例任務,模擬審批通過
- 查詢新流程實例對應完成任務后的軌跡
嗯 上面 就是一個測試過程,主要想表達一個意思:當前流程實例中的任務駁回之后,不影響別的流程實例。這里有一張之前研究時的錯誤圖,可以給大家看看。不噴哈~~
好了下面上代碼~~~~
代碼:
每一個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這些類,還需要再研究研究~~