Flowable 任务节点按流程执行顺序排序

背景

在流程设计器里面画完图之后,后端从xml的BpmnModel解析出来的任务节点列表,其顺序是画图时节点的创建顺序。而绝大多数情况下,我们期望的任务节点顺序是流程执行顺序。这就需要进行一次排序。
排序

思路
  1. 拿到开始节点
  2. 通过开始节点的出口箭头拿到下一个节点
  3. 重复上面的动作,拿到下一个节点的目标节点,直到流程图结束
/**
 * 获取所有排序后的用户任务节点
 *
 * @param model bpmnModel对象
 * @return 用户任务节点列表
 */
public static List<UserTask> getAllSortedUserTaskEvent(BpmnModel model) {
    final Collection<UserTask> userTasks = getAllUserTaskEvent(model);
    return sortTasksByFlowPath(getStartEvent(model), userTasks);
}

/**
 * 获取开始节点
 *
 * @param model bpmnModel对象
 * @return 开始节点(未找到开始节点,返回null)
 */
public static StartEvent getStartEvent(BpmnModel model) {
    Process process = model.getMainProcess();
    FlowElement startElement = process.getInitialFlowElement();
    if (startElement instanceof StartEvent) {
        return (StartEvent) startElement;
    }
    return getStartEvent(process.getFlowElements());
}

/**
 * 获取所有用户任务节点
 *
 * @param model bpmnModel对象
 * @return 用户任务节点列表
 */
public static Collection<UserTask> getAllUserTaskEvent(BpmnModel model) {
    Process process = model.getMainProcess();
    Collection<FlowElement> flowElements = process.getFlowElements();
    return getAllUserTaskEvent(flowElements, null);
}

/**
 * 获取所有用户任务节点
 * @param flowElements 流程元素集合
 * @param allElements 所有流程元素集合
 * @return 用户任务节点列表
 */
public static Collection<UserTask> getAllUserTaskEvent(Collection<FlowElement> flowElements, Collection<UserTask> allElements) {
    allElements = allElements == null ? new ArrayList<>() : allElements;
    for (FlowElement flowElement : flowElements) {

        if (flowElement instanceof UserTask) {
            allElements.add((UserTask) flowElement);
        }
        if (flowElement instanceof SubProcess) {
            // 继续深入子流程,进一步获取子流程
            allElements = getAllUserTaskEvent(((SubProcess) flowElement).getFlowElements(), allElements);
        }
    }
    return allElements;
}

/**
 * 对任务节点按照流程图顺序排序
 * @param startEvent 开始节点(根节点)
 * @param userTasks 所有任务节点
 * @return
 */
public static List<UserTask> sortTasksByFlowPath(StartEvent startEvent, Collection<UserTask> userTasks) {
    List<UserTask> sorted = new ArrayList<>(userTasks.size());
    FlowElement next = startEvent.getOutgoingFlows().get(0).getTargetFlowElement();
    if (next == null) {
        throw new ServiceException("流程图开始节点未找到目标节点");
    }
    // 第一个节点
    sorted.add((UserTask) next);
    boolean end = false;
    while (!end) {
        next = findTargetNode(next);
        if (next instanceof Gateway) {
            continue;
        }
        if (next instanceof EndEvent) {
            end = true;
            continue;
        }
        if (next == null) {
            end = true;
        } else {
            sorted.add((UserTask) next);
        }
    }

    return sorted;
}

/**
 * 查找节点在工作流中的下一个节点。如遇到网关有多个出口路径,则只搜索条件表达式包含‘pass’的路径。
 *
 * @param node
 * @return
 */
private static FlowElement findTargetNode(FlowElement node) {
    if (node instanceof Gateway) {
        SequenceFlow passWay = ((Gateway) node).getOutgoingFlows().stream()
                .filter(flow -> flow.getConditionExpression().contains("pass"))
                .findFirst()
                .orElseThrow(()-> new ServiceException("网关未正确配置流转条件"));
        return passWay.getTargetFlowElement();
    }
    if (node instanceof EndEvent) {
        return null;
    }
    if (node == null) {
        return null;
    }
    final UserTask userTask = (UserTask) node;
    // 用户任务节点默认只支持一个出口路径
    return userTask.getOutgoingFlows().get(0).getTargetFlowElement();
}

/**
 * xml转bpmnModel对象
 *
 * @param xml xml
 * @return bpmnModel对象
 */
public static BpmnModel getBpmnModel(String xml) {
    return bpmnXMLConverter.convertToBpmnModel(new StringStreamSource(xml), false, false);
}

public static void main(String[] args) {
    String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>.......";
    final BpmnModel bpmnModel = getBpmnModel(xml);
    final Collection<UserTask> sortedUserTaskEvent = getAllSortedUserTaskEvent(bpmnModel);
    for (UserTask userTask : sortedUserTaskEvent) {
        System.out.println(userTask.getName());
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值