Activiti驳回方法的补充

目录

前言

问题

改进方案

一、方案1:安全获取最新历史任务名称(基础优化)

二、方案2:结合BPMN模型获取拓扑关系上的前一个任务(精准)

三、关键区别与选择建议 

项目驳回改动代码

前言

        本人前面的驳回方法如果存在相邻的任务连续驳回的情况时,会变成循环驳回,因为本人驳回取的任务是历史表里的最近的一个任务。

问题

代码如下:

 //获取上一个任务的任务名称
String lastpoint =  processEngine.getHistoryService().createHistoricTaskInstanceQuery().processInstanceId(processInstance.getProcessInstanceId())
                        .orderByHistoricTaskInstanceEndTime().desc().list().get(0).getName();

这段代码的目的是 获取指定流程实例中最新完成的历史任务的名称,这就会导致连续驳回的时候会查找到前一个驳回的任务,导致流程异常并结束!

并且当前代码存在一定的风险

  1. 空指针风险

    • 如果流程实例没有历史任务(如刚启动),list().get(0) 会抛出 IndexOutOfBoundsException

  2. 性能问题

    • list() 会加载全部历史任务数据,若任务数量大(如万级),可能内存溢出。

  3. 逻辑不严谨

    • 仅按结束时间排序可能无法准确反映“上一个任务”(需结合流程拓扑结构)。

改进方案

一、方案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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值