package com.flowable.devops.config; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.flowable.devops.entity.NodeType; import com.flowable.devops.service.NodeTypeService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.List; /** * 数据初始化组件 * * 在应用启动时加载默认节点类型和示例数据 */ @Slf4j @Component @Order(1) // 确保在其他初始化组件之前执行 public class DataInitializer implements CommandLineRunner { @Autowired private NodeTypeService nodeTypeService; @Value("${flowable-devops.node-types.load-defaults:true}") private boolean loadDefaultNodeTypes; private final ObjectMapper objectMapper = new ObjectMapper(); @Override public void run(String... args) throws Exception { log.info("开始数据初始化..."); if (loadDefaultNodeTypes) { initializeDefaultNodeTypes(); } log.info("数据初始化完成"); } /** * 初始化默认节点类型 */ private void initializeDefaultNodeTypes() { log.info("加载默认节点类型..."); try { List defaultNodeTypes = createDefaultNodeTypes(); for (NodeType nodeType : defaultNodeTypes) { try { // 检查节点类型是否已存在 try { nodeTypeService.getNodeType(nodeType.getId()); log.debug("节点类型已存在,跳过: {}", nodeType.getId()); continue; } catch (Exception e) { // 节点类型不存在,继续创建 } NodeType created = nodeTypeService.createNodeType(nodeType); log.info("创建默认节点类型: {} ({})", created.getName(), created.getId()); } catch (Exception e) { log.warn("创建默认节点类型失败: {} - {}", nodeType.getId(), e.getMessage()); } } // 刷新注册表 nodeTypeService.refreshRegistry(); log.info("默认节点类型加载完成,共 {} 个节点类型", defaultNodeTypes.size()); } catch (Exception e) { log.error("加载默认节点类型失败", e); } } /** * 创建默认节点类型列表 */ private List createDefaultNodeTypes() throws Exception { return List.of( // 1. 开始节点 createStartNodeType(), // 2. 结束节点 createEndNodeType(), // 3. 脚本任务节点 createScriptTaskNodeType(), // 4. HTTP请求节点 createHttpRequestNodeType(), // 5. 用户任务节点(审批节点) createUserTaskNodeType(), // 6. 条件分支节点 createExclusiveGatewayNodeType(), // 7. 并行分支节点 createParallelGatewayNodeType(), // 8. 数据转换节点 createDataTransformNodeType() ); } /** * 开始节点 */ private NodeType createStartNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("start"); nodeType.setName("开始"); nodeType.setDisplayName("开始"); nodeType.setDescription("工作流开始节点"); nodeType.setCategory(NodeType.NodeCategory.OTHER); nodeType.setIcon("play-circle"); nodeType.setImplementationClass("com.flowable.devops.workflow.node.StartNode"); nodeType.setEnabled(true); nodeType.setDisplayOrder(10); // 字段定义 - 开始节点通常不需要配置字段 String fieldsJson = "[]"; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "startTime": { "type": "string", "format": "date-time", "description": "开始时间" }, "initiator": { "type": "string", "description": "发起人" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } /** * 结束节点 */ private NodeType createEndNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("end"); nodeType.setName("结束"); nodeType.setDisplayName("结束"); nodeType.setDescription("工作流结束节点"); nodeType.setCategory(NodeType.NodeCategory.OTHER); nodeType.setIcon("stop-circle"); nodeType.setImplementationClass("com.flowable.devops.workflow.node.EndNode"); nodeType.setEnabled(true); nodeType.setDisplayOrder(20); // 字段定义 String fieldsJson = """ [ { "name": "result", "label": "结束结果", "type": "select", "required": false, "defaultValue": "completed", "options": [ {"label": "完成", "value": "completed"}, {"label": "取消", "value": "cancelled"}, {"label": "中止", "value": "aborted"} ] } ] """; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "endTime": { "type": "string", "format": "date-time", "description": "结束时间" }, "result": { "type": "string", "description": "执行结果" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } /** * 脚本任务节点 */ private NodeType createScriptTaskNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("script-task"); nodeType.setName("脚本任务"); nodeType.setDisplayName("脚本任务"); nodeType.setDescription("执行脚本代码的任务节点"); nodeType.setCategory(NodeType.NodeCategory.LOGIC); nodeType.setIcon("code"); nodeType.setImplementationClass("com.flowable.devops.workflow.node.ScriptTaskNode"); nodeType.setEnabled(true); nodeType.setDisplayOrder(100); // 字段定义 String fieldsJson = """ [ { "name": "script", "label": "脚本内容", "type": "textarea", "required": true, "placeholder": "输入要执行的脚本代码", "rows": 5 }, { "name": "language", "label": "脚本语言", "type": "select", "required": true, "defaultValue": "javascript", "options": [ {"label": "JavaScript", "value": "javascript"}, {"label": "Groovy", "value": "groovy"}, {"label": "Python", "value": "python"} ] }, { "name": "timeout", "label": "超时时间(秒)", "type": "number", "required": false, "defaultValue": 30, "min": 1, "max": 300 } ] """; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "result": { "type": "object", "description": "脚本执行结果" }, "executionTime": { "type": "number", "description": "执行耗时(毫秒)" }, "status": { "type": "string", "enum": ["success", "error"], "description": "执行状态" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } /** * HTTP请求节点 */ private NodeType createHttpRequestNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("http-request"); nodeType.setName("HTTP请求"); nodeType.setDescription("发送HTTP请求的任务节点"); nodeType.setCategory(NodeType.NodeCategory.API); nodeType.setIcon("globe"); nodeType.setEnabled(true); nodeType.setDisplayOrder(200); // 字段定义 String fieldsJson = """ [ { "name": "url", "label": "请求URL", "type": "text", "required": true, "placeholder": "http://example.com/api" }, { "name": "method", "label": "请求方法", "type": "select", "required": true, "defaultValue": "GET", "options": [ {"label": "GET", "value": "GET"}, {"label": "POST", "value": "POST"}, {"label": "PUT", "value": "PUT"}, {"label": "DELETE", "value": "DELETE"} ] }, { "name": "headers", "label": "请求头", "type": "keyvalue", "required": false, "description": "HTTP请求头" }, { "name": "body", "label": "请求体", "type": "textarea", "required": false, "placeholder": "JSON格式的请求体内容" }, { "name": "timeout", "label": "超时时间(秒)", "type": "number", "required": false, "defaultValue": 30 } ] """; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "status": { "type": "number", "description": "HTTP状态码" }, "headers": { "type": "object", "description": "响应头" }, "body": { "type": "object", "description": "响应体" }, "responseTime": { "type": "number", "description": "响应时间(毫秒)" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } /** * 用户任务节点(审批节点) */ private NodeType createUserTaskNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("user-task"); nodeType.setName("用户任务"); nodeType.setDescription("需要人工处理的审批任务节点"); nodeType.setCategory(NodeType.NodeCategory.OTHER); nodeType.setIcon("user-check"); nodeType.setEnabled(true); nodeType.setDisplayOrder(300); // 字段定义 String fieldsJson = """ [ { "name": "assignee", "label": "分配给", "type": "text", "required": false, "placeholder": "用户ID或表达式" }, { "name": "candidateUsers", "label": "候选用户", "type": "text", "required": false, "placeholder": "用户ID列表,逗号分隔" }, { "name": "candidateGroups", "label": "候选组", "type": "text", "required": false, "placeholder": "组ID列表,逗号分隔" }, { "name": "dueDate", "label": "截止时间", "type": "text", "required": false, "placeholder": "时间表达式或具体时间" }, { "name": "priority", "label": "优先级", "type": "number", "required": false, "defaultValue": 50, "min": 1, "max": 100 }, { "name": "formKey", "label": "表单Key", "type": "text", "required": false, "placeholder": "关联的表单标识" } ] """; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "approved": { "type": "boolean", "description": "是否通过审批" }, "approver": { "type": "string", "description": "审批人" }, "approvalTime": { "type": "string", "format": "date-time", "description": "审批时间" }, "comment": { "type": "string", "description": "审批意见" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } /** * 条件分支节点 */ private NodeType createExclusiveGatewayNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("exclusive-gateway"); nodeType.setName("条件分支"); nodeType.setDescription("基于条件的排他分支节点"); nodeType.setCategory(NodeType.NodeCategory.LOGIC); nodeType.setIcon("git-branch"); nodeType.setEnabled(true); nodeType.setDisplayOrder(400); // 字段定义 String fieldsJson = """ [ { "name": "name", "label": "分支名称", "type": "text", "required": false, "placeholder": "分支节点的名称" } ] """; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "selectedPath": { "type": "string", "description": "选择的分支路径" }, "evaluationTime": { "type": "number", "description": "条件评估耗时(毫秒)" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } /** * 并行分支节点 */ private NodeType createParallelGatewayNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("parallel-gateway"); nodeType.setName("并行分支"); nodeType.setDescription("并行执行多个分支的节点"); nodeType.setCategory(NodeType.NodeCategory.LOGIC); nodeType.setIcon("share"); nodeType.setEnabled(true); nodeType.setDisplayOrder(410); // 字段定义 String fieldsJson = """ [ { "name": "name", "label": "并行节点名称", "type": "text", "required": false, "placeholder": "并行节点的名称" } ] """; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "parallelPaths": { "type": "array", "items": { "type": "string" }, "description": "并行分支路径" }, "forkTime": { "type": "string", "format": "date-time", "description": "分支创建时间" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } /** * 数据转换节点 */ private NodeType createDataTransformNodeType() throws Exception { NodeType nodeType = new NodeType(); nodeType.setId("data-transform"); nodeType.setName("数据转换"); nodeType.setDescription("数据映射和转换节点"); nodeType.setCategory(NodeType.NodeCategory.TRANSFORM); nodeType.setIcon("refresh-cw"); nodeType.setEnabled(true); nodeType.setDisplayOrder(500); // 字段定义 String fieldsJson = """ [ { "name": "mappings", "label": "字段映射", "type": "keyvalue", "required": true, "description": "输入字段到输出字段的映射关系" }, { "name": "expression", "label": "转换表达式", "type": "textarea", "required": false, "placeholder": "JUEL表达式,用于复杂数据转换", "rows": 3 } ] """; nodeType.setFields(objectMapper.readTree(fieldsJson)); // 输出模式 String outputSchemaJson = """ { "type": "object", "properties": { "transformedData": { "type": "object", "description": "转换后的数据" }, "transformedFields": { "type": "array", "items": { "type": "string" }, "description": "被转换的字段列表" } } } """; nodeType.setOutputSchema(objectMapper.readTree(outputSchemaJson)); return nodeType; } }