【全网最新-首发】Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成

[原创]Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成

  • 一. springdoc-openapi简介
    • open api 简介
    • swagger 简介
    • springfox 简介
    • springdoc 简介
  • 二. 如何从Springfox迁移过来?
    • 依赖替换
    • 注解版本替换
    • Docket对象替换为GroupedOpenApi
  • 三. 笔者亲自实战分享
    • 本案例的灵活性介绍
    • 本案例完整示例展示
  • 四. 启动成功页面效果展示

一. springdoc-openapi简介

open api 简介

OpenApi是业界真正的 api 文档标准,一个规范,好比java里面一个抽象的概念。
它即是一个抽象类,只是提供了一个api文档规范的抽象方法,该方法目前被两大非官方实现了,一个是springfox,另一个是springdoc。

swagger 简介

  1. swagger 是一个 api 文档维护组织,后来成为了 Open API 标准的主要定义者,现在最新的版本为17年发布的 Swagger3(Open Api3)。
  2. 国内绝大部分人还在用过时的swagger2(17年停止维护并更名为swagger3)swagger2的包名为 io.swagger,而swagger3的包名为 io.swagger.core.v3。

springfox 简介

  1. SpringFox是 spring 社区维护的一个项目(非官方),帮助使用者将 swagger2 集成到 Spring 中。常常用于 Spring 中帮助开发者生成文档,并可以轻松的在spring boot中使用。
  2. 截至2020年4月,都未支持 OpenAPI3 标准。
  3. 此版本实现较springdoc来讲,实现不是很规范和正式,少了很多架构上的灵活性,维护更新也不如springdoc活跃。因此笔者推荐大家使用springdoc,弃用springfox。

springdoc 简介

  1. SpringDoc也是 spring 社区维护的一个项目(非官方),帮助使用者将 swagger3 集成到 Spring 中。也是用来在 Spring 中帮助开发者生成文档,并可以轻松的在spring boot中使用。
    该组织下的项目支持swagger页面Oauth2登录(Open API3的内容),相较 Springfox来说,它的支撑时间更长,无疑是更好的选择。由于国内发展较慢,在国内不容易看到太多有用的文档,不过可以访问它的官网。它使用了 swagger3(OpenAPI3),但 swagger3 并未对 swagger2 的注解做兼容,不易迁移,也因此名气并不如 springfox
  2. springdoc-openapi的工作原理是在运行时检查应用程序,根据spring配置、类结构和各种注释推断API语义。自动生成JSON/YAML和HTML格式api中的文档。这个文档可以通过使用swaggerapi注释的注释来完成。
  3. springdoc-openapi库支持
    OpenAPI 3
    Spring-boot (v1 and v2)
    JSR-303,专门用于@NotNull、@Min、@Max和@Size。 Swagger-ui
    OAuth 2
    以下图片对该库进行简单介绍:
    【全网最新-首发】Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成_第1张图片

二. 如何从Springfox迁移过来?

依赖替换

 删除springfox和swagger 2的依赖项。而是添加springdoc openapi用户界面依赖项。以下是当前最新版本 
<dependency>
    <groupId>org.springdocgroupId>
     <artifactId>springdoc-openapi-uiartifactId>
    <version>1.4.3version>
dependency>

注解版本替换

  1. 将swagger 2注释替换为swagger 3注释(它已经包含在springdoc-openapi-ui依赖项中)。swagger 3注解是io.swagger.v3.oas.annotations包名下的。
  2. 两个版本的注解映射关系:
@Api -> @Tag
@ApiIgnore -> @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden
@ApiImplicitParam -> @Parameter
@ApiImplicitParams -> @Parameters
@ApiModel -> @Schema
@ApiModelProperty(hidden = true) -> @Schema(accessMode = READ_ONLY)
@ApiModelProperty -> @Schema
@ApiOperation(value = "foo", notes = "bar") -> @Operation(summary = "foo", description = "bar")
@ApiParam -> @Parameter
@ApiResponse(code = 404, message = "foo") -> @ApiResponse(responseCode = "404", description = "foo")

