flowable-devops/backend/src/main/java/com/flowable/devops/config/DataInitializer.java
dengqichen d840effe9e 提交
2025-10-13 14:04:05 +08:00

628 lines
21 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<NodeType> 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<NodeType> 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;
}
}