From f0c964ea43afd99c941fa5c3fbe299ab3d665606 Mon Sep 17 00:00:00 2001 From: asp_ly Date: Sat, 14 Dec 2024 21:58:26 +0800 Subject: [PATCH] 1 --- .../workflow/delegate/ShellTaskDelegate.java | 99 ++-- .../workflow/enums/BpmnNodeTypeEnums.java | 86 +++- .../backend/workflow/enums/NodeTypeEnums.java | 7 + .../backend/workflow/event/ShellLogEvent.java | 4 + .../workflow/handler/BpmnNodeHandler.java | 44 -- .../handler/impl/ShellTaskHandler.java | 132 ----- .../workflow/parser/BpmnNodeConfigParser.java | 76 --- .../service/IWorkflowDefinitionService.java | 2 +- .../impl/WorkflowDefinitionServiceImpl.java | 73 +-- .../backend/workflow/util/BpmnConverter.java | 415 ++++++---------- .../util/WorkflowDefinitionGraph.java | 461 +++++++++--------- 11 files changed, 528 insertions(+), 871 deletions(-) delete mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/BpmnNodeHandler.java delete mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/impl/ShellTaskHandler.java delete mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/parser/BpmnNodeConfigParser.java diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java index d51cbb75..e3c6e79a 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java @@ -26,75 +26,62 @@ public class ShellTaskDelegate implements JavaDelegate { @Resource private ApplicationEventPublisher eventPublisher; - + @Resource private RuntimeService runtimeService; - + @Resource private ManagementService managementService; private Expression script; + private Expression workDir; + private Expression env; // 用于存储实时输出的Map private static final Map outputMap = new ConcurrentHashMap<>(); + private static final Map errorMap = new ConcurrentHashMap<>(); - private void processInputStream(InputStream inputStream, String processInstanceId, NodeLogTypeEnums logType) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { - String line; - while ((line = reader.readLine()) != null) { - // 发布日志事件 - eventPublisher.publishEvent(new ShellLogEvent(processInstanceId, line, logType)); - - // 同时保存到StringBuilder中 - if (logType == NodeLogTypeEnums.STDOUT) { - StringBuilder output = outputMap.get(processInstanceId); - synchronized (output) { - output.append(line).append("\n"); - } - log.info("Shell output: {}", line); - } else { - StringBuilder error = errorMap.get(processInstanceId); - synchronized (error) { - error.append(line).append("\n"); - } - log.error("Shell error: {}", line); - } - } - } catch (IOException e) { - log.error("Error reading process output", e); - } - } @Override public void execute(DelegateExecution execution) { + log.info("ShellTaskDelegate开始执行, processInstanceId={}, executionId={}", + execution.getProcessInstanceId(), execution.getId()); + // 从字段注入中获取值 String scriptValue = script != null ? script.getValue(execution).toString() : null; String workDirValue = workDir != null ? workDir.getValue(execution).toString() : null; @SuppressWarnings("unchecked") Map envValue = env != null ? (Map) env.getValue(execution) : null; + log.info("字段注入的值: script={}, workDir={}, env={}", scriptValue, workDirValue, envValue); + // 如果流程变量中有值,优先使用流程变量 if (execution.hasVariable("script")) { scriptValue = (String) execution.getVariable("script"); + log.info("从流程变量获取到script={}", scriptValue); } if (execution.hasVariable("workDir")) { workDirValue = (String) execution.getVariable("workDir"); + log.info("从流程变量获取到workDir={}", workDirValue); } if (execution.hasVariable("env")) { @SuppressWarnings("unchecked") Map envFromVar = (Map) execution.getVariable("env"); envValue = envFromVar; + log.info("从流程变量获取到env={}", envValue); } if (scriptValue == null) { + log.error("脚本内容为空,执行失败"); handleFailure(execution, "Script is required but not provided"); return; } try { + log.info("准备执行脚本: {}", scriptValue); // 使用processInstanceId而不是executionId String processInstanceId = execution.getProcessInstanceId(); outputMap.put(processInstanceId, new StringBuilder()); @@ -102,7 +89,7 @@ public class ShellTaskDelegate implements JavaDelegate { // 创建进程构建器 ProcessBuilder processBuilder = new ProcessBuilder(); - + // 根据操作系统选择合适的shell String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win")) { @@ -137,7 +124,7 @@ public class ShellTaskDelegate implements JavaDelegate { } // 执行命令 - log.info("Executing shell script: {}", scriptValue); + log.info("执行shell脚本: {}", scriptValue); Process process = processBuilder.start(); // 使用BufferedReader实时读取输出 @@ -148,11 +135,11 @@ public class ShellTaskDelegate implements JavaDelegate { ExecutorService executorService = Executors.newFixedThreadPool(2); // 处理标准输出 - Future outputFuture = executorService.submit(() -> + Future outputFuture = executorService.submit(() -> processInputStream(process.getInputStream(), processInstanceId, NodeLogTypeEnums.STDOUT)); - + // 处理错误输出 - Future errorFuture = executorService.submit(() -> + Future errorFuture = executorService.submit(() -> processInputStream(process.getErrorStream(), processInstanceId, NodeLogTypeEnums.STDERR)); // 等待进程完成 @@ -168,7 +155,7 @@ public class ShellTaskDelegate implements JavaDelegate { // 设置最终结果 StringBuilder finalOutput = outputMap.get(processInstanceId); StringBuilder finalError = errorMap.get(processInstanceId); - + execution.setVariable("shellOutput", finalOutput.toString()); execution.setVariable("shellError", finalError.toString()); execution.setVariable("shellExitCode", exitCode); @@ -178,28 +165,56 @@ public class ShellTaskDelegate implements JavaDelegate { errorMap.remove(processInstanceId); if (exitCode != 0) { - log.error("Shell script execution failed with exit code: {}", exitCode); - log.error("Error output: {}", finalError); - handleFailure(execution, "Shell script execution failed with exit code: " + exitCode); + log.error("Shell脚本执行失败,退出码: {}", exitCode); + log.error("错误输出: {}", finalError); + handleFailure(execution, "Shell脚本执行失败,退出码: " + exitCode); return; } - log.info("Shell script executed successfully"); - log.debug("Script output: {}", finalOutput); + log.info("Shell脚本执行成功"); + log.debug("脚本输出: {}", finalOutput); } catch (Exception e) { - log.error("Shell script execution failed", e); - handleFailure(execution, "Shell script execution failed: " + e.getMessage()); + log.error("Shell脚本执行失败", e); + handleFailure(execution, "Shell脚本执行失败: " + e.getMessage()); } } + private void processInputStream(InputStream inputStream, String processInstanceId, NodeLogTypeEnums logType) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = reader.readLine()) != null) { + // 发布日志事件 + eventPublisher.publishEvent(new ShellLogEvent(processInstanceId, line, logType)); + + // 同时保存到StringBuilder中 + if (logType == NodeLogTypeEnums.STDOUT) { + StringBuilder output = outputMap.get(processInstanceId); + synchronized (output) { + output.append(line).append("\n"); + } + log.info("Shell output: {}", line); + } else { + StringBuilder error = errorMap.get(processInstanceId); + synchronized (error) { + error.append(line).append("\n"); + } + log.error("Shell error: {}", line); + } + } + } catch (IOException e) { + log.error("Error reading process output", e); + } + } + + private void handleFailure(DelegateExecution execution, String errorMessage) { String processInstanceId = execution.getProcessInstanceId(); try { // 直接终止流程实例 runtimeService.deleteProcessInstance(processInstanceId, errorMessage); } catch (Exception e) { - log.error("Error while handling shell task failure for process instance: {}", processInstanceId, e); + log.error("处理Shell任务失败时出现错误,流程实例: {}", processInstanceId, e); } } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/BpmnNodeTypeEnums.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/BpmnNodeTypeEnums.java index ff49f508..211443e5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/BpmnNodeTypeEnums.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/BpmnNodeTypeEnums.java @@ -1,33 +1,79 @@ package com.qqchen.deploy.backend.workflow.enums; import lombok.Getter; +import org.flowable.bpmn.model.EndEvent; +import org.flowable.bpmn.model.ExclusiveGateway; +import org.flowable.bpmn.model.ScriptTask; +import org.flowable.bpmn.model.ServiceTask; +import org.flowable.bpmn.model.StartEvent; +import org.flowable.bpmn.model.UserTask; /** * BPMN节点类型枚举 */ @Getter public enum BpmnNodeTypeEnums { - START("start", "startEvent"), - END("end", "endEvent"), - USER_TASK("userTask", "userTask"), - SERVICE_TASK("serviceTask", "serviceTask"), - SHELL_TASK("shellTask", "serviceTask"), - EXCLUSIVE_GATEWAY("exclusiveGateway", "exclusiveGateway"); - - private final String shape; + + START_EVENT("startEvent", StartEvent.class), + + END_EVENT("endEvent", EndEvent.class), + + USER_TASK("userTask", UserTask.class), + + SERVICE_TASK("serviceTask", ServiceTask.class), + + SCRIPT_TASK("scriptTask", ScriptTask.class), + + EXCLUSIVE_GATEWAY("exclusiveGateway", ExclusiveGateway.class); + private final String bpmnType; - - BpmnNodeTypeEnums(String shape, String bpmnType) { - this.shape = shape; + + private final Object instance; + + BpmnNodeTypeEnums(String bpmnType, Object instance) { this.bpmnType = bpmnType; + this.instance = instance; } - - public static BpmnNodeTypeEnums fromShape(String shape) { - for (BpmnNodeTypeEnums type : values()) { - if (type.getShape().equals(shape)) { - return type; - } - } - return null; - } + + + /** + * Flowable 主要的节点类型包括: + * + * 事件类型: + * StartEvent (开始事件) + * EndEvent (结束事件) + * TimerStartEvent (定时开始事件) + * ErrorStartEvent (错误开始事件) + * MessageStartEvent (消息开始事件) + * SignalStartEvent (信号开始事件) + * IntermediateCatchEvent (中间捕获事件) + * IntermediateThrowEvent (中间抛出事件) + * 任务类型: + * UserTask (用户任务) + * ServiceTask (服务任务) + * ScriptTask (脚本任务) + * MailTask (邮件任务) + * ManualTask (手动任务) + * ReceiveTask (接收任务) + * BusinessRuleTask (业务规则任务) + * CallActivity (调用活动) + * 网关类型: + * ExclusiveGateway (排他网关) + * ParallelGateway (并行网关) + * InclusiveGateway (包容网关) + * EventBasedGateway (事件网关) + * ComplexGateway (复杂网关) + * 子流程: + * SubProcess (子流程) + * EventSubProcess (事件子流程) + * Transaction (事务子流程) + * 边界事件: + * BoundaryEvent (边界事件) + * ErrorBoundaryEvent (错误边界事件) + * TimerBoundaryEvent (定时边界事件) + * SignalBoundaryEvent (信号边界事件) + * 连线: + * SequenceFlow (顺序流) + * MessageFlow (消息流) + */ } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeTypeEnums.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeTypeEnums.java index 21c1fc4e..9b19033b 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeTypeEnums.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeTypeEnums.java @@ -23,6 +23,7 @@ public enum NodeTypeEnums { START_EVENT( "START_EVENT", // 节点类型编码 "开始节点", // 节点显示名称 + BpmnNodeTypeEnums.START_EVENT, NodeCategoryEnums.EVENT, "工作流的起点", // 节点简要描述 new WorkflowNodeGraph() // UI配置 @@ -42,6 +43,7 @@ public enum NodeTypeEnums { END_EVENT( "END_EVENT", "结束节点", + BpmnNodeTypeEnums.END_EVENT, NodeCategoryEnums.EVENT, "工作流的终点", new WorkflowNodeGraph() @@ -53,6 +55,7 @@ public enum NodeTypeEnums { SCRIPT_TASK( "SCRIPT_TASK", "脚本任务", + BpmnNodeTypeEnums.SERVICE_TASK, NodeCategoryEnums.TASK, "脚本执行任务", new WorkflowNodeGraph() @@ -200,6 +203,8 @@ public enum NodeTypeEnums { private final String name; // 节点显示名称 + private final BpmnNodeTypeEnums bpmnType; // 对应的BPMN类型 + private final NodeCategoryEnums category; //分类 private final String description; // 节点详细描述 @@ -209,11 +214,13 @@ public enum NodeTypeEnums { NodeTypeEnums( String code, String name, + BpmnNodeTypeEnums bpmnType, NodeCategoryEnums category, String description, WorkflowNodeGraph uiConfig) { this.code = code; this.name = name; + this.bpmnType = bpmnType; this.category = category; this.description = description; this.uiConfig = uiConfig; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/event/ShellLogEvent.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/event/ShellLogEvent.java index 77519a95..5f4b72cd 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/event/ShellLogEvent.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/event/ShellLogEvent.java @@ -10,7 +10,11 @@ import lombok.Getter; @Getter @AllArgsConstructor public class ShellLogEvent { + private String processInstanceId; + private String logMessage; + private NodeLogTypeEnums logType; + } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/BpmnNodeHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/BpmnNodeHandler.java deleted file mode 100644 index 7722e654..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/BpmnNodeHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.qqchen.deploy.backend.workflow.handler; - -import com.fasterxml.jackson.databind.JsonNode; -import com.qqchen.deploy.backend.workflow.enums.BpmnNodeTypeEnums; -import com.qqchen.deploy.backend.workflow.model.BpmnNodeConfig; -import org.flowable.bpmn.model.FlowElement; - -/** - * BPMN节点处理器接口 - * - * @param 流程元素类型 - */ -public interface BpmnNodeHandler { - /** - * 处理节点数据 - * - * @param nodeData JSON节点数据 - * @param element 流程元素 - * @param config 节点配置 - */ - void handle(JsonNode nodeData, T element, BpmnNodeConfig config); - - /** - * 创建流程元素 - * - * @param config 节点配置 - * @return 流程元素 - */ - T createElement(BpmnNodeConfig config); - - /** - * 获取处理器类型 - * - * @return 节点类型 - */ - BpmnNodeTypeEnums getType(); - - /** - * 获取处理的元素类型 - * - * @return 元素类型Class - */ - Class getElementType(); -} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/impl/ShellTaskHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/impl/ShellTaskHandler.java deleted file mode 100644 index da1449c8..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/handler/impl/ShellTaskHandler.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.qqchen.deploy.backend.workflow.handler.impl; - -import com.fasterxml.jackson.databind.JsonNode; -import com.qqchen.deploy.backend.workflow.annotation.BpmnNode; -import com.qqchen.deploy.backend.workflow.enums.BpmnNodeTypeEnums; -import com.qqchen.deploy.backend.workflow.handler.BpmnNodeHandler; -import com.qqchen.deploy.backend.workflow.model.BpmnNodeConfig; -import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.FieldExtension; -import org.flowable.bpmn.model.ServiceTask; -import org.springframework.stereotype.Component; - -import java.util.Map; -import java.util.Optional; - -/** - * Shell任务处理器 - */ -@Slf4j -@Component -@BpmnNode( - type = "shellTask", - name = "Shell脚本", - async = true, - requiredFields = {"script", "workDir"}, - delegateExpression = "${shellTaskDelegate}" -) -public class ShellTaskHandler implements BpmnNodeHandler { - - @Override - public void handle(JsonNode nodeData, ServiceTask element, BpmnNodeConfig config) { - // 设置任务委托表达式 - setupTaskDelegate(element); - - // 设置任务属性 - setupTaskProperties(element, config); - - // 验证必需字段 - validateRequiredFields(element, config); - - // 处理扩展字段 - handleExtensionFields(element, config); - } - - @Override - public ServiceTask createElement(BpmnNodeConfig config) { - ServiceTask task = new ServiceTask(); - task.setId(config.getId()); - task.setName(config.getName()); - return task; - } - - @Override - public BpmnNodeTypeEnums getType() { - return BpmnNodeTypeEnums.SHELL_TASK; - } - - @Override - public Class getElementType() { - return ServiceTask.class; - } - - /** - * 设置任务委托表达式 - */ - private void setupTaskDelegate(ServiceTask element) { - BpmnNode annotation = this.getClass().getAnnotation(BpmnNode.class); - element.setImplementationType("delegateExpression"); - element.setImplementation(annotation.delegateExpression()); - element.setAsynchronous(annotation.async()); - } - - /** - * 设置任务属性 - */ - private void setupTaskProperties(ServiceTask element, BpmnNodeConfig config) { - Map properties = config.getProperties(); - properties.forEach((key, value) -> { - if (value != null) { - addFieldExtension(element, key, value.toString()); - } - }); - } - - /** - * 验证必需字段 - */ - private void validateRequiredFields(ServiceTask element, BpmnNodeConfig config) { - BpmnNode annotation = this.getClass().getAnnotation(BpmnNode.class); - for (String requiredField : annotation.requiredFields()) { - boolean fieldExists = element.getFieldExtensions().stream() - .anyMatch(field -> field.getFieldName().equals(requiredField)); - if (!fieldExists) { - log.warn("Required field '{}' is missing for shell task '{}'", - requiredField, element.getId()); - } - } - } - - /** - * 处理扩展字段 - */ - private void handleExtensionFields(ServiceTask element, BpmnNodeConfig config) { - Map extensions = config.getExtensions(); - extensions.forEach((key, value) -> { - if (value != null) { - addFieldExtension(element, key, value); - } - }); - } - - /** - * 添加字段扩展 - */ - private void addFieldExtension(ServiceTask serviceTask, String name, String value) { - // 检查字段是否已存在 - Optional existingField = serviceTask.getFieldExtensions().stream() - .filter(field -> field.getFieldName().equals(name)) - .findFirst(); - - if (existingField.isPresent()) { - // 更新现有字段 - existingField.get().setStringValue(value); - } else { - // 添加新字段 - FieldExtension field = new FieldExtension(); - field.setFieldName(name); - field.setStringValue(value); - serviceTask.getFieldExtensions().add(field); - } - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/parser/BpmnNodeConfigParser.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/parser/BpmnNodeConfigParser.java deleted file mode 100644 index dd0aacd3..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/parser/BpmnNodeConfigParser.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.qqchen.deploy.backend.workflow.parser; - -import com.fasterxml.jackson.databind.JsonNode; -import com.qqchen.deploy.backend.workflow.enums.BpmnNodeTypeEnums; -import com.qqchen.deploy.backend.workflow.model.BpmnNodeConfig; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.Map; - -/** - * BPMN节点配置解析器 - */ -@Component -public class BpmnNodeConfigParser { - - /** - * 解析节点配置 - * - * @param node JSON节点数据 - * @return 节点配置 - */ - public BpmnNodeConfig parse(JsonNode node) { - BpmnNodeConfig config = new BpmnNodeConfig(); - config.setId(node.path("id").asText()); - config.setName(node.path("data").path("label").asText()); - config.setType(BpmnNodeTypeEnums.fromShape(node.path("shape").asText())); - - // 解析属性 - JsonNode data = node.path("data"); - - // 处理通用属性 - Map properties = new HashMap<>(); - if (data.has("properties")) { - data.path("properties").fields() - .forEachRemaining(entry -> properties.put( - entry.getKey(), - parseValue(entry.getValue()) - )); - } - - // 处理特定任务属性 - if (data.has("serviceTask") && data.path("serviceTask").has("fields")) { - JsonNode fields = data.path("serviceTask").path("fields"); - fields.fields().forEachRemaining(entry -> - properties.put(entry.getKey(), parseValue(entry.getValue())) - ); - } - - config.setProperties(properties); - - // 解析扩展字段 - Map extensions = new HashMap<>(); - if (data.has("extensions")) { - data.path("extensions").fields() - .forEachRemaining(entry -> extensions.put( - entry.getKey(), - entry.getValue().asText() - )); - } - config.setExtensions(extensions); - - return config; - } - - /** - * 解析JSON值 - */ - private Object parseValue(JsonNode value) { - if (value.isTextual()) return value.asText(); - if (value.isNumber()) return value.numberValue(); - if (value.isBoolean()) return value.asBoolean(); - if (value.isObject() || value.isArray()) return value.toString(); - return null; - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/IWorkflowDefinitionService.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/IWorkflowDefinitionService.java index f18ed7d8..df2cf22f 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/IWorkflowDefinitionService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/IWorkflowDefinitionService.java @@ -24,7 +24,7 @@ public interface IWorkflowDefinitionService extends IBaseService new RuntimeException("Workflow definition not found: " + dto.getId())); - - // 转换为DTO - dto.setFlowVersion(definition.getFlowVersion()); - return dto; - + log.info("Successfully deployed workflow: {}", workflowDefinition.getName()); } catch (Exception e) { - log.error("Failed to deploy workflow: {}", dto.getName(), e); + log.error("Failed to deploy workflow: {}", workflowDefinition.getName(), e); throw new RuntimeException("Failed to deploy workflow", e); } } @@ -299,6 +260,20 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl { + if (a.getStartTime() == null && b.getStartTime() == null) { + return 0; + } + if (a.getStartTime() == null) { + return 1; + } + if (b.getStartTime() == null) { + return -1; + } + return a.getStartTime().compareTo(b.getStartTime()); + }); + executionDTO.setStages(stages); return executionDTO; } catch (Exception e) { @@ -368,7 +343,11 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl new RuntimeException("Workflow definition not found: " + workflowDefinitionId)); + WorkflowDefinitionGraph graph = definition.getGraph(); + definition.setBpmnXml(bpmnConverter.convertToXml(graph, definition.getKey())); definition.setStatus(WorkflowStatusEnums.PUBLISHED); + this.deployWorkflow(definition); + definition.setFlowVersion(1); workflowDefinitionRepository.save(definition); log.info("Successfully published workflow definition: {}", workflowDefinitionId); } 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 63246359..181c8f1e 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,302 +1,163 @@ package com.qqchen.deploy.backend.workflow.util; import com.qqchen.deploy.backend.workflow.dto.graph.*; +import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.BpmnAutoLayout; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.Process; import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * BPMN 模型转换工具 * @author cascade * @date 2024-12-11 */ +@Slf4j @Component public class BpmnConverter { - private final BpmnXMLConverter bpmnXmlConverter = new BpmnXMLConverter(); - /** - * 将工作流图转换为BPMN XML - * @param graph 工作流图数据 - * @param processKey 流程标识 - * @return BPMN XML字符串 + * 将工作流定义图转换为Flowable XML + * + * @param graph 工作流定义图 + * @param processKey 流程定义的唯一标识 + * @return Flowable XML字符串 + * @throws RuntimeException 当转换失败时抛出 */ public String convertToXml(WorkflowDefinitionGraph graph, String processKey) { - BpmnModel bpmnModel = convertToBpmnModel(graph, processKey); - byte[] xmlBytes = bpmnXmlConverter.convertToXML(bpmnModel); - return new String(xmlBytes, StandardCharsets.UTF_8); - } - - /** - * 将工作流图转换为BPMN模型 - * @param graph 工作流图数据 - * @param processKey 流程标识 - * @return BPMN模型 - */ - public BpmnModel convertToBpmnModel(WorkflowDefinitionGraph graph, String processKey) { - BpmnModel bpmnModel = new BpmnModel(); - Process process = new Process(); - - // 设置流程属性 - process.setId(processKey); -// if (graph.getProperties() != null) { -// Map properties = graph.getProperties(); -// process.setName(properties.get("name") != null ? properties.get("name").toString() : null); -// process.setDocumentation(properties.get("description") != null ? properties.get("description").toString() : null); -// } - - // 转换节点 -// for (WorkflowDefinitionNode node : graph.getNodes()) { -// FlowElement element = convertNode(node); -// if (element != null) { -// process.addFlowElement(element); -// } -// } -// -// // 转换边 -// for (WorkflowDefinitionEdge edge : graph.getEdges()) { -// SequenceFlow flow = convertEdge(edge); -// if (flow != null) { -// process.addFlowElement(flow); -// } -// } - - bpmnModel.addProcess(process); - return bpmnModel; - } - - /** - * 将工作流图转换为BPMN模型 - * @param graph 工作流图数据 - * @return BPMN模型 - */ - public BpmnModel convertToBpmnModel(WorkflowDefinitionGraph graph) { - String processKey = null; -// if (graph.getProperties() != null) { -// Object key = graph.getProperties().get("key"); -// processKey = key != null ? key.toString() : null; -// } -// if (processKey == null) { -// processKey = "process_" + System.currentTimeMillis(); -// } - return convertToBpmnModel(graph, processKey); - } - - /** - * 转换节点 - * @param node 工作流节点 - * @return 流程元素 - */ - private FlowElement convertNode(WorkflowDefinitionNode node) { - if (node.getType() == null) { - return null; - } - - switch (node.getType()) { - case START_EVENT: - return createStartEvent(node); - case END_EVENT: - return createEndEvent(node); -// case SERVICE_TASK: -// return createServiceTask(node); -// case USER_TASK: -// return createUserTask(node); -// case SCRIPT_TASK: -// return createScriptTask(node); -// case EXCLUSIVE_GATEWAY: -// return createExclusiveGateway(node); -// case PARALLEL_GATEWAY: -// return createParallelGateway(node); -// case SUBPROCESS: -// return createSubProcess(node); -// case CALL_ACTIVITY: -// return createCallActivity(node); - default: - return null; - } - } - - /** - * 创建开始事件 - * @param node 节点数据 - * @return 开始事件 - */ - private StartEvent createStartEvent(WorkflowDefinitionNode node) { - StartEvent startEvent = new StartEvent(); - startEvent.setId(node.getId()); - startEvent.setName(node.getName()); - return startEvent; - } - - /** - * 创建结束事件 - * @param node 节点数据 - * @return 结束事件 - */ - private EndEvent createEndEvent(WorkflowDefinitionNode node) { - EndEvent endEvent = new EndEvent(); - endEvent.setId(node.getId()); - endEvent.setName(node.getName()); - return endEvent; - } - - /** - * 创建服务任务 - * @param node 节点数据 - * @return 服务任务 - */ - private ServiceTask createServiceTask(WorkflowDefinitionNode node) { - ServiceTask serviceTask = new ServiceTask(); - serviceTask.setId(node.getId()); - serviceTask.setName(node.getName()); - - if (node.getConfig() != null) { -// WorkflowDefinitionEdgeNodeConfig config = node.getConfig(); -// serviceTask.setImplementation(config.getImplementation()); -// if (config.getFields() != null) { -// config.getFields().forEach((key, value) -> { -// FieldExtension field = new FieldExtension(); -// field.setFieldName(key); -// field.setStringValue(value != null ? value.toString() : null); -// serviceTask.getFieldExtensions().add(field); -// }); -// } - } - - return serviceTask; - } - - /** - * 创建用户任务 - * @param node 节点数据 - * @return 用户任务 - */ - private UserTask createUserTask(WorkflowDefinitionNode node) { - UserTask userTask = new UserTask(); - userTask.setId(node.getId()); - userTask.setName(node.getName()); - - if (node.getConfig() != null) { -// NodeConfig config = node.getConfig(); -// userTask.setAssignee(config.getAssignee()); -// userTask.setCandidateUsers(config.getCandidateUsers()); -// userTask.setCandidateGroups(config.getCandidateGroups()); -// userTask.setDueDate(config.getDueDate()); -// userTask.setPriority(config.getPriority() != null ? config.getPriority().toString() : null); -// userTask.setFormKey(config.getFormKey()); -// userTask.setSkipExpression(config.getSkipExpression()); - } - - return userTask; - } - - /** - * 创建脚本任务 - * @param node 节点数据 - * @return 脚本任务 - */ - private ScriptTask createScriptTask(WorkflowDefinitionNode node) { - ScriptTask scriptTask = new ScriptTask(); - scriptTask.setId(node.getId()); - scriptTask.setName(node.getName()); - - if (node.getConfig() != null) { -// NodeConfig config = node.getConfig(); -// scriptTask.setScriptFormat(config.getImplementation()); -// if (config.getFields() != null && config.getFields().containsKey("script")) { -// scriptTask.setScript(config.getFields().get("script").toString()); -// } - } - - return scriptTask; - } - - /** - * 创建排他网关 - * @param node 节点数据 - * @return 排他网关 - */ - private ExclusiveGateway createExclusiveGateway(WorkflowDefinitionNode node) { - ExclusiveGateway gateway = new ExclusiveGateway(); - gateway.setId(node.getId()); - gateway.setName(node.getName()); - return gateway; - } - - /** - * 创建并行网关 - * @param node 节点数据 - * @return 并行网关 - */ - private ParallelGateway createParallelGateway(WorkflowDefinitionNode node) { - ParallelGateway gateway = new ParallelGateway(); - gateway.setId(node.getId()); - gateway.setName(node.getName()); - return gateway; - } - - /** - * 创建子流程 - * @param node 节点数据 - * @return 子流程 - */ - private SubProcess createSubProcess(WorkflowDefinitionNode node) { - SubProcess subProcess = new SubProcess(); - subProcess.setId(node.getId()); - subProcess.setName(node.getName()); - return subProcess; - } - - /** - * 创建调用活动 - * @param node 节点数据 - * @return 调用活动 - */ - private CallActivity createCallActivity(WorkflowDefinitionNode node) { - CallActivity callActivity = new CallActivity(); - callActivity.setId(node.getId()); - callActivity.setName(node.getName()); - - if (node.getConfig() != null) { -// WorkflowDefinitionEdgeNodeConfig config = node.getConfig(); -// callActivity.setCalledElement(config.getImplementation()); -// if (config.getFields() != null) { -// config.getFields().forEach((key, value) -> { -// IOParameter parameter = new IOParameter(); -// parameter.setSource(key); -// parameter.setTarget(value != null ? value.toString() : null); -// callActivity.getInParameters().add(parameter); -// }); -// } - } - - return callActivity; - } - - /** - * 转换边 - * @param edge 工作流边 - * @return 序列流 - */ - private SequenceFlow convertEdge(WorkflowDefinitionEdge edge) { - SequenceFlow flow = new SequenceFlow(); - flow.setId(edge.getId()); - flow.setName(edge.getName()); -// flow.setSourceRef(edge.getSource()); -// flow.setTargetRef(edge.getTarget()); - - if (edge.getConfig() != null) { - WorkflowDefinitionEdgeConfig config = edge.getConfig(); - if ("sequence".equals(config.getType())) { - if (config.getCondition() != null) { - ((SequenceFlow) flow).setConditionExpression(config.getCondition()); - } + try { + log.debug("开始转换工作流定义为XML, processKey: {}", processKey); + + // 创建BPMN模型 + BpmnModel bpmnModel = new BpmnModel(); + Process process = new Process(); + // 确保processKey符合NCName规则 + String validProcessKey = processKey.replaceAll("[^a-zA-Z0-9-_.]", "_"); + process.setId(validProcessKey); + process.setName(processKey); // 保持原始processKey作为显示名称 + process.setExecutable(true); + bpmnModel.addProcess(process); + + // 创建节点ID到规范化ID的映射 + Map idMapping = new HashMap<>(); + + // 转换节点 + for (WorkflowDefinitionNode node : graph.getNodes()) { + log.debug("转换节点: {}, 类型: {}", node.getName(), node.getCode()); + + // 通过NodeTypeEnums获取对应的BpmnTypeEnums中定义的实例类型 + @SuppressWarnings("unchecked") + Class instanceClass = (Class) NodeTypeEnums.valueOf(node.getCode()) + .getBpmnType() + .getInstance(); + + // 创建节点实例 + FlowElement element = instanceClass.getDeclaredConstructor().newInstance(); + String validId = sanitizeId(node.getId()); + idMapping.put(node.getId(), validId); + element.setId(validId); + element.setName(node.getName()); + + // 设置节点特定属性 + configureFlowElement(element, node); + + process.addFlowElement(element); } + + // 转换连线 + for (WorkflowDefinitionEdge edge : graph.getEdges()) { + log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo()); + + SequenceFlow flow = new SequenceFlow(); + flow.setId("flow_" + edge.getId().replaceAll("[^a-zA-Z0-9-_.]", "_")); + flow.setName(edge.getName()); + flow.setSourceRef(idMapping.get(edge.getFrom())); + flow.setTargetRef(idMapping.get(edge.getTo())); + process.addFlowElement(flow); + } + + // 自动布局 + new BpmnAutoLayout(bpmnModel).execute(); + + // 转换为XML + BpmnXMLConverter converter = new BpmnXMLConverter(); + byte[] bytes = converter.convertToXML(bpmnModel); + String xml = new String(bytes, StandardCharsets.UTF_8); + + log.debug("工作流定义转换完成"); + return xml; + + } catch (Exception e) { + log.error("转换工作流定义为XML失败", e); + throw new RuntimeException("转换工作流定义为XML失败: " + e.getMessage(), e); + } + } + + private String sanitizeId(String id) { + return "node_" + id.replaceAll("[^a-zA-Z0-9-_.]", "_"); + } + + /** + * 配置流程节点的特定属性 + * @param element 流程节点元素 + * @param node 工作流节点定义 + */ + private void configureFlowElement(FlowElement element, WorkflowDefinitionNode node) { + if (element instanceof ServiceTask) { + ServiceTask serviceTask = (ServiceTask) element; + // 设置委托表达式 + String delegate = (String) node.getConfig().get("delegate"); + serviceTask.setImplementationType("delegateExpression"); + serviceTask.setImplementation(delegate); + serviceTask.setAsynchronous(true); // 设置为异步执行 + + // 添加字段注入和扩展属性 + List fieldExtensions = new ArrayList<>(); + Map> extensionElements = new HashMap<>(); + + // 遍历所有配置项 + node.getConfig().forEach((key, value) -> { + if (value != null && !"delegate".equals(key)) { + // 添加为字段注入 + FieldExtension fieldExtension = new FieldExtension(); + fieldExtension.setFieldName(key); + fieldExtension.setStringValue(String.valueOf(value)); + fieldExtensions.add(fieldExtension); + + // 同时也添加为扩展属性(用于兼容性和可视化) + addExtensionElement(extensionElements, key, String.valueOf(value)); + } + }); + + serviceTask.setFieldExtensions(fieldExtensions); + serviceTask.setExtensionElements(extensionElements); + } + // 后续可以添加其他类型的节点配置 + // else if (element instanceof UserTask) { ... } + } + + /** + * 添加扩展属性 + */ + private void addExtensionElement(Map> extensionElements, String name, String value) { + if (value != null && !value.trim().isEmpty()) { + ExtensionElement extensionElement = new ExtensionElement(); + extensionElement.setName(name); + extensionElement.setNamespace("http://flowable.org/bpmn"); + extensionElement.setNamespacePrefix("flowable"); + + // 直接设置文本值,让Flowable自己处理XML转义 + extensionElement.setElementText(value); + + extensionElements.computeIfAbsent(name, k -> new ArrayList<>()).add(extensionElement); } - - return flow; } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/WorkflowDefinitionGraph.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/WorkflowDefinitionGraph.java index 78d621a6..cae2490a 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/WorkflowDefinitionGraph.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/WorkflowDefinitionGraph.java @@ -1,232 +1,229 @@ -package com.qqchen.deploy.backend.workflow.util; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.qqchen.deploy.backend.workflow.dto.graph.*; -import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 工作流定义图形生成工具类 - * 用于生成示例工作流定义,包括: - * 1. 简单工作流:开始 -> 脚本任务 -> 结束 - * 2. 复杂工作流:开始 -> 脚本任务A -> 脚本任务B -> 结束 - */ -@Data -@Slf4j -public class WorkflowDefinitionGraph { - private static final ObjectMapper mapper = new ObjectMapper(); - - /** - * 节点列表 - */ - private List nodes; - - /** - * 边列表 - */ - private List edges; - - /** - * 生成简单工作流 - * 开始 -> 脚本任务 -> 结束 - */ - public static WorkflowDefinitionGraph generateSimpleWorkflow() { - WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph(); - List nodes = new ArrayList<>(); - List edges = new ArrayList<>(); - - // 开始节点 - WorkflowDefinitionNode startNode = createNode( - "startEvent1", - NodeTypeEnums.START_EVENT, - "开始", - 100, 100, - createNodeConfig("开始节点", "启动流程") - ); - nodes.add(startNode); - - // 脚本任务节点 - Map scriptConfig = createNodeConfig("脚本任务", "执行一个简单的Shell脚本"); - scriptConfig.put("script", "echo 'Hello World'"); - scriptConfig.put("language", "shell"); - - WorkflowDefinitionNode scriptNode = createNode( - "scriptTask1", - NodeTypeEnums.SCRIPT_TASK, - "执行脚本", - 300, 100, - scriptConfig - ); - nodes.add(scriptNode); - - // 结束节点 - WorkflowDefinitionNode endNode = createNode( - "endEvent1", - NodeTypeEnums.END_EVENT, - "结束", - 500, 100, - createNodeConfig("结束节点", "流程结束") - ); - nodes.add(endNode); - - // 添加连线 - edges.add(createEdge("flow1", "startEvent1", "scriptTask1", "开始到脚本")); - edges.add(createEdge("flow2", "scriptTask1", "endEvent1", "脚本到结束")); - - graph.setNodes(nodes); - graph.setEdges(edges); - return graph; - } - - /** - * 生成复杂工作流 - * 开始 -> 脚本任务A -> 脚本任务B -> 结束 - */ - public static WorkflowDefinitionGraph generateComplexWorkflow() { - WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph(); - List nodes = new ArrayList<>(); - List edges = new ArrayList<>(); - - // 开始节点 - WorkflowDefinitionNode startNode = createNode( - "startEvent1", - NodeTypeEnums.START_EVENT, - "开始", - 100, 100, - createNodeConfig("开始节点", "启动流程") - ); - nodes.add(startNode); - - // 脚本任务A - Map scriptConfigA = createNodeConfig("脚本任务A", "数据处理"); - scriptConfigA.put("script", "process_data.sh"); - scriptConfigA.put("language", "shell"); - - WorkflowDefinitionNode scriptNodeA = createNode( - "scriptTask1", - NodeTypeEnums.SCRIPT_TASK, - "数据处理", - 300, 100, - scriptConfigA - ); - nodes.add(scriptNodeA); - - // 脚本任务B - Map scriptConfigB = createNodeConfig("脚本任务B", "生成报告"); - scriptConfigB.put("script", "generate_report.sh"); - scriptConfigB.put("language", "shell"); - - WorkflowDefinitionNode scriptNodeB = createNode( - "scriptTask2", - NodeTypeEnums.SCRIPT_TASK, - "生成报告", - 500, 100, - scriptConfigB - ); - nodes.add(scriptNodeB); - - // 结束节点 - WorkflowDefinitionNode endNode = createNode( - "endEvent1", - NodeTypeEnums.END_EVENT, - "结束", - 700, 100, - createNodeConfig("结束节点", "流程结束") - ); - nodes.add(endNode); - - // 添加连线 - edges.add(createEdge("flow1", "startEvent1", "scriptTask1", "开始到处理")); - edges.add(createEdge("flow2", "scriptTask1", "scriptTask2", "处理到报告")); - edges.add(createEdge("flow3", "scriptTask2", "endEvent1", "报告到结束")); - - graph.setNodes(nodes); - graph.setEdges(edges); - return graph; - } - - /** - * 创建节点 - */ - private static WorkflowDefinitionNode createNode(String id, NodeTypeEnums type, String name, int x, int y, Map config) { - WorkflowDefinitionNode node = new WorkflowDefinitionNode(); - node.setId(id); - node.setCode(type.getCode()); - node.setType(type); - node.setName(name); - node.setConfig(config); - - // 从枚举的uiConfig中获取配置并创建新的图形配置 - WorkflowNodeGraph originalConfig = type.getUiConfig(); - WorkflowNodeGraph nodeGraph = new WorkflowNodeGraph() - .setShape(originalConfig.getShape()) - .setSize(originalConfig.getSize().getWidth(), originalConfig.getSize().getHeight()) - .setStyle(originalConfig.getStyle().getFill(), - originalConfig.getStyle().getStroke(), - originalConfig.getStyle().getIcon()) - .configPorts(originalConfig.getPorts().getTypes()) - .setPosition(x, y); - - node.setGraph(nodeGraph); - return node; - } - - /** - * 创建节点配置 - */ - private static Map createNodeConfig(String name, String description) { - Map config = new HashMap<>(); - config.put("name", name); - config.put("description", description); - return config; - } - - /** - * 创建连线 - */ - private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name) { - return createEdge(id, from, to, name, null); - } - - /** - * 创建带条件的连线 - */ - private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name, String condition) { - WorkflowDefinitionEdge edge = new WorkflowDefinitionEdge(); - edge.setId(id); - edge.setFrom(from); - edge.setTo(to); - edge.setName(name); - - // 设置边配置 - WorkflowDefinitionEdgeConfig config = new WorkflowDefinitionEdgeConfig(); - config.setType("sequence"); - if (condition != null) { - config.setCondition(condition); - config.setConditionExpression(condition); - } - edge.setConfig(config); - - return edge; - } - - public static void main(String[] args) { - try { - System.out.println("=== 简单工作流 ==="); - System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateSimpleWorkflow())); - System.out.println("\n=== 复杂工作流 ==="); - System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateComplexWorkflow())); - } catch (Exception e) { - log.error("生成工作流定义失败", e); - } - } -} +//package com.qqchen.deploy.backend.workflow.util; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.qqchen.deploy.backend.workflow.dto.graph.*; +//import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums; +//import lombok.Data; +//import lombok.extern.slf4j.Slf4j; +// +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +// +///** +// * 工作流定义图形生成工具类 +// * 用于生成示例工作流定义,包括: +// * 1. 简单工作流:开始 -> 脚本任务 -> 结束 +// * 2. 复杂工作流:开始 -> 脚本任务A -> 脚本任务B -> 结束 +// */ +//@Data +//@Slf4j +//public class WorkflowDefinitionGraph { +// private static final ObjectMapper mapper = new ObjectMapper(); +// +// /** +// * 节点列表 +// */ +// private List nodes; +// +// /** +// * 边列表 +// */ +// private List edges; +// +// /** +// * 生成简单工作流 +// * 开始 -> 脚本任务 -> 结束 +// */ +// public static WorkflowDefinitionGraph generateSimpleWorkflow() { +// WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph(); +// List nodes = new ArrayList<>(); +// List edges = new ArrayList<>(); +// +// // 开始节点 +// WorkflowDefinitionNode startNode = createNode( +// "startEvent1", +// NodeTypeEnums.START_EVENT, +// "开始", +// 100, 100, +// createNodeConfig("开始节点", "启动流程") +// ); +// nodes.add(startNode); +// +// // 脚本任务节点 +// Map scriptConfig = createNodeConfig("脚本任务", "执行一个简单的Shell脚本"); +// scriptConfig.put("script", "echo 'Hello World'"); +// scriptConfig.put("language", "shell"); +// +// WorkflowDefinitionNode scriptNode = createNode( +// "scriptTask1", +// NodeTypeEnums.SCRIPT_TASK, +// "执行脚本", +// 300, 100, +// scriptConfig +// ); +// nodes.add(scriptNode); +// +// // 结束节点 +// WorkflowDefinitionNode endNode = createNode( +// "endEvent1", +// NodeTypeEnums.END_EVENT, +// "结束", +// 500, 100, +// createNodeConfig("结束节点", "流程结束") +// ); +// nodes.add(endNode); +// +// // 添加连线 +// edges.add(createEdge("flow1", "startEvent1", "scriptTask1", "开始到脚本")); +// edges.add(createEdge("flow2", "scriptTask1", "endEvent1", "脚本到结束")); +// +// graph.setNodes(nodes); +// graph.setEdges(edges); +// return graph; +// } +// +// /** +// * 生成复杂工作流 +// * 开始 -> 脚本任务A -> 脚本任务B -> 结束 +// */ +// public static WorkflowDefinitionGraph generateComplexWorkflow() { +// WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph(); +// List nodes = new ArrayList<>(); +// List edges = new ArrayList<>(); +// +// // 开始节点 +// WorkflowDefinitionNode startNode = createNode( +// "startEvent1", +// NodeTypeEnums.START_EVENT, +// "开始", +// 100, 100, +// createNodeConfig("开始节点", "启动流程") +// ); +// nodes.add(startNode); +// +// // 脚本任务A +// Map scriptConfigA = createNodeConfig("脚本任务A", "数据处理"); +// scriptConfigA.put("script", "process_data.sh"); +// scriptConfigA.put("language", "shell"); +// +// WorkflowDefinitionNode scriptNodeA = createNode( +// "scriptTask1", +// NodeTypeEnums.SCRIPT_TASK, +// "数据处理", +// 300, 100, +// scriptConfigA +// ); +// nodes.add(scriptNodeA); +// +// // 脚本任务B +// Map scriptConfigB = createNodeConfig("脚本任务B", "生成报告"); +// scriptConfigB.put("script", "generate_report.sh"); +// scriptConfigB.put("language", "shell"); +// +// WorkflowDefinitionNode scriptNodeB = createNode( +// "scriptTask2", +// NodeTypeEnums.SCRIPT_TASK, +// "生成报告", +// 500, 100, +// scriptConfigB +// ); +// nodes.add(scriptNodeB); +// +// // 结束节点 +// WorkflowDefinitionNode endNode = createNode( +// "endEvent1", +// NodeTypeEnums.END_EVENT, +// "结束", +// 700, 100, +// createNodeConfig("结束节点", "流程结束") +// ); +// nodes.add(endNode); +// +// // 添加连线 +// edges.add(createEdge("flow1", "startEvent1", "scriptTask1", "开始到处理")); +// edges.add(createEdge("flow2", "scriptTask1", "scriptTask2", "处理到报告")); +// edges.add(createEdge("flow3", "scriptTask2", "endEvent1", "报告到结束")); +// +// graph.setNodes(nodes); +// graph.setEdges(edges); +// return graph; +// } +// +// /** +// * 创建节点 +// */ +// private static WorkflowDefinitionNode createNode(String id, NodeTypeEnums type, String name, int x, int y, Map config) { +// WorkflowDefinitionNode node = new WorkflowDefinitionNode(); +// node.setId(id); +// node.setCode(type.getCode()); +// node.setType(type); +// node.setName(name); +// node.setConfig(config); +// +// // 从枚举的uiConfig中获取配置并创建新的图形配置 +// WorkflowNodeGraph originalConfig = type.getUiConfig(); +// WorkflowNodeGraph nodeGraph = new WorkflowNodeGraph() +// .setShape(originalConfig.getShape()) +// .setSize(originalConfig.getSize().getWidth(), originalConfig.getSize().getHeight()) +// .setStyle(originalConfig.getStyle().getFill(), +// originalConfig.getStyle().getStroke(), +// originalConfig.getStyle().getIcon()) +// .configPorts(originalConfig.getPorts().getTypes()) +// .setPosition(x, y); +// +// node.setGraph(nodeGraph); +// return node; +// } +// +// /** +// * 创建节点配置 +// */ +// private static Map createNodeConfig(String name, String description) { +// Map config = new HashMap<>(); +// config.put("name", name); +// config.put("description", description); +// return config; +// } +// +// /** +// * 创建连线 +// */ +// private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name) { +// return createEdge(id, from, to, name, null); +// } +// +// /** +// * 创建带条件的连线 +// */ +// private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name, String condition) { +// WorkflowDefinitionEdge edge = new WorkflowDefinitionEdge(); +// edge.setId(id); +// edge.setFrom(from); +// edge.setTo(to); +// edge.setName(name); +// +// // 设置边配置 +// WorkflowDefinitionEdgeConfig config = new WorkflowDefinitionEdgeConfig(); +// config.setType("sequence"); +// if (condition != null) { +// config.setCondition(condition); +// config.setConditionExpression(condition); +// } +// edge.setConfig(config); +// +// return edge; +// } +// +// public static void main(String[] args) { +// try { +// System.out.println("=== 简单工作流 ==="); +// System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateSimpleWorkflow())); +// System.out.println("\n=== 复杂工作流 ==="); +// System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateComplexWorkflow())); +// } catch (Exception e) { +// log.error("生成工作流定义失败", e); +// } +// } +//}