Docket对象替换为GroupedOpenApi

  1. GroupedOpenApi对象的意义,顾名思义,是对api进行分组划分,方便阅读,仅此。此步骤是可选的:仅当您有多个Docket Bean对象时,将它们替换为GroupedOpenApi bean。
    swagger2配置Docket是:
   @Bean
   public Docket publicApi() {
       return new Docket(DocumentationType.SWAGGER_2)
               .select()
               .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
               .paths(PathSelectors.regex("/public.*"))
               .build()
               .groupName("springshop-public")
               .apiInfo(apiInfo());
   }
 
   @Bean
   public Docket adminApi() {
       return new Docket(DocumentationType.SWAGGER_2)
               .select()
               .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.admin"))
               .paths(PathSelectors.regex("/admin.*"))
               .build()
               .groupName("springshop-admin")
               .apiInfo(apiInfo());
   }

需要替换成springdoc-openapi配置的GroupedOpenApi对象

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .setGroup("springshop-public")
                .pathsToMatch("/public/**")
                .build();
    }
  
    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
                .setGroup("springshop-admin")
                .pathsToMatch("/admin/**")
                .build();
    }
  1. 笔者通过亲自尝试,表达下自己的想法,不建议配置GroupedOpenApi对象,理由就是比较繁琐,如果要配置,最佳方式是一个controller类对应一个GroupedOpenApi对象,但是这个方法除非手动一个个配置,那样太繁琐。可以考虑通过程序自动生成分组的GroupedOpenApi对象,但是依然比较繁琐,必要的情况可能还需要开发者自己去解析字节码提取controller类上的RequestMapping注解。所以不建议配置该对象,直接用默认即可。
  2. 添加OpenAPI类型的Spring bean对象,参见示例:
    @Bean
    public OpenAPI springShopOpenAPI() {
        Components components = new Components();
        
        // 添加auth认证header
        components.addSecuritySchemes("auth", new SecurityScheme().type(SecurityScheme.Type.APIKEY).name("auth").in(In.HEADER).scheme("basic"));
        
        // 添加全局header
        components.addParameters("myHeader1", new Parameter().in(In.HEADER.toString()).schema(new StringSchema()).name("myHeader1"));
        components.addHeaders("myHeader2", new Header().description("myHeader2 header").schema(new StringSchema()));
        
        return new OpenAPI()
                .components(components)
                .info(new Info().title("Sinhy " + applicationName + " Api Doc")
                .description(applicationDescription)
                .version("Application Version: " + applicationVersion + "\n Spring Boot Version: " + SpringBootVersion.getVersion())
                .license(new License().name("Apache 2.0").url("http://springdoc.org")))
                .externalDocs(new ExternalDocumentation()
                .description("SpringShop Wiki Documentation")
                .url("https://springshop.wiki.github.org/docs"));
    }

三. 笔者亲自实战分享

本案例的灵活性介绍

  1. 能够自动对 “ spring拦截器Interceptor添加api文档地址访问拦截 ” 进行排除添加,需要实现WebMvcConfigurer接口。如下示例所示:
public class SpringdocConfiguration implements WebMvcConfigurer
添加实现方法
    /**
     * 通用拦截器排除设置,所有拦截器都会自动加springdoc-opapi相关的资源排除信息,不用在应用程序自身拦截器定义的地方去添加,算是良心解耦实现。
     */
    @SuppressWarnings("unchecked")
    public void addInterceptors(InterceptorRegistry registry)
    {
        Field registrationsField = ClassUtils.getField(InterceptorRegistry.class, "registrations");
        List<InterceptorRegistration> registrations = (List<InterceptorRegistration>) ReflectionUtils.getField(registrationsField, registry);
        if (registrations != null)
        {
            for (InterceptorRegistration interceptorRegistration : registrations)
            {
                interceptorRegistration.excludePathPatterns("/springdoc**/**");
            }
        }
    }
  1. api文档集成好后,springboot应用启动成功,程序便会自动打开浏览器,访问api-doc地址。程序要实现ApplicationListener接口,代码示例如下:
