From bfb7c7b6da56a49f2781ff23e481a83d010cede8 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Thu, 26 Dec 2024 18:05:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A7=E5=A3=B0=E9=81=93=E6=92=92=E6=97=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/DeployAppConfigApiController.java | 44 ++++ .../converter/DeployAppConfigConverter.java | 13 ++ .../deploy/dto/BuildConfigDefinedDTO.java | 27 +++ .../deploy/dto/DeployAppConfigDTO.java | 29 +++ .../variables/JenkinsBaseBuildVariables.java | 19 ++ .../dto/variables/JenkinsBuildVariables.java | 4 - .../variables/JenkinsJavaBuildVariables.java | 12 ++ .../JenkinsNodeJsBuildVariables.java | 11 + .../backend/deploy/enums/BuildTypeEnum.java | 69 ++++++- .../deploy/query/DeployAppConfigQuery.java | 29 +++ .../IDeployAppConfigRepository.java | 13 ++ .../service/IDeployAppConfigService.java | 23 +++ .../impl/DeployAppConfigServiceImpl.java | 56 +++++ .../WorkflowNodeDefinitionServiceImpl.java | 182 +--------------- .../workflow/util/GenerateSchemaUtils.java | 194 ++++++++++++++++++ .../db/migration/V1.0.1__init_data.sql | 2 + 16 files changed, 538 insertions(+), 189 deletions(-) create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployAppConfigApiController.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/DeployAppConfigConverter.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/BuildConfigDefinedDTO.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployAppConfigDTO.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBaseBuildVariables.java delete mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBuildVariables.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsJavaBuildVariables.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsNodeJsBuildVariables.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/query/DeployAppConfigQuery.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IDeployAppConfigRepository.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployAppConfigService.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployAppConfigServiceImpl.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/util/GenerateSchemaUtils.java diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployAppConfigApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployAppConfigApiController.java new file mode 100644 index 00000000..494664d8 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployAppConfigApiController.java @@ -0,0 +1,44 @@ +package com.qqchen.deploy.backend.deploy.api; + +import com.qqchen.deploy.backend.deploy.dto.BuildConfigDefinedDTO; +import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO; +import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig; +import com.qqchen.deploy.backend.deploy.query.DeployAppConfigQuery; +import com.qqchen.deploy.backend.deploy.service.IDeployAppConfigService; +import com.qqchen.deploy.backend.framework.api.Response; +import com.qqchen.deploy.backend.framework.controller.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 应用配置控制器 + */ +@Slf4j +@RestController +@RequestMapping("/api/v1/deploy-app-config") +@Tag(name = "应用配置管理", description = "应用配置管理相关接口") +public class DeployAppConfigApiController extends BaseController { + + + @Resource + private IDeployAppConfigService deployAppConfigService; + + @Operation(summary = "获取构建类型Schema定义") + @GetMapping("/defined") + public Response> defined() { + return Response.success(deployAppConfigService.defined()); + } + + @Override + protected void exportData(HttpServletResponse response, List data) { + + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/DeployAppConfigConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/DeployAppConfigConverter.java new file mode 100644 index 00000000..c8a1c507 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/DeployAppConfigConverter.java @@ -0,0 +1,13 @@ +package com.qqchen.deploy.backend.deploy.converter; + +import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO; +import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig; +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import org.mapstruct.Mapper; + +/** + * 应用配置转换器 + */ +@Mapper(config = BaseConverter.class) +public interface DeployAppConfigConverter extends BaseConverter { +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/BuildConfigDefinedDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/BuildConfigDefinedDTO.java new file mode 100644 index 00000000..d219f2b3 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/BuildConfigDefinedDTO.java @@ -0,0 +1,27 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.fasterxml.jackson.databind.JsonNode; +import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum; +import com.qqchen.deploy.backend.deploy.enums.DevelopmentLanguageTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "部署配置定义") +public class BuildConfigDefinedDTO { + + @Schema(description = "编码") + private String code; + + @Schema(description = "名称") + private String name; + + @Schema(description = "部署类型类型") + private BuildTypeEnum buildType; + + private DevelopmentLanguageTypeEnum languageType; + + @Schema(description = "JSON SCHEMA") + private JsonNode buildVariablesSchema; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployAppConfigDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployAppConfigDTO.java new file mode 100644 index 00000000..c8b429fb --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployAppConfigDTO.java @@ -0,0 +1,29 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.fasterxml.jackson.databind.JsonNode; +import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum; +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用配置DTO + */ +@Data +@Schema(description = "应用配置") +@EqualsAndHashCode(callSuper = true) +public class DeployAppConfigDTO extends BaseDTO { + + @Schema(description = "环境ID") + private Long environmentId; + + @Schema(description = "应用ID") + private Long applicationId; + + @Schema(description = "构建类型") + private BuildTypeEnum buildType; + + @Schema(description = "构建变量") + private JsonNode buildVariables; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBaseBuildVariables.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBaseBuildVariables.java new file mode 100644 index 00000000..5a67a86c --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBaseBuildVariables.java @@ -0,0 +1,19 @@ +package com.qqchen.deploy.backend.deploy.dto.variables; + +import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty; +import lombok.Data; + +/** + * Jenkins构建变量 + */ +@Data +public class JenkinsBaseBuildVariables { + + @SchemaProperty( + title = "分支名称", + description = "Git分支名称", + required = true + ) + private String branch; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBuildVariables.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBuildVariables.java deleted file mode 100644 index c362fe23..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsBuildVariables.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.qqchen.deploy.backend.deploy.dto.variables; - -public class JenkinsBuildVariables { -} diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsJavaBuildVariables.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsJavaBuildVariables.java new file mode 100644 index 00000000..a9bf8899 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsJavaBuildVariables.java @@ -0,0 +1,12 @@ +package com.qqchen.deploy.backend.deploy.dto.variables; + +import lombok.Data; + +/** + * Jenkins构建变量 + */ +@Data +public class JenkinsJavaBuildVariables extends JenkinsBaseBuildVariables { + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsNodeJsBuildVariables.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsNodeJsBuildVariables.java new file mode 100644 index 00000000..3ff1e066 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/variables/JenkinsNodeJsBuildVariables.java @@ -0,0 +1,11 @@ +package com.qqchen.deploy.backend.deploy.dto.variables; + +import lombok.Data; + +/** + * Jenkins构建变量 + */ +@Data +public class JenkinsNodeJsBuildVariables extends JenkinsBaseBuildVariables { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/BuildTypeEnum.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/BuildTypeEnum.java index 277086cd..8380dafa 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/BuildTypeEnum.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/BuildTypeEnum.java @@ -1,5 +1,7 @@ package com.qqchen.deploy.backend.deploy.enums; +import com.fasterxml.jackson.annotation.JsonValue; +import com.qqchen.deploy.backend.deploy.dto.variables.JenkinsJavaBuildVariables; import lombok.Getter; /** @@ -7,14 +9,71 @@ import lombok.Getter; */ @Getter public enum BuildTypeEnum { - - JENKINS("Jenkins构建"), - GITLAB_RUNNER("GitLab Runner构建"), - GITHUB_ACTION("GitHub Action构建"); + + JENKINS( + "JENKINS", + "Jenkins构建", + new DevelopmentLanguageTypeEnum[] { + DevelopmentLanguageTypeEnum.JAVA, + DevelopmentLanguageTypeEnum.NODE_JS, + DevelopmentLanguageTypeEnum.GO, + DevelopmentLanguageTypeEnum.PYTHON + }, + new Class[] { + JenkinsJavaBuildVariables.class, + null, + null, + null + }, + "Jenkins构建" + ), + GITLAB_RUNNER( + "GITLAB_RUNNER", + "GitLab Runner构建", + null, + null, + "GitLab Runner构建" + ), + GITHUB_ACTION( + "GITHUB_ACTION", + "GitHub Action构建", + null, + null, + "GitHub Action构建" + ); + + @JsonValue + private final String code; + + private final String name; + + private final DevelopmentLanguageTypeEnum[] supportedLanguages; + + private final Class[] buildVariables; private final String description; - BuildTypeEnum(String description) { + BuildTypeEnum(String code, String name, DevelopmentLanguageTypeEnum[] supportedLanguages, Class[] buildVariables, String description) { + this.code = code; + this.name = name; + this.supportedLanguages = supportedLanguages; + this.buildVariables = buildVariables; this.description = description; } + + /** + * 根据编码查找对应的枚举 + * + * @param code 构建类型编码 + * @return 对应的枚举实例 + * @throws IllegalArgumentException 当找不到对应的枚举值时抛出 + */ + public static BuildTypeEnum fromValue(String code) { + for (BuildTypeEnum type : values()) { + if (type.code.equals(code)) { + return type; + } + } + throw new IllegalArgumentException("Unknown BuildType code: " + code); + } } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/DeployAppConfigQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/DeployAppConfigQuery.java new file mode 100644 index 00000000..86a19742 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/DeployAppConfigQuery.java @@ -0,0 +1,29 @@ +package com.qqchen.deploy.backend.deploy.query; + +import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum; +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用配置查询对象 + */ +@Data +@Schema(description = "应用配置查询") +@EqualsAndHashCode(callSuper = true) +public class DeployAppConfigQuery extends BaseQuery { + + @Schema(description = "环境ID") + @QueryField(field = "environmentId") + private Long environmentId; + + @Schema(description = "应用ID") + @QueryField(field = "applicationId") + private Long applicationId; + + @Schema(description = "构建类型") + @QueryField(field = "buildType") + private BuildTypeEnum buildType; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IDeployAppConfigRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IDeployAppConfigRepository.java new file mode 100644 index 00000000..cf968950 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IDeployAppConfigRepository.java @@ -0,0 +1,13 @@ +package com.qqchen.deploy.backend.deploy.repository; + +import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig; +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; +import org.springframework.stereotype.Repository; + +/** + * 应用配置仓库接口 + */ +@Repository +public interface IDeployAppConfigRepository extends IBaseRepository { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployAppConfigService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployAppConfigService.java new file mode 100644 index 00000000..2da64e7d --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployAppConfigService.java @@ -0,0 +1,23 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.BuildConfigDefinedDTO; +import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO; +import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig; +import com.qqchen.deploy.backend.deploy.query.DeployAppConfigQuery; +import com.qqchen.deploy.backend.framework.service.IBaseService; +import com.qqchen.deploy.backend.workflow.dto.WorkflowNodeTypeDefinedDTO; + +import java.util.List; + +/** + * 应用配置服务接口 + */ +public interface IDeployAppConfigService extends IBaseService { + + /** + * 获取构建类型Schema定义 + * + * @return Schema定义列表 + */ + List defined(); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployAppConfigServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployAppConfigServiceImpl.java new file mode 100644 index 00000000..fbb658c3 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployAppConfigServiceImpl.java @@ -0,0 +1,56 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.dto.BuildConfigDefinedDTO; +import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO; +import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig; +import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum; +import com.qqchen.deploy.backend.deploy.enums.DevelopmentLanguageTypeEnum; +import com.qqchen.deploy.backend.deploy.query.DeployAppConfigQuery; +import com.qqchen.deploy.backend.deploy.service.IDeployAppConfigService; +import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +import static com.qqchen.deploy.backend.workflow.util.GenerateSchemaUtils.generateSchema; + +/** + * 应用配置服务实现类 + */ +@Slf4j +@Service +public class DeployAppConfigServiceImpl extends BaseServiceImpl implements IDeployAppConfigService { + + + @Override + public List defined() { + List result = new ArrayList<>(); + + for (BuildTypeEnum buildType : BuildTypeEnum.values()) { + try { + BuildConfigDefinedDTO definedDTO = new BuildConfigDefinedDTO(); + definedDTO.setCode(buildType.getCode()); + definedDTO.setName(buildType.getName()); + // 获取支持的语言和对应的构建变量类 + DevelopmentLanguageTypeEnum[] languages = buildType.getSupportedLanguages(); + Class[] buildVariablesClasses = buildType.getBuildVariables(); + definedDTO.setBuildType(buildType); + // 如果支持的语言不为空,则处理每种语言对应的Schema + if (languages != null && buildVariablesClasses != null) { + for (int i = 0; i < languages.length; i++) { + if (buildVariablesClasses[i] != null) { + definedDTO.setLanguageType(languages[i]); + definedDTO.setBuildVariablesSchema(generateSchema(buildVariablesClasses[i])); + result.add(definedDTO); + } + } + } + } catch (Exception e) { + log.error("Error processing build type: " + buildType, e); + } + } + return result; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowNodeDefinitionServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowNodeDefinitionServiceImpl.java index 33baee2f..97c7840a 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowNodeDefinitionServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowNodeDefinitionServiceImpl.java @@ -30,6 +30,8 @@ import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty; import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSource; import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSourceParam; +import static com.qqchen.deploy.backend.workflow.util.GenerateSchemaUtils.generateSchema; + /** * 工作流节点定义服务实现 */ @@ -125,184 +127,4 @@ public class WorkflowNodeDefinitionServiceImpl extends BaseServiceImpl cls) { - ObjectMapper mapper = new ObjectMapper(); - ObjectNode schema = mapper.createObjectNode(); - schema.put("type", "object"); - - // 处理属性 - ObjectNode properties = schema.putObject("properties"); - List required = new ArrayList<>(); - - // 获取所有字段,包括父类的字段 - List allFields = getAllFields(cls); - - // 遍历所有字段 - for (Field field : allFields) { - SchemaProperty annotation = field.getAnnotation(SchemaProperty.class); - if (annotation != null) { - ObjectNode property = properties.putObject(field.getName()); - - // 设置基本属性 - String jsonType = getJsonSchemaType(field.getType()); - property.put("type", jsonType); - - // 从注解中获取属性 - if (!annotation.title().isEmpty()) { - property.put("title", annotation.title()); - } - if (!annotation.description().isEmpty()) { - property.put("description", annotation.description()); - } - if (!annotation.format().isEmpty()) { - property.put("format", annotation.format()); - } - if (annotation.required()) { - required.add(field.getName()); - } - if (annotation.defaultValue().length() > 0) { - if (jsonType.equals("integer")) { - property.put("default", Integer.parseInt(annotation.defaultValue())); - } else if (jsonType.equals("number")) { - property.put("default", Double.parseDouble(annotation.defaultValue())); - } else { - property.put("default", annotation.defaultValue()); - } - } - - // 处理枚举 - if (annotation.enumValues().length > 0) { - ArrayNode enumNode = property.putArray("enum"); - for (String value : annotation.enumValues()) { - enumNode.add(value); - } - - if (annotation.enumNames().length > 0) { - ArrayNode enumNamesNode = property.putArray("enumNames"); - for (String name : annotation.enumNames()) { - enumNamesNode.add(name); - } - } - } - - // 处理数组类型 - if (List.class.isAssignableFrom(field.getType())) { - ObjectNode items = property.putObject("items"); - items.put("type", "string"); - } - - // 处理Map类型 - if (Map.class.isAssignableFrom(field.getType())) { - ObjectNode additionalProperties = property.putObject("additionalProperties"); - additionalProperties.put("type", "string"); - } - - // 处理嵌套对象 - if (property.get("type").asText().equals("object") - && !Map.class.isAssignableFrom(field.getType()) - && !field.getType().getName().startsWith("java.")) { - ObjectNode nestedSchema = generateSchema(field.getType()); - if (nestedSchema.has("properties")) { - property.set("properties", nestedSchema.get("properties")); - } - if (nestedSchema.has("required")) { - property.set("required", nestedSchema.get("required")); - } - } - - // 处理数据源 - SchemaPropertyDataSource dataSource = annotation.dataSource(); - if (dataSource != null && !dataSource.type().isEmpty()) { - processDataSource(property, dataSource); - } - } - } - - // 添加required字段 - if (!required.isEmpty()) { - ArrayNode requiredNode = schema.putArray("required"); - required.forEach(requiredNode::add); - } - return schema; - } - - /** - * 处理SchemaPropertyDataSource注解,生成数据源配置 - * - * @param property 当前属性节点 - * @param dataSource 数据源注解 - */ - private void processDataSource(ObjectNode property, SchemaPropertyDataSource dataSource) { - ObjectNode dataSourceNode = property.putObject("dataSource"); - - // 处理基本属性 - dataSourceNode.put("type", dataSource.type()); - dataSourceNode.put("url", dataSource.url()); - dataSourceNode.put("valueField", dataSource.valueField()); - dataSourceNode.put("labelField", dataSource.labelField()); - - // 处理依赖字段 - String[] dependsOn = dataSource.dependsOn(); - if (dependsOn != null && dependsOn.length > 0) { - ArrayNode dependsOnNode = dataSourceNode.putArray("dependsOn"); - for (String depend : dependsOn) { - dependsOnNode.add(depend); - } - } - - // 处理请求参数 - SchemaPropertyDataSourceParam[] params = dataSource.params(); - if (params != null && params.length > 0) { - ObjectNode paramsNode = dataSourceNode.putObject("params"); - for (SchemaPropertyDataSourceParam param : params) { - paramsNode.put(param.name(), param.value()); - } - } - -// // 处理其他可选属性 -// if (!dataSource.method().isEmpty()) { -// dataSourceNode.put("method", dataSource.method()); -// } -// if (!dataSource.searchField().isEmpty()) { -// dataSourceNode.put("searchField", dataSource.searchField()); -// } - } - - /** - * 获取类的所有字段,包括父类的字段 - */ - private List getAllFields(Class clazz) { - List fields = new ArrayList<>(); - Class currentClass = clazz; - - // 遍历类的继承层次 - while (currentClass != null && !currentClass.equals(Object.class)) { - // 添加当前类的字段 - fields.addAll(Arrays.asList(currentClass.getDeclaredFields())); - // 获取父类 - currentClass = currentClass.getSuperclass(); - } - - return fields; - } - - private String getJsonSchemaType(Class type) { - if (String.class.equals(type)) { - return "string"; - } else if (Integer.class.equals(type) || int.class.equals(type) - || Long.class.equals(type) || long.class.equals(type)) { - return "integer"; - } else if (Double.class.equals(type) || double.class.equals(type) - || Float.class.equals(type) || float.class.equals(type)) { - return "number"; - } else if (Boolean.class.equals(type) || boolean.class.equals(type)) { - return "boolean"; - } else if (List.class.isAssignableFrom(type)) { - return "array"; - } else if (Map.class.isAssignableFrom(type)) { - return "object"; - } else { - return "object"; - } - } } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/GenerateSchemaUtils.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/GenerateSchemaUtils.java new file mode 100644 index 00000000..dc5c815b --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/GenerateSchemaUtils.java @@ -0,0 +1,194 @@ +package com.qqchen.deploy.backend.workflow.util; + +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.annotation.SchemaProperty; +import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSource; +import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSourceParam; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class GenerateSchemaUtils { + + public static ObjectNode generateSchema(Class cls) { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode schema = mapper.createObjectNode(); + schema.put("type", "object"); + + // 处理属性 + ObjectNode properties = schema.putObject("properties"); + List required = new ArrayList<>(); + + // 获取所有字段,包括父类的字段 + List allFields = getAllFields(cls); + + // 遍历所有字段 + for (Field field : allFields) { + SchemaProperty annotation = field.getAnnotation(SchemaProperty.class); + if (annotation != null) { + ObjectNode property = properties.putObject(field.getName()); + + // 设置基本属性 + String jsonType = getJsonSchemaType(field.getType()); + property.put("type", jsonType); + + // 从注解中获取属性 + if (!annotation.title().isEmpty()) { + property.put("title", annotation.title()); + } + if (!annotation.description().isEmpty()) { + property.put("description", annotation.description()); + } + if (!annotation.format().isEmpty()) { + property.put("format", annotation.format()); + } + if (annotation.required()) { + required.add(field.getName()); + } + if (annotation.defaultValue().length() > 0) { + if (jsonType.equals("integer")) { + property.put("default", Integer.parseInt(annotation.defaultValue())); + } else if (jsonType.equals("number")) { + property.put("default", Double.parseDouble(annotation.defaultValue())); + } else { + property.put("default", annotation.defaultValue()); + } + } + + // 处理枚举 + if (annotation.enumValues().length > 0) { + ArrayNode enumNode = property.putArray("enum"); + for (String value : annotation.enumValues()) { + enumNode.add(value); + } + + if (annotation.enumNames().length > 0) { + ArrayNode enumNamesNode = property.putArray("enumNames"); + for (String name : annotation.enumNames()) { + enumNamesNode.add(name); + } + } + } + + // 处理数组类型 + if (List.class.isAssignableFrom(field.getType())) { + ObjectNode items = property.putObject("items"); + items.put("type", "string"); + } + + // 处理Map类型 + if (Map.class.isAssignableFrom(field.getType())) { + ObjectNode additionalProperties = property.putObject("additionalProperties"); + additionalProperties.put("type", "string"); + } + + // 处理嵌套对象 + if (property.get("type").asText().equals("object") && !Map.class.isAssignableFrom(field.getType()) && !field.getType().getName().startsWith("java.")) { + ObjectNode nestedSchema = generateSchema(field.getType()); + if (nestedSchema.has("properties")) { + property.set("properties", nestedSchema.get("properties")); + } + if (nestedSchema.has("required")) { + property.set("required", nestedSchema.get("required")); + } + } + + // 处理数据源 + SchemaPropertyDataSource dataSource = annotation.dataSource(); + if (dataSource != null && !dataSource.type().isEmpty()) { + processDataSource(property, dataSource); + } + } + } + + // 添加required字段 + if (!required.isEmpty()) { + ArrayNode requiredNode = schema.putArray("required"); + required.forEach(requiredNode::add); + } + return schema; + } + + /** + * 处理SchemaPropertyDataSource注解,生成数据源配置 + * + * @param property 当前属性节点 + * @param dataSource 数据源注解 + */ + private static void processDataSource(ObjectNode property, SchemaPropertyDataSource dataSource) { + ObjectNode dataSourceNode = property.putObject("dataSource"); + + // 处理基本属性 + dataSourceNode.put("type", dataSource.type()); + dataSourceNode.put("url", dataSource.url()); + dataSourceNode.put("valueField", dataSource.valueField()); + dataSourceNode.put("labelField", dataSource.labelField()); + + // 处理依赖字段 + String[] dependsOn = dataSource.dependsOn(); + if (dependsOn != null && dependsOn.length > 0) { + ArrayNode dependsOnNode = dataSourceNode.putArray("dependsOn"); + for (String depend : dependsOn) { + dependsOnNode.add(depend); + } + } + + // 处理请求参数 + SchemaPropertyDataSourceParam[] params = dataSource.params(); + if (params != null && params.length > 0) { + ObjectNode paramsNode = dataSourceNode.putObject("params"); + for (SchemaPropertyDataSourceParam param : params) { + paramsNode.put(param.name(), param.value()); + } + } + +// // 处理其他可选属性 +// if (!dataSource.method().isEmpty()) { +// dataSourceNode.put("method", dataSource.method()); +// } +// if (!dataSource.searchField().isEmpty()) { +// dataSourceNode.put("searchField", dataSource.searchField()); +// } + } + + /** + * 获取类的所有字段,包括父类的字段 + */ + private static List getAllFields(Class clazz) { + List fields = new ArrayList<>(); + Class currentClass = clazz; + + // 遍历类的继承层次 + while (currentClass != null && !currentClass.equals(Object.class)) { + // 添加当前类的字段 + fields.addAll(Arrays.asList(currentClass.getDeclaredFields())); + // 获取父类 + currentClass = currentClass.getSuperclass(); + } + + return fields; + } + + private static String getJsonSchemaType(Class type) { + if (String.class.equals(type)) { + return "string"; + } else if (Integer.class.equals(type) || int.class.equals(type) || Long.class.equals(type) || long.class.equals(type)) { + return "integer"; + } else if (Double.class.equals(type) || double.class.equals(type) || Float.class.equals(type) || float.class.equals(type)) { + return "number"; + } else if (Boolean.class.equals(type) || boolean.class.equals(type)) { + return "boolean"; + } else if (List.class.isAssignableFrom(type)) { + return "array"; + } else if (Map.class.isAssignableFrom(type)) { + return "object"; + } else { + return "object"; + } + } +} diff --git a/backend/src/main/resources/db/migration/V1.0.1__init_data.sql b/backend/src/main/resources/db/migration/V1.0.1__init_data.sql index 7c55462c..74363354 100644 --- a/backend/src/main/resources/db/migration/V1.0.1__init_data.sql +++ b/backend/src/main/resources/db/migration/V1.0.1__init_data.sql @@ -78,6 +78,8 @@ VALUES (202, '应用管理', '/deploy/applications', '/src/pages/Deploy/Application/List/index', 'AppstoreOutlined', 2, 200, 2, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), (203, '环境管理', '/deploy/environments', '/src/pages/Deploy/Environment/List/index', 'CloudOutlined', 2, 200, 3, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), + +(204, '部署配置管理', '/deploy/deployment', '/src/pages/Deploy/Deployment/List/index', 'CloudOutlined', 2, 200, 3, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), -- 三方系统 (205, '三方系统管理', '/deploy/external', '/src/pages/Deploy/external/index', 'ApiOutlined', 2, 200, 70, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE);