package org.dromara.workflow.utils; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.workflow.domain.vo.MultiInstanceVo; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.Process; import org.flowable.editor.language.json.converter.BpmnJsonConverter; import org.flowable.engine.ProcessEngine; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.rmi.ServerException; import java.util.*; import java.util.stream.Collectors; /** * 模型工具 * * @author may */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ModelUtils { private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); public static BpmnModel xmlToBpmnModel(String xml) throws IOException { if (xml == null) { throw new ServerException("xml不能为空"); } try { InputStream inputStream = new ByteArrayInputStream(StrUtil.utf8Bytes(xml)); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLStreamReader reader = factory.createXMLStreamReader(inputStream); return new BpmnXMLConverter().convertToBpmnModel(reader); } catch (XMLStreamException e) { throw new ServerException(e.getMessage()); } } /** * bpmnModel转为xml * * @param jsonBytes json */ public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException { if (jsonBytes == null) { return new byte[0]; } // 1. json字节码转成 BpmnModel 对象 ObjectMapper objectMapper = JsonUtils.getObjectMapper(); JsonNode jsonNode = objectMapper.readTree(jsonBytes); BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode); if (bpmnModel.getProcesses().isEmpty()) { return new byte[0]; } // 2.将bpmnModel转为xml return new BpmnXMLConverter().convertToXML(bpmnModel); } /** * xml转为bpmnModel * * @param xmlBytes xml */ public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException { ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes); XMLInputFactory xif = XMLInputFactory.newInstance(); XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream); return new BpmnXMLConverter().convertToBpmnModel(xtr); } /** * 校验模型 * * @param bpmnModel bpmn模型 */ public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException { Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); checkBpmnNode(flowElements, false); List subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList()); if (!CollUtil.isEmpty(subProcessList)) { for (SubProcess subProcess : subProcessList) { Collection subProcessFlowElements = subProcess.getFlowElements(); checkBpmnNode(subProcessFlowElements, true); } } List multiInstanceVoList = new ArrayList<>(); for (FlowElement flowElement : flowElements) { if (flowElement instanceof UserTask && ObjectUtil.isNotEmpty(((UserTask) flowElement).getLoopCharacteristics()) && StringUtils.isNotBlank(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem())) { MultiInstanceVo multiInstanceVo = new MultiInstanceVo(); multiInstanceVo.setAssigneeList(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem()); multiInstanceVoList.add(multiInstanceVo); } } if (CollectionUtil.isNotEmpty(multiInstanceVoList) && multiInstanceVoList.size() > 1) { Map> assigneeListGroup = StreamUtils.groupByKey(multiInstanceVoList, MultiInstanceVo::getAssigneeList); for (Map.Entry> entry : assigneeListGroup.entrySet()) { List value = entry.getValue(); if (CollectionUtil.isNotEmpty(value) && value.size() > 1) { String key = entry.getKey(); throw new ServerException("会签人员集合【" + key + "】重复,请重新设置集合KEY"); } } } } /** * 校验bpmn节点是否合法 * * @param flowElements 节点集合 * @param subtask 是否子流程 */ private static void checkBpmnNode(Collection flowElements, boolean subtask) throws ServerException { if (CollUtil.isEmpty(flowElements)) { throw new ServerException(subtask ? "子流程必须存在节点" : "必须存在节点!"); } List startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); if (CollUtil.isEmpty(startEventList)) { throw new ServerException(subtask ? "子流程必须存在开始节点" : "必须存在开始节点!"); } if (startEventList.size() > 1) { throw new ServerException(subtask ? "子流程只能存在一个开始节点" : "只能存在一个开始节点!"); } StartEvent startEvent = startEventList.get(0); List outgoingFlows = startEvent.getOutgoingFlows(); if (CollUtil.isEmpty(outgoingFlows)) { throw new ServerException(subtask ? "子流程流程节点为空,请至少设计一条主线流程!" : "流程节点为空,请至少设计一条主线流程!"); } FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); if (!(targetFlowElement instanceof UserTask) && !subtask) { throw new ServerException("开始节点后第一个节点必须是用户任务!"); } //开始节点后第一个节点申请人节点 if ((targetFlowElement instanceof UserTask) && !subtask) { UserTask userTask = (UserTask) targetFlowElement; if (StringUtils.isBlank(userTask.getFormKey())) { throw new ServerException("申请人节点必须选择表单!"); } } List endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList()); if (CollUtil.isEmpty(endEventList)) { throw new ServerException(subtask ? "子流程必须存在结束节点!" : "必须存在结束节点!"); } } /** * 获取流程全部用户节点 * * @param processDefinitionId 流程定义id */ public static List getUserTaskFlowElements(String processDefinitionId) { BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); List list = new ArrayList<>(); List processes = bpmnModel.getProcesses(); Collection flowElements = processes.get(0).getFlowElements(); buildUserTaskFlowElements(flowElements, list); return list; } /** * 递归获取所有节点 * * @param flowElements 节点信息 * @param list 集合 */ private static void buildUserTaskFlowElements(Collection flowElements, List list) { for (FlowElement flowElement : flowElements) { if (flowElement instanceof SubProcess) { Collection subFlowElements = ((SubProcess) flowElement).getFlowElements(); buildUserTaskFlowElements(subFlowElements, list); } else if (flowElement instanceof UserTask) { list.add((UserTask) flowElement); } } } /** * 获取流程全部节点 * * @param processDefinitionId 流程定义id */ public static List getFlowElements(String processDefinitionId) { BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); List list = new ArrayList<>(); List processes = bpmnModel.getProcesses(); Collection flowElements = processes.get(0).getFlowElements(); buildFlowElements(flowElements, list); return list; } /** * 递归获取所有节点 * * @param flowElements 节点信息 * @param list 集合 */ private static void buildFlowElements(Collection flowElements, List list) { for (FlowElement flowElement : flowElements) { list.add(flowElement); if (flowElement instanceof SubProcess) { Collection subFlowElements = ((SubProcess) flowElement).getFlowElements(); buildFlowElements(subFlowElements, list); } } } /** * 获取全部扩展信息 * * @param processDefinitionId 流程定义id */ public static Map> getExtensionElements(String processDefinitionId) { Map> map = new HashMap<>(); List flowElements = getFlowElements(processDefinitionId); for (FlowElement flowElement : flowElements) { if (flowElement instanceof UserTask && CollUtil.isNotEmpty(flowElement.getExtensionElements())) { map.putAll(flowElement.getExtensionElements()); } } return map; } /** * 获取某个节点的扩展信息 * * @param processDefinitionId 流程定义id * @param flowElementId 节点id */ public static Map> getExtensionElement(String processDefinitionId, String flowElementId) { BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); Process process = bpmnModel.getMainProcess(); FlowElement flowElement = process.getFlowElement(flowElementId); return flowElement.getExtensionElements(); } /** * 判断当前节点是否为用户任务 * * @param processDefinitionId 流程定义id * @param taskDefinitionKey 流程定义id */ public static boolean isUserTask(String processDefinitionId, String taskDefinitionKey) { BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); return flowNode instanceof UserTask; } /** * 获取申请人节点 * * @param processDefinitionId 流程定义id * @return 结果 */ public static UserTask getApplyUserTask(String processDefinitionId) { BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); List startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); StartEvent startEvent = startEventList.get(0); List outgoingFlows = startEvent.getOutgoingFlows(); FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); return (UserTask) targetFlowElement; } }