場(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.2git地址:https://github.com/oldguys/flowable-modeler-demo/tree/branch_with_flowable_examples
所有章節(jié):
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(1)普通節(jié)點(diǎn)撤回
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(2)會(huì)簽任務(wù)(已完成)
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(3)會(huì)簽任務(wù)(正在執(zhí)行中)
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(4)多重網(wǎng)關(guān)
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(5)嵌入式子流程
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(6)調(diào)用式子流程
嵌入式子流程具有一定的特殊性,操作撤回的時(shí)候,比如 :
- 節(jié)點(diǎn) A 進(jìn)入子流程這種邊界事件
- 子流程中的 各節(jié)點(diǎn)的跳轉(zhuǎn) b-1 b-2 b-3
與之前一樣,對(duì)系統(tǒng)的各種數(shù)據(jù)進(jìn)行分析
從debug數(shù)據(jù)中可以看到饱亮,SubProcess 中的節(jié)點(diǎn) 存在于 節(jié)點(diǎn) SubProcess 中,不能直接通過(guò) getElement 拿到
然后 Process和 SubProcess 都實(shí)現(xiàn)于接口 org.flowable.bpmn.model.FlowElementsContainer辰如,并且調(diào)用的接口 是 FlowElementsContainer.getFlowElement(String id);
所以 可以從這兩處入手赞咙,進(jìn)行功能編寫
NextSubProcessRollbackOperateStrategy: 從嵌入式子流程撤回到普通節(jié)點(diǎn)
步驟:
- 如果下一節(jié)點(diǎn)是子流程 判定 子流程中 是否具有 已完成任務(wù)责循,如果具有,則不具備撤回條件攀操。如果正常則無(wú)所謂院仿。
- 像 之前一樣的步驟,構(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)建)
- 處理掉已生成的 子流程任務(wù)碰凶,另外暮芭,由上圖可以看出,子流程任務(wù) b-1 具有 頂級(jí) execution欲低,這個(gè)也需要進(jìn)行移除辕宏,不然會(huì)導(dǎo)致流程無(wú)法歸檔。
- 清理掉相關(guān)依賴數(shù)據(jù)砾莱。
如果是嵌入式子流程 內(nèi)部節(jié)點(diǎn)間處理瑞筐,則處理方式基本和 普通節(jié)點(diǎn)的處理方式一致,只需要判斷恤磷,如果 在 Process 找不到 flowElement面哼,則在SubProcess進(jìn)行找就行。所以之前的操作類直接滿足效果扫步。
基于模板方法模式魔策,構(gòu)建編寫通用 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)建主線
ExecutionEntity newExecution = CommandContextUtil.getExecutionEntityManager(commandContext).createChildExecution(executionEntity.getParent());
// 創(chuàng)建新任務(wù)
createExecution(newExecution);
// 移除歷史任務(wù)
removeHisTask(hisTask);
}
刪除歷史連線
@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í)間 之后線條
if (obj.getStartTime().getTime() > paramsTemplate.getHisTask().getCreateTime().getTime()
&& subProcessItemKeySet.contains(obj.getActivityId())) {
ids.add(obj.getId());
}
// 當(dāng)前任務(wù)的連線 ID
if (paramsTemplate.getHisTask().getTaskDefinitionKey().equals(obj.getActivityId())
&& obj.getEndTime().getTime() > paramsTemplate.getHisTask().getCreateTime().getTime()
) {
ids.add(obj.getId());
}
});
LOGGER.debug("移除歷史任務(wù)連線");
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