From 9c8065dd53eeecc705a9d387b8213a299ab324ce Mon Sep 17 00:00:00 2001 From: dengqichen Date: Wed, 22 Oct 2025 20:25:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=80=9A=E7=9F=A5=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/workflow/util/BpmnConverter.java | 186 +++++++++++------- 1 file changed, 111 insertions(+), 75 deletions(-) diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java index 3bec0dae..049543b5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java @@ -1,6 +1,7 @@ package com.qqchen.deploy.backend.workflow.util; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants; import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphEdge; import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph; @@ -31,6 +32,8 @@ import java.util.Map; @Component public class BpmnConverter { + private final ObjectMapper objectMapper = new ObjectMapper(); + /** * 将工作流定义图转换为Flowable XML * @@ -144,8 +147,8 @@ public class BpmnConverter { element.setName(node.getNodeName()); } - // 步骤2.5:配置节点的特定属性 - configureFlowElement(element, node, process); + // 步骤2.5:配置节点的特定属性(传递原始节点ID和sanitized ID) + configureFlowElement(element, node, process, validId); // 步骤2.6:将节点添加到流程中 process.addFlowElement(element); @@ -155,8 +158,15 @@ public class BpmnConverter { } } + /** + * 直接使用前端生成的节点 ID + * 前端已经生成了符合 NCName 规范的 ID(如 sid_265bc83e_9e7f_4acf_bd25_cf04c868a5da) + * + * @param id 前端生成的节点 ID + * @return 节点 ID(直接返回) + */ private String sanitizeId(String id) { - return "NODE_" + id.replaceAll("[^a-zA-Z0-9-_.]", "_"); + return id; } /** @@ -165,14 +175,15 @@ public class BpmnConverter { * @param element 流程节点元素 * @param node 工作流节点定义 * @param process 当前流程 + * @param validId sanitized 后的节点 ID */ - private void configureFlowElement(FlowElement element, WorkflowDefinitionGraphNode node, Process process) { + private void configureFlowElement(FlowElement element, WorkflowDefinitionGraphNode node, Process process, String validId) { // 步骤1:配置执行监听器 Map> extensionElements = configureExecutionListeners(element); // 步骤2:根据节点类型进行特定配置 if (element instanceof ServiceTask) { - configureServiceTask((ServiceTask) element, node, process, extensionElements); + configureServiceTask((ServiceTask) element, node, process, extensionElements, validId); } else { element.setExtensionElements(extensionElements); } @@ -229,20 +240,50 @@ public class BpmnConverter { * @param node 工作流节点定义 * @param process 当前流程 * @param extensionElements 扩展元素 + * @param validId sanitized 后的节点 ID */ - private void configureServiceTask(ServiceTask serviceTask, WorkflowDefinitionGraphNode node, Process process, Map> extensionElements) { -// if (node.getPanelVariables() != null && node.getPanelVariables().has("delegate")) { -// String delegate = node.getPanelVariables().get("delegate").asText(); -// serviceTask.setImplementationType("delegateExpression"); -// serviceTask.setImplementation(delegate); -// } + private void configureServiceTask(ServiceTask serviceTask, WorkflowDefinitionGraphNode node, Process process, Map> extensionElements, String validId) { + // ✅ 设置 delegateExpression(根据节点类型映射) + String delegateExpression = getDelegateExpression(node.getNodeCode()); + if (delegateExpression != null && !delegateExpression.isEmpty()) { + serviceTask.setImplementationType("delegateExpression"); + serviceTask.setImplementation(delegateExpression); + } - addExecutionVariables(extensionElements, node); + // ✅ 添加 field 字段(nodeId, configs, inputMapping) + addExecutionVariables(extensionElements, node, validId); + + // ✅ 添加重试策略 addRetryStrategy(extensionElements); + serviceTask.setExtensionElements(extensionElements); addErrorBoundaryEventHandler(process, serviceTask); } + /** + * 根据节点类型获取对应的 delegateExpression + * + * @param nodeCode 节点类型编码 + * @return delegateExpression 字符串 + */ + private String getDelegateExpression(String nodeCode) { + switch (nodeCode) { + case "JENKINS_BUILD": + return "${jenkinsBuildDelegate}"; + case "NOTIFICATION": + return "${notificationDelegate}"; + case "SCRIPT_NODE": + return "${shellDelegate}"; + case "APPROVAL_NODE": + return "${approvalDelegate}"; + case "DEPLOY_NODE": + return "${deployDelegate}"; + default: + log.warn("未知的节点类型: {}, 将不设置 delegateExpression", nodeCode); + return null; + } + } + /** * 创建扩展属性 * @@ -258,65 +299,67 @@ public class BpmnConverter { } /** - * 添加执行实例级变量 + * 添加执行实例级变量(field 字段) * * @param extensionElements 扩展元素 * @param node 工作流节点定义 + * @param validId sanitized 后的节点 ID */ - private void addExecutionVariables(Map> extensionElements, WorkflowDefinitionGraphNode node) { - // 添加panelVariables变量 -// if (node.getPanelVariables() != null) { -// ExtensionElement fieldElement = new ExtensionElement(); -// fieldElement.setName("field"); -// fieldElement.setNamespace("http://flowable.org/bpmn"); -// fieldElement.setNamespacePrefix("flowable"); -// -// // 创建field的子元素string -// ExtensionElement stringElement = new ExtensionElement(); -// stringElement.setName("string"); -// stringElement.setNamespace("http://flowable.org/bpmn"); -// stringElement.setNamespacePrefix("flowable"); -// // 直接设置JSON内容,不使用CDATA -// stringElement.setElementText(node.getPanelVariables().toString()); -// -// // 设置field的name属性 -// Map> fieldAttributes = new HashMap<>(); -// fieldAttributes.put("name", Collections.singletonList(createAttribute("name", "panelVariables"))); -// fieldElement.setAttributes(fieldAttributes); -// -// // 添加string子元素到field -// fieldElement.addChildElement(stringElement); -// -// // 添加field到extensionElements -// extensionElements.computeIfAbsent("field", k -> new ArrayList<>()).add(fieldElement); -// } + private void addExecutionVariables(Map> extensionElements, WorkflowDefinitionGraphNode node, String validId) { + try { + // ✅ 1. 添加 nodeId field + extensionElements.computeIfAbsent("field", k -> new ArrayList<>()) + .add(createFieldElement("nodeId", validId)); - // 添加localVariables变量 -// if (node.getLocalVariables() != null) { -// ExtensionElement fieldElement = new ExtensionElement(); -// fieldElement.setName("field"); -// fieldElement.setNamespace("http://flowable.org/bpmn"); -// fieldElement.setNamespacePrefix("flowable"); -// -// // 创建field的子元素string -// ExtensionElement stringElement = new ExtensionElement(); -// stringElement.setName("string"); -// stringElement.setNamespace("http://flowable.org/bpmn"); -// stringElement.setNamespacePrefix("flowable"); -// // 直接设置JSON内容,不使用CDATA -// stringElement.setElementText(node.getLocalVariables().toString()); -// -// // 设置field的name属性 -// Map> fieldAttributes = new HashMap<>(); -// fieldAttributes.put("name", Collections.singletonList(createAttribute("name", "localVariables"))); -// fieldElement.setAttributes(fieldAttributes); -// -// // 添加string子元素到field -// fieldElement.addChildElement(stringElement); -// -// // 添加field到extensionElements -// extensionElements.computeIfAbsent("field", k -> new ArrayList<>()).add(fieldElement); -// } + // ✅ 2. 添加 configs field + if (node.getConfigs() != null) { + String configsJson = objectMapper.writeValueAsString(node.getConfigs()); + extensionElements.computeIfAbsent("field", k -> new ArrayList<>()) + .add(createFieldElement("configs", configsJson)); + } + + // ✅ 3. 添加 inputMapping field + if (node.getInputMapping() != null) { + String inputMappingJson = objectMapper.writeValueAsString(node.getInputMapping()); + extensionElements.computeIfAbsent("field", k -> new ArrayList<>()) + .add(createFieldElement("inputMapping", inputMappingJson)); + } + } catch (Exception e) { + log.error("添加执行变量失败: {}", node.getNodeName(), e); + throw new RuntimeException("添加执行变量失败: " + e.getMessage(), e); + } + } + + /** + * 创建 field 扩展元素 + * + * @param fieldName 字段名 + * @param fieldValue 字段值 + * @return field 扩展元素 + */ + private ExtensionElement createFieldElement(String fieldName, String fieldValue) { + // 创建 field 元素 + ExtensionElement fieldElement = new ExtensionElement(); + fieldElement.setName("field"); + fieldElement.setNamespace("http://flowable.org/bpmn"); + fieldElement.setNamespacePrefix("flowable"); + + // 设置 field 的 name 属性 + Map> fieldAttributes = new HashMap<>(); + fieldAttributes.put("name", Collections.singletonList(createAttribute("name", fieldName))); + fieldElement.setAttributes(fieldAttributes); + + // 创建 string 子元素 + ExtensionElement stringElement = new ExtensionElement(); + stringElement.setName("string"); + stringElement.setNamespace("http://flowable.org/bpmn"); + stringElement.setNamespacePrefix("flowable"); + stringElement.setElementText(fieldValue); + + // 添加 string 子元素到 field + fieldElement.addChildElement(stringElement); + + return fieldElement; } /** @@ -494,8 +537,8 @@ public class BpmnConverter { log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo()); SequenceFlow flow = new SequenceFlow(); - String flowId = "FLOW_" + edge.getId().replaceAll("[^a-zA-Z0-9-_.]", "_"); - flow.setId(flowId); + // ✅ 直接使用前端生成的 edge ID(前端已经生成了 eid_ 开头的 ID) + flow.setId(edge.getId()); flow.setName(edge.getName()); flow.setSourceRef(idMapping.get(edge.getFrom())); flow.setTargetRef(idMapping.get(edge.getTo())); @@ -508,13 +551,6 @@ public class BpmnConverter { } } -// // 添加 take 事件监听器 -// Map> extensionElements = new HashMap<>(); -// List executionListeners = new ArrayList<>(); -// executionListeners.add(createExecutionListener("take", "${sequenceFlowTakeListener}")); -// extensionElements.put("executionListener", executionListeners); -// flow.setExtensionElements(extensionElements); - process.addFlowElement(flow); } }