目录
二、方案2:结合BPMN模型获取拓扑关系上的前一个任务(精准)
前言
本人前面的驳回方法如果存在相邻的任务连续驳回的情况时,会变成循环驳回,因为本人驳回取的任务是历史表里的最近的一个任务。
问题
代码如下:
//获取上一个任务的任务名称
String lastpoint = processEngine.getHistoryService().createHistoricTaskInstanceQuery().processInstanceId(processInstance.getProcessInstanceId())
.orderByHistoricTaskInstanceEndTime().desc().list().get(0).getName();
这段代码的目的是 获取指定流程实例中最新完成的历史任务的名称,这就会导致连续驳回的时候会查找到前一个驳回的任务,导致流程异常并结束!
并且当前代码存在一定的风险
-
空指针风险
-
如果流程实例没有历史任务(如刚启动),
list().get(0)
会抛出IndexOutOfBoundsException
。
-
-
性能问题
-
list()
会加载全部历史任务数据,若任务数量大(如万级),可能内存溢出。
-
-
逻辑不严谨
-
仅按结束时间排序可能无法准确反映“上一个任务”(需结合流程拓扑结构)。
-
改进方案
一、方案1:安全获取最新历史任务名称(基础优化)
String lastTaskName = null;
List<HistoricTaskInstance> historicTasks = processEngine.getHistoryService()
.createHistoricTaskInstanceQuery()
.processInstanceId(processInstance.getProcessInstanceId())
.finished() // 仅查询已完成的任务
.orderByHistoricTaskInstanceEndTime().desc()
.listPage(0, 1); // 仅查第一条
if (!historicTasks.isEmpty()) {
lastTaskName = historicTasks.get(0).getName();
} else {
lastTaskName = "无历史任务";
}
二、方案2:结合BPMN模型获取拓扑关系上的前一个任务(精准)
/**
* 查找当前任务的前一个用户任务
*/
public UserTask getPreviousUserTask(Task currentTask, BpmnModel bpmnModel) {
FlowElement currentElement = bpmnModel.getFlowElement(currentTask.getTaskDefinitionKey());
// 2. 向上查找
return findPreviousUserTask(bpmnModel, currentElement, 0);
}
private UserTask findPreviousUserTask(
BpmnModel bpmnModel,
FlowElement currentElement,
int depth) {
if (depth > 10 || !(currentElement instanceof FlowNode)) return null;
for (SequenceFlow flow : ((FlowNode) currentElement).getIncomingFlows()) {
FlowElement sourceElement = flow.getSourceFlowElement();
if (sourceElement instanceof UserTask) {
return (UserTask) sourceElement;
} else if (sourceElement instanceof Gateway) {
// 处理网关分支
UserTask task = findPreviousUserTask(bpmnModel, sourceElement, depth + 1);
if (task != null) return task;
} else if (sourceElement instanceof SubProcess) {
// 处理子流程
FlowElement startEvent = ((SubProcess) sourceElement).getFlowElements()
.stream()
.filter(e -> e instanceof StartEvent)
.findFirst()
.orElse(null);
return findPreviousUserTask(bpmnModel, startEvent, depth + 1);
}
}
return null;
}
三、关键区别与选择建议
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
方案1 | 实现简单,依赖历史数据 | 不反映流程拓扑,可能结果不准确 | 快速获取最近完成的任务名称 |
方案2 | 精准反映流程图的上下级关系 | 需解析BPMN模型,代码复杂 | 需要严格按流程图退回的场景 |
项目驳回改动代码
因为我的业务流程的驳回场景比较复杂,所以我这里的代码是使用的方案一和方案二的结合。流程图如下所示:
我这里很明显的从部门经理计划审批驳回的时候,如果是走的上面那条线那就需要方案一来驳回,如果是走的中间带主管计划审批的线,那就存在连续驳回到发起人,如果还使用方案一来驳回是做不到的,所以我这里在主管计划审批驳回的时候选择了方案二来实现。
//获取上一个任务的任务名称
String lastpoint = null;
List<HistoricTaskInstance> historicTaskInstances =
processEngine.getHistoryService().createHistoricTaskInstanceQuery().processInstanceId(processInstance.getProcessInstanceId())
.orderByHistoricTaskInstanceEndTime().desc().listPage(0, 1);
if (!historicTaskInstances.isEmpty()) {
lastpoint = historicTaskInstances.get(0).getName();
}
UserTask previousUserTask = getPreviousUserTask(task,bpmnModel);
if(task.getName().equals("主管计划审批")){
lastpoint = previousUserTask.getName();
}
String incomeNodesRecur = getIncomeNodesRecur(currActivityId, incomeNodes, process, false, processInstance.getProcessInstanceId(),
lastpoint);
具体的驳回代码请看博主的另一篇文章:
https://blog.csdn.net/milk_yan/article/details/143575778