diff --git a/orion-ops-dependencies/pom.xml b/orion-ops-dependencies/pom.xml index e8403ec2..cf796e86 100644 --- a/orion-ops-dependencies/pom.xml +++ b/orion-ops-dependencies/pom.xml @@ -18,6 +18,9 @@ 2.7.11 1.0.5 1.18.26 + 1.6.15 + 4.1.0 + 1.5.5.Final @@ -60,16 +63,52 @@ orion-ops-spring-boot-starter-web ${revision} + + com.orion.ops + orion-ops-spring-boot-starter-swagger + ${revision} + - + org.projectlombok lombok ${lombok.version} + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-jdk8 + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + org.springdoc + springdoc-openapi-ui + ${springdoc.version} + + + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + ${knife4j.version} + + diff --git a/orion-ops-framework/orion-ops-common/pom.xml b/orion-ops-framework/orion-ops-common/pom.xml index 28f0a91c..c4717604 100644 --- a/orion-ops-framework/orion-ops-common/pom.xml +++ b/orion-ops-framework/orion-ops-common/pom.xml @@ -26,6 +26,27 @@ org.projectlombok lombok + + + + org.mapstruct + mapstruct + + + org.mapstruct + mapstruct-jdk8 + + + org.mapstruct + mapstruct-processor + + + + + org.springdoc + springdoc-openapi-ui + provided + \ No newline at end of file diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/java/com/orion/ops/framework/banner/core/BannerApplicationRunner.java b/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/java/com/orion/ops/framework/banner/core/BannerApplicationRunner.java index 0b4f203b..401748be 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/java/com/orion/ops/framework/banner/core/BannerApplicationRunner.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/java/com/orion/ops/framework/banner/core/BannerApplicationRunner.java @@ -33,7 +33,7 @@ public class BannerApplicationRunner implements ApplicationRunner { String line = AnsiCode.GLOSS_GREEN.stain(":: orion-ops-server v" + version + " 服务已启动(" + env + ") ::\n") + AnsiCode.GLOSS_GREEN.stain(":: swagger 文档 ") + // TODO swagger 地址 - AnsiCode.GLOSS_BLUE.stain("http://127.0.0.1:xxxx/dox.html\n") + + AnsiCode.GLOSS_BLUE.stain("http://127.0.0.1:" + port + "/doc.html\n") + AnsiCode.GLOSS_GREEN.stain(":: server 心跳检测 ") + AnsiCode.GLOSS_BLUE + "curl -X GET --location \"http://127.0.0.1:" + port + apiPrefix + "/server/bootstrap/health\"" + diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/resources/banner.txt b/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/resources/banner.txt index 96ff95f2..5d5f4a1a 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/resources/banner.txt +++ b/orion-ops-framework/orion-ops-spring-boot-starter-banner/src/main/resources/banner.txt @@ -9,3 +9,4 @@ ${AnsiColor.BRIGHT_GREEN}:: Application Name ${AnsiColor.BLUE}${spring.appli ${AnsiColor.BRIGHT_GREEN}:: Application Version ${AnsiColor.BLUE}${orion.version} ${AnsiColor.BRIGHT_GREEN}:: SpringBoot Version ${AnsiColor.BLUE}${spring-boot.version} ${AnsiColor.BRIGHT_GREEN}:: Active Profile ${AnsiColor.BLUE}${spring.profiles.active} +${AnsiColor.DEFAULT} \ No newline at end of file diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-swagger/pom.xml b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/pom.xml new file mode 100644 index 00000000..4db48c26 --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/pom.xml @@ -0,0 +1,43 @@ + + + + com.orion.ops + orion-ops-framework + ${revision} + + + 4.0.0 + orion-ops-spring-boot-starter-swagger + ${project.artifactId} + jar + + 项目 swagger 配置包 + https://github.com/lijiahangmax/orion-ops-pro + + + + com.orion.ops + orion-ops-common + + + + org.springframework.boot + spring-boot-starter + + + + + org.springdoc + springdoc-openapi-ui + + + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + + + + \ No newline at end of file diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/java/com/orion/ops/framework/swagger/config/OrionSwaggerAutoConfiguration.java b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/java/com/orion/ops/framework/swagger/config/OrionSwaggerAutoConfiguration.java new file mode 100644 index 00000000..cdf82c7c --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/java/com/orion/ops/framework/swagger/config/OrionSwaggerAutoConfiguration.java @@ -0,0 +1,160 @@ +package com.orion.ops.framework.swagger.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springdoc.core.*; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.providers.JavadocProvider; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpHeaders; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * swagger 配置 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2022/6/21 11:22 + */ +@Profile({"dev"}) +@ConditionalOnClass({OpenAPI.class}) +@EnableConfigurationProperties(SwaggerProperties.class) +@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) +@AutoConfiguration +public class OrionSwaggerAutoConfiguration { + + private static String orionApiPrefix; + + /** + * @param properties 配置 + * @return API + */ + @Bean + public OpenAPI createApi(SwaggerProperties properties) { + Map securitySchemas = this.buildSecuritySchemes(); + OpenAPI api = new OpenAPI() + // 接口信息 + .info(buildInfo(properties)) + // 接口安全配置 + .components(new Components().securitySchemes(securitySchemas)); + securitySchemas.keySet() + .forEach(key -> api.addSecurityItem(new SecurityRequirement().addList(key))); + return api; + } + + /** + * api 摘要信息 + */ + private Info buildInfo(SwaggerProperties properties) { + return new Info() + .title(properties.getTitle()) + .description(properties.getDescription()) + .version(properties.getVersion()) + .contact(new Contact().name(properties.getAuthor()).url(properties.getUrl()).email(properties.getEmail())) + .license(new License().name(properties.getLicense()).url(properties.getLicenseUrl())); + } + + /** + * 配置请求头 Authorization 传递 token 参数 + * + * @return 安全模式 + */ + private Map buildSecuritySchemes() { + Map securitySchemes = new HashMap<>(); + SecurityScheme securityScheme = new SecurityScheme() + // 类型 + .type(SecurityScheme.Type.APIKEY) + // 请求头的 name + .name(HttpHeaders.AUTHORIZATION) + // token 所在位置 + .in(SecurityScheme.In.HEADER); + securitySchemes.put(HttpHeaders.AUTHORIZATION, securityScheme); + return securitySchemes; + } + + /** + * @return 自定义 OpenAPI 处理器 + */ + @Bean + public OpenAPIService openApiBuilder(Optional openAPI, + SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, + PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomizers, + Optional> serverBaseUrlCustomizers, + Optional javadocProvider) { + + return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, + propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); + } + + + /** + * @return 所有模块的 api 分组 + */ + @Bean + public GroupedOpenApi allGroupedOpenApi() { + return buildGroupedOpenApi("全部", ""); + } + + /** + * 构建 api 分组 + * + * @param group group + * @return group + */ + public static GroupedOpenApi buildGroupedOpenApi(String group) { + return buildGroupedOpenApi(group, group); + } + + /** + * 构建 api 分组 + * + * @param group group + * @param path path + * @return group + */ + public static GroupedOpenApi buildGroupedOpenApi(String group, String path) { + return GroupedOpenApi.builder() + .group(group) + .pathsToMatch(orionApiPrefix + "/" + path + "/**") + .addOperationCustomizer((operation, handlerMethod) -> operation + .addParametersItem(buildSecurityHeaderParameter())) + .build(); + } + + /** + * @return Authorization 认证请求头参数 + */ + private static Parameter buildSecurityHeaderParameter() { + return new Parameter() + .name(HttpHeaders.AUTHORIZATION) + .description("认证 Token") + .in(String.valueOf(SecurityScheme.In.HEADER)) + .schema(new StringSchema()._default("Bearer ").name("NAME").description("认证 Token")); + } + + @Value("${orion.api.prefix}") + public void setOrionApiPrefix(String orionApiPrefix) { + OrionSwaggerAutoConfiguration.orionApiPrefix = orionApiPrefix; + } + +} diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/java/com/orion/ops/framework/swagger/config/SwaggerProperties.java b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/java/com/orion/ops/framework/swagger/config/SwaggerProperties.java new file mode 100644 index 00000000..40f4bf74 --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/java/com/orion/ops/framework/swagger/config/SwaggerProperties.java @@ -0,0 +1,55 @@ +package com.orion.ops.framework.swagger.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/6/21 11:13 + */ +@Data +@ConfigurationProperties("orion.swagger") +public class SwaggerProperties { + + /** + * 标题 + */ + private String title; + + /** + * 描述 + */ + private String description; + + /** + * 作者 + */ + private String author; + + /** + * 版本 + */ + private String version; + + /** + * url + */ + private String url; + + /** + * email + */ + private String email; + + /** + * license + */ + private String license; + + /** + * license-url + */ + private String licenseUrl; + +} diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..0c9c980a --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.orion.ops.framework.swagger.config.OrionSwaggerAutoConfiguration \ No newline at end of file diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionWebAutoConfiguration.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionWebAutoConfiguration.java index 383e9577..3106416f 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionWebAutoConfiguration.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionWebAutoConfiguration.java @@ -15,6 +15,8 @@ import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.http.MediaType; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; +import org.springframework.util.AntPathMatcher; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -27,6 +29,8 @@ import java.util.List; /** * web 配置类 + *

+ * TODO XSS 后续选择性的配置 * * @author Jiahang Li * @version 1.0.0 @@ -38,12 +42,12 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer { @Value("${orion.api.prefix}") private String orionApiPrefix; - // TODO XSS - @Override public void configurePathMatch(PathMatchConfigurer configurer) { // 公共 api 前缀 - configurer.addPathPrefix(orionApiPrefix, clazz -> clazz.isAnnotationPresent(RestController.class)); + AntPathMatcher antPathMatcher = new AntPathMatcher("."); + configurer.addPathPrefix(orionApiPrefix, clazz -> clazz.isAnnotationPresent(RestController.class) + && antPathMatcher.match("com.orion.ops.**.controller.**", clazz.getPackage().getName())); // 仅仅匹配 controller 包 } /** diff --git a/orion-ops-framework/pom.xml b/orion-ops-framework/pom.xml index 22553a66..a6bf599f 100644 --- a/orion-ops-framework/pom.xml +++ b/orion-ops-framework/pom.xml @@ -17,8 +17,9 @@ orion-ops-common - orion-ops-spring-boot-starter-banner orion-ops-spring-boot-starter-web + orion-ops-spring-boot-starter-banner + orion-ops-spring-boot-starter-swagger \ No newline at end of file diff --git a/orion-ops-server/pom.xml b/orion-ops-server/pom.xml index af498e60..c22314a0 100644 --- a/orion-ops-server/pom.xml +++ b/orion-ops-server/pom.xml @@ -32,6 +32,10 @@ com.orion.ops orion-ops-spring-boot-starter-web + + com.orion.ops + orion-ops-spring-boot-starter-swagger + org.springframework.boot diff --git a/orion-ops-server/src/main/resources/application.yaml b/orion-ops-server/src/main/resources/application.yaml index a35fdf78..3288fad9 100644 --- a/orion-ops-server/src/main/resources/application.yaml +++ b/orion-ops-server/src/main/resources/application.yaml @@ -21,11 +21,37 @@ spring: pathmatch: matching-strategy: ANT_PATH_MATCHER +springdoc: + api-docs: + enabled: true + path: /v3/api-docs + swagger-ui: + enabled: true + path: /swagger-ui + tags-sorter: alpha + operations-sorter: alpha + show-extensions: true + +knife4j: + enable: true + setting: + language: zh_cn + orion: # 版本 version: @revision@ + # api 信息 api: # 公共api前缀 prefix: /orion-api # 是否开启跨域 cors: true + # 文档配置 + swagger: + title: orion-ops-pro 运维平台 + description: 一站式提供运维功能 + version: ${orion.version} + url: https://github.com/lijiahangmax/orion-ops-pro + email: ljh1553488six@139.com + license: Apache-2.0 + license-url: https://github.com/lijiahangmax/orion-ops-pro/blob/main/LICENSE