public class SpringdocConfiguration implements ApplicationListener<ContextRefreshedEvent>
{
添加实现方法
    /**
     * 
系统启动后自动打开浏览器访问api-doc地址
* @author lilinhai * @since 2020-07-17 15:53 * @param arg0 * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */
@Override public void onApplicationEvent(ContextRefreshedEvent arg0) { StartupInformation.getInstance().setStartupTime(new Date()); if (PlatformUtils.isWindows()) { // 如果rest-api开关打开,则启动完成后启动打开浏览器并浏览该rest-api主页 String baseUrl = "http://localhost:" + port; if (!contextPath.startsWith("/")) { baseUrl += "/"; } baseUrl += contextPath; if (!baseUrl.endsWith("/")) { baseUrl += "/"; } if (apiDocUiPath.startsWith("/")) { apiDocUiPath = apiDocUiPath.substring(1); } // 打开rest-api网址 String restApiUrl = baseUrl + apiDocUiPath; BrowseUtils.browse(restApiUrl); // 打开数据源监控网址 String datasourceMonitorUrl = baseUrl + "datasource-monitor/admin.html"; BrowseUtils.browse(datasourceMonitorUrl); } }

本案例完整示例展示

  1. 准备一个springdoc.yml配置文件,以下springdoc.yml的配置内容是笔者深入阅读官方文档提取出的必要配置选项,算是精华部分,特此分享给大家,如果大家也要阅读官方文档,请点击此链接:springdoc-sproperties
springdoc: 
  swagger-ui: 
  
    # 自定义的文档界面访问路径。默认访问路径是/swagger-ui.html
    path: /springdoc/docs.html
    
    # 字符串类型,一共三个值来控制操作和标记的默认展开设置。它可以是“list”(仅展开标记)、“full”(展开标记和操作)或“none”(不展开任何内容)。
    docExpansion: none
    
    # 布尔值。控制“试用”请求的请求持续时间(毫秒)的显示。 
    displayRequestDuration: true
    
    # 布尔值。控制供应商扩展(x-)字段和操作、参数和架构值的显示。 
    showExtensions: true
    
    # 布尔值。控制参数的扩展名(pattern、maxLength、minLength、maximum、minminimum)字段和值的显示。 
    showCommonExtensions: true
    
    # 布尔值。禁用swagger用户界面默认petstore url。(从v1.4.1开始提供)。 
    disable-swagger-default-url: true
    
  api-docs: 
  
    # 自定义的文档api元数据访问路径。默认访问路径是/v3/api-docs
    path: /springdoc/api-docs
    
    # 布尔值。在@Schema(名称name、标题title和说明description,三个属性)上启用属性解析程序。 
    resolve-schema-properties: true
    
    # 布尔值。实现OpenApi规范的打印。 
    writer-with-default-pretty-printer: true
  1. controller类注解添加示例
    【全网最新-首发】Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成_第2张图片
  2. model类注解添加示例
    【全网最新-首发】Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成_第3张图片
  3. SpringdocOpenapiConfiguration完整代码示例
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;

import org.apache.logging.log4j.core.config.Order;
import org.springdoc.core.Constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.headers.Header;
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.SecurityScheme;
import io.swagger.v3.oas.models.security.SecurityScheme.In;
import pers.linhai.nature.spring.YamlPropertySourceFactory;
import pers.linhai.nature.utils.BrowseUtils;
import pers.linhai.nature.utils.ClassUtils;
import pers.linhai.nature.utils.PlatformUtils;
import pers.linhai.nature.utils.ReflectionUtils;
import pers.linhai.nature.webmvc.controller.model.SystemInfo.StartupInformation;

/**
 * 
Springdoc-openapi配置
* * @author lilinhai * @since 2020-07-13 10:46 * @version V1.0 */
@Order(Integer.MAX_VALUE) @Configuration @ConditionalOnProperty(name = Constants.SPRINGDOC_ENABLED, havingValue = "true", matchIfMissing = true) @PropertySource(value = "classpath:META-INF/springdoc.yml", factory = YamlPropertySourceFactory.class) public class SpringdocOpenapiConfiguration implements WebMvcConfigurer, ApplicationListener<ContextRefreshedEvent> { /** * 项目应用名 */ @Value("${application.name}") private String applicationName; /** * 项目版本信息 */ @Value("${application.version}") private String applicationVersion; /** * API文档访问地址 */ @Value("${springdoc.swagger-ui.path}") private String apiDocUiPath; /** * API文档访问地址 */ @Value("${springdoc.api-docs.path}") private String apiDocPath; /** * 项目描述信息 */ @Value("${application.description}") private String applicationDescription; /** * 上下文路径 */ @Value("${server.servlet.context-path}") private String contextPath; /** * web访问端口 */ @Value("${server.port}") private int port; @Bean public OpenAPI springShopOpenAPI() { Components components = new Components(); // 添加auth认证header components.addSecuritySchemes("auth", new SecurityScheme().type(SecurityScheme.Type.APIKEY).name("auth").in(In.HEADER).scheme("basic")); // 添加全局header components.addParameters("myHeader1", new Parameter().in(In.HEADER.toString()).schema(new StringSchema()).name("myHeader1")); components.addHeaders("myHeader2", new Header().description("myHeader2 header").schema(new StringSchema())); return new OpenAPI() .components(components) .info(new Info().title("Sinhy " + applicationName + " Api Doc") .description(applicationDescription) .version("Application Version: " + applicationVersion + "\n Spring Boot Version: " + SpringBootVersion.getVersion()) .license(new License().name("Apache 2.0").url("http://springdoc.org"))) .externalDocs(new ExternalDocumentation() .description("SpringShop Wiki Documentation") .url("https://springshop.wiki.github.org/docs")); } /** * 通用拦截器排除设置,所有拦截器都会自动加springdoc-opapi相关的资源排除信息,不用在应用程序自身拦截器定义的地方去添加,算是良心解耦实现。 */ @SuppressWarnings("unchecked") public void addInterceptors(InterceptorRegistry registry) { Field registrationsField = ClassUtils.getField(InterceptorRegistry.class, "registrations"); List<InterceptorRegistration> registrations = (List<InterceptorRegistration>) ReflectionUtils.getField(registrationsField, registry); if (registrations != null) { for (InterceptorRegistration interceptorRegistration : registrations) { interceptorRegistration.excludePathPatterns("/springdoc**/**"); } } } /** *
系统启动后自动打开浏览器访问api-doc地址
* @author lilinhai * @since 2020-07-17 15:53 * @param arg0 * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */
@Override public void onApplicationEvent(ContextRefreshedEvent arg0) { StartupInformation.getInstance().setStartupTime(new Date()); if (PlatformUtils.isWindows()) { // 如果rest-api开关打开,则启动完成后启动打开浏览器并浏览该rest-api主页 String baseUrl = "http://localhost:" + port; if (!contextPath.startsWith("/")) { baseUrl += "/"; } baseUrl += contextPath; if (!baseUrl.endsWith("/")) { baseUrl += "/"; } if (apiDocUiPath.startsWith("/")) { apiDocUiPath = apiDocUiPath.substring(1); } // 打开rest-api网址 String restApiUrl = baseUrl + apiDocUiPath; BrowseUtils.browse(restApiUrl); // 打开数据源监控网址 String datasourceMonitorUrl = baseUrl + "datasource-monitor/admin.html"; BrowseUtils.browse(datasourceMonitorUrl); } } }

四. 启动成功页面效果展示

【全网最新-首发】Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成_第4张图片【全网最新-首发】Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成_第5张图片【全网最新-首发】Springfox/swagger迁移springdoc-openapi & springdoc-openapi最新版本和springboot应用集成_第6张图片以上是本文全部内容,若是有疑问,请留言笔者,感谢拜读~

你可能感兴趣的:(open,api,Java专栏,openapi,springdoc与系统集成,从springfox迁移切换,springdoc推荐使用,推荐迁移springdoc)