package com.dl.flowable.utils; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; import org.flowable.common.engine.impl.util.io.StringStreamSource; import java.util.*; /** * @author KonBAI * @createTime 2022/3/26 19:04 */ public class ModelUtils { private static final BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter(); /** * xml转bpmnModel对象 * * @param xml xml * @return bpmnModel对象 */ public static BpmnModel getBpmnModel(String xml) { return bpmnXMLConverter.convertToBpmnModel(new StringStreamSource(xml), false, false); } /** * bpmnModel转xml字符串 * * @deprecated 存在会丢失 bpmn 连线问题 * @param bpmnModel bpmnModel对象 * @return xml字符串 */ @Deprecated public static String getBpmnXmlStr(BpmnModel bpmnModel) { return StrUtil.utf8Str(getBpmnXml(bpmnModel)); } /** * bpmnModel转xml对象 * * @deprecated 存在丢失 bpmn 连线问题 * @param bpmnModel bpmnModel对象 * @return xml */ @Deprecated public static byte[] getBpmnXml(BpmnModel bpmnModel) { return bpmnXMLConverter.convertToXML(bpmnModel); } /** * 根据节点,获取入口连线 * * @param source 起始节点 * @return 入口连线列表 */ public static List getElementIncomingFlows(FlowElement source) { List sequenceFlows = new ArrayList<>(); if (source instanceof FlowNode) { sequenceFlows = ((FlowNode) source).getIncomingFlows(); } return sequenceFlows; } /** * 根据节点,获取出口连线 * * @param source 起始节点 * @return 出口连线列表 */ public static List getElementOutgoingFlows(FlowElement source) { List sequenceFlows = new ArrayList<>(); if (source instanceof FlowNode) { sequenceFlows = ((FlowNode) source).getOutgoingFlows(); } return sequenceFlows; } /** * 获取开始节点 * * @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 flowElements 流程元素集合 * @return 开始节点(未找到开始节点,返回null) */ public static StartEvent getStartEvent(Collection flowElements) { for (FlowElement flowElement : flowElements) { if (flowElement instanceof StartEvent) { return (StartEvent) flowElement; } } return null; } /** * 获取结束节点 * * @param model bpmnModel对象 * @return 结束节点(未找到开始节点,返回null) */ public static EndEvent getEndEvent(BpmnModel model) { Process process = model.getMainProcess(); return getEndEvent(process.getFlowElements()); } /** * 获取结束节点 * * @param flowElements 流程元素集合 * @return 结束节点(未找到开始节点,返回null) */ public static EndEvent getEndEvent(Collection flowElements) { for (FlowElement flowElement : flowElements) { if (flowElement instanceof EndEvent) { return (EndEvent) flowElement; } } return null; } public static UserTask getUserTaskByKey(BpmnModel model, String taskKey) { Process process = model.getMainProcess(); FlowElement flowElement = process.getFlowElement(taskKey); if (flowElement instanceof UserTask) { return (UserTask) flowElement; } return null; } /** * 获取流程元素信息 * * @param model bpmnModel对象 * @param flowElementId 元素ID * @return 元素信息 */ public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) { Process process = model.getMainProcess(); return process.getFlowElement(flowElementId); } /** * 获取元素表单Key(限开始节点和用户节点可用) * * @param flowElement 元素 * @return 表单Key */ public static String getFormKey(FlowElement flowElement) { if (flowElement != null) { if (flowElement instanceof StartEvent) { return ((StartEvent) flowElement).getFormKey(); } else if (flowElement instanceof UserTask) { return ((UserTask) flowElement).getFormKey(); } } return null; } /** * 获取开始节点属性值 * @param model bpmnModel对象 * @param name 属性名 * @return 属性值 */ public static String getStartEventAttributeValue(BpmnModel model, String name) { StartEvent startEvent = getStartEvent(model); return getElementAttributeValue(startEvent, name); } /** * 获取结束节点属性值 * @param model bpmnModel对象 * @param name 属性名 * @return 属性值 */ public static String getEndEventAttributeValue(BpmnModel model, String name) { EndEvent endEvent = getEndEvent(model); return getElementAttributeValue(endEvent, name); } /** * 获取用户任务节点属性值 * @param model bpmnModel对象 * @param taskKey 任务Key * @param name 属性名 * @return 属性值 */ public static String getUserTaskAttributeValue(BpmnModel model, String taskKey, String name) { UserTask userTask = getUserTaskByKey(model, taskKey); return getElementAttributeValue(userTask, name); } /** * 获取元素属性值 * @param baseElement 流程元素 * @param name 属性名 * @return 属性值 */ public static String getElementAttributeValue(BaseElement baseElement, String name) { if (baseElement != null) { List attributes = baseElement.getAttributes().get(name); if (attributes != null && !attributes.isEmpty()) { attributes.iterator().next().getValue(); Iterator attrIterator = attributes.iterator(); if(attrIterator.hasNext()) { ExtensionAttribute attribute = attrIterator.next(); return attribute.getValue(); } } } return null; } public static boolean isMultiInstance(BpmnModel model, String taskKey) { UserTask userTask = getUserTaskByKey(model, taskKey); if (ObjectUtil.isNotNull(userTask)) { return userTask.hasMultiInstanceLoopCharacteristics(); } return false; } /** * 获取所有用户任务节点 * * @param model bpmnModel对象 * @return 用户任务节点列表 */ public static Collection getAllUserTaskEvent(BpmnModel model) { Process process = model.getMainProcess(); Collection flowElements = process.getFlowElements(); return getAllUserTaskEvent(flowElements, null); } /** * 获取所有用户任务节点 * @param flowElements 流程元素集合 * @param allElements 所有流程元素集合 * @return 用户任务节点列表 */ public static Collection getAllUserTaskEvent(Collection flowElements, Collection 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 source 起始节点 * @return 结果 */ public static List findNextUserTasks(FlowElement source) { return findNextUserTasks(source, null, null); } /** * 查找起始节点下一个用户任务列表列表 * @param source 起始节点 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 * @param userTaskList 用户任务列表 * @return 结果 */ public static List findNextUserTasks(FlowElement source, Set hasSequenceFlow, List userTaskList) { hasSequenceFlow = Optional.ofNullable(hasSequenceFlow).orElse(new HashSet<>()); userTaskList = Optional.ofNullable(userTaskList).orElse(new ArrayList<>()); // 获取出口连线 List sequenceFlows = getElementOutgoingFlows(source); if (!sequenceFlows.isEmpty()) { for (SequenceFlow sequenceFlow : sequenceFlows) { // 如果发现连线重复,说明循环了,跳过这个循环 if (hasSequenceFlow.contains(sequenceFlow.getId())) { continue; } // 添加已经走过的连线 hasSequenceFlow.add(sequenceFlow.getId()); FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement(); if (targetFlowElement instanceof UserTask) { // 若节点为用户任务,加入到结果列表中 userTaskList.add((UserTask) targetFlowElement); } else { // 若节点非用户任务,继续递归查找下一个节点 findNextUserTasks(targetFlowElement, hasSequenceFlow, userTaskList); } } } return userTaskList; } /** * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行 * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况 * @param source 起始节点 * @param target 目标节点 * @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复 * @return 结果 */ public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set visitedElements) { visitedElements = visitedElements == null ? new HashSet<>() : visitedElements; if (source instanceof StartEvent && isInEventSubprocess(source)) { return false; } // 根据类型,获取入口连线 List sequenceFlows = getElementIncomingFlows(source); if (sequenceFlows != null && sequenceFlows.size() > 0) { // 循环找到目标元素 for (SequenceFlow sequenceFlow: sequenceFlows) { // 如果发现连线重复,说明循环了,跳过这个循环 if (visitedElements.contains(sequenceFlow.getId())) { continue; } // 添加已经走过的连线 visitedElements.add(sequenceFlow.getId()); FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement(); // 这条线路存在目标节点,这条线路完成,进入下个线路 if (target.getId().equals(sourceFlowElement.getId())) { continue; } // 如果目标节点为并行网关,则不继续 if (sourceFlowElement instanceof ParallelGateway) { return false; } // 否则就继续迭代 boolean isSequential = isSequentialReachable(sourceFlowElement, target, visitedElements); if (!isSequential) { return false; } } } return true; } protected static boolean isInEventSubprocess(FlowElement flowElement) { FlowElementsContainer flowElementsContainer = flowElement.getParentContainer(); while (flowElementsContainer != null) { if (flowElementsContainer instanceof EventSubProcess) { return true; } if (flowElementsContainer instanceof FlowElement) { flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer(); } else { flowElementsContainer = null; } } return false; } }