Swagger 3.0 天天刷屏,真的香嗎?

愛撒謊的男孩發表於2020-11-06

持續原創輸出,點選上方藍字關注我

目錄

  • 前言
  • 官方文件如何說?
  • Spring Boot版本說明
  • 新增依賴
  • springfox-boot-starter做了什麼?
  • 擼起袖子就是幹?
    • 定製一個基本的文件示例
    • 文件如何分組?
    • 如何新增授權資訊?
    • 如何攜帶公共的請求引數?
  • 粗略是一個BUG
  • 總結

前言

最近頻繁被Swagger 3.0刷屏,官方表示這是一個突破性的變更,有很多的亮點,我還真不太相信,今天來帶大家嚐嚐鮮,看看這碗湯到底鮮不鮮....

官方文件如何說?

該專案開源在Github上,地址:https://github.com/springfox/springfox

Swagger 3.0有何改動?官方文件總結如下幾點:

  1. 刪除了對springfox-swagger2的依賴
  2. 刪除所有@EnableSwagger2...註解
  3. 新增了springfox-boot-starter依賴項
  4. 移除了guava等第三方依賴
  5. 文件訪問地址改變了,改成了http://ip:port/project/swagger-ui/index.html

姑且看到這裡,各位初始感覺如何?

既然人家更新出來了,我們不能不捧場,下面就介紹下Spring Boot如何整合Swagger 3.0吧。

Spring Boot版本說明

作者使用Spring Boot的版本是2.3.5.RELEASE

新增依賴

Swagger 3.0已經有了與Spring Boot整合的啟動器,只需要新增以下依賴:

  <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-boot-starter</artifactId>
       <version>3.0.0</version>
  </dependency>

springfox-boot-starter做了什麼?

Swagger 3.0主推的一大特色就是這個啟動器,那麼這個啟動器做了什麼呢?

記住:啟動器的一切邏輯都在自動配置類中。

找到springfox-boot-starter的自動配置類,在/META-INF/spring.factories檔案中,如下:

從上圖可以知道,自動配置類就是OpenApiAutoConfiguration,原始碼如下:

@Configuration
@EnableConfigurationProperties(SpringfoxConfigurationProperties.class)
@ConditionalOnProperty(value = "springfox.documentation.enabled", havingValue = "true", matchIfMissing = true)
@Import({
    OpenApiDocumentationConfiguration.class,
    SpringDataRestConfiguration.class,
    BeanValidatorPluginsConfiguration.class,
    Swagger2DocumentationConfiguration.class,
    SwaggerUiWebFluxConfiguration.class,
    SwaggerUiWebMvcConfiguration.class
})
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
    HttpMessageConvertersAutoConfiguration.class, RepositoryRestMvcAutoConfiguration.class })
public class OpenApiAutoConfiguration {

}

敢情這個自動配置類啥也沒幹,就光匯入了幾個配置類(@Import)以及開啟了屬性配置(@EnableConfigurationProperties)。

3
3

重點:記住OpenApiDocumentationConfiguration這個配置類,初步看來這是個BUG,本人也不想深入,裡面的程式碼寫的實在拙劣,註釋都不寫。

擼起袖子就是幹?

說真的,還是和以前一樣,真的沒什麼太大的改變,按照文件的步驟一步步來。

定製一個基本的文件示例

一切的東西還是需要配置類手動配置,說真的,我以為會在全域性配置檔案中自己配置就行了。哎,想多了。配置類如下:

@EnableOpenApi
@Configuration
@EnableConfigurationProperties(value = {SwaggerProperties.class})
public class SwaggerConfig {
  /**
     * 配置屬性
     */
    @Autowired
    private SwaggerProperties properties;

    @Bean
    public Docket frontApi() {
        return new Docket(DocumentationType.OAS_30)
                //是否開啟,根據環境配置
                .enable(properties.getFront().getEnable())
                .groupName(properties.getFront().getGroupName())
                .apiInfo(frontApiInfo())
                .select()
                //指定掃描的包
                .apis(RequestHandlerSelectors.basePackage(properties.getFront().getBasePackage()))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 前臺API資訊
     */
    private ApiInfo frontApiInfo() {
        return new ApiInfoBuilder()
                .title(properties.getFront().getTitle())
                .description(properties.getFront().getDescription())
                .version(properties.getFront().getVersion())
                .contact(    //新增開發者的一些資訊
                        new Contact(properties.getFront().getContactName(), properties.getFront().getContactUrl(),
                                properties.getFront().getContactEmail()))
                .build();
    }
}

@EnableOpenApi這個註解文件解釋如下:

Indicates that Swagger support should be enabled.
This should be applied to a Spring java config and should have an accompanying '@Configuration' annotation.
Loads all required beans defined in @see SpringSwaggerConfig

什麼意思呢?大致意思就是只有在配置類標註了@EnableOpenApi這個註解才會生成Swagger文件

@EnableConfigurationProperties這個註解使開啟自定義的屬性配置,這是作者自定義的Swagger配置。

總之還是和之前一樣配置,根據官方文件要求,需要在配置類上加一個@EnableOpenApi註解。

文件如何分組?

我們都知道,一個專案可能分為前臺後臺APP端小程式端.....每個端的介面可能還相同,不可能全部放在一起吧,肯定是要區分開的。

因此,實際開發中文件肯定是要分組的。

分組其實很簡單,SwaggerIOC中注入一個Docket即為一個組的文件,其中有個groupName()方法指定分組的名稱。

因此只需要注入多個Docket指定不同的組名即可,當然,這些文件的標題、描述、掃描的路徑都是可以不同定製的。

如下配置兩個Docket,分為前臺和後臺,配置類如下:

@EnableOpenApi
@Configuration
@EnableConfigurationProperties(value = {SwaggerProperties.class})
public class SwaggerConfig {
  /**
     * 配置屬性
     */
    @Autowired
    private SwaggerProperties properties;

    @Bean
    public Docket frontApi() {
        return new Docket(DocumentationType.OAS_30)
                //是否開啟,根據環境配置
                .enable(properties.getFront().getEnable())
                .groupName(properties.getFront().getGroupName())
                .apiInfo(frontApiInfo())
                .select()
                //指定掃描的包
                .apis(RequestHandlerSelectors.basePackage(properties.getFront().getBasePackage()))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 前臺API資訊
     */
    private ApiInfo frontApiInfo() {
        return new ApiInfoBuilder()
                .title(properties.getFront().getTitle())
                .description(properties.getFront().getDescription())
                .version(properties.getFront().getVersion())
                .contact(    //新增開發者的一些資訊
                        new Contact(properties.getFront().getContactName(), properties.getFront().getContactUrl(),
                                properties.getFront().getContactEmail()))
                .build();
    }
    
    /**
     * 後臺API
     */
    @Bean
    public Docket backApi() {
        return new Docket(DocumentationType.OAS_30)
                //是否開啟,根據環境配置
                .enable(properties.getBack().getEnable())
                .groupName("後臺管理")
                .apiInfo(backApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(properties.getBack().getBasePackage()))
                .paths(PathSelectors.any())
                .build();
    }
    
    /**
     * 後臺API資訊
     */
    private ApiInfo backApiInfo() {
        return new ApiInfoBuilder()
                .title(properties.getBack().getTitle())
                .description(properties.getBack().getDescription())
                .version(properties.getBack().getVersion())
                .contact(    //新增開發者的一些資訊
                        new Contact(properties.getBack().getContactName(), properties.getBack().getContactUrl(),
                                properties.getBack().getContactEmail()))
                .build();
    }
    
}

屬性配置檔案SwaggerProperties如下,分為前臺和後臺兩個不同屬性的配置:

/**
 * swagger的屬性配置類
 */
@ConfigurationProperties(prefix = "spring.swagger")
@Data
public class SwaggerProperties {

    /**
     * 前臺介面配置
     */
    private SwaggerEntity front;

    /**
     * 後臺介面配置
     */
    private SwaggerEntity back;

    @Data
    public static class SwaggerEntity {
        private String groupName;
        private String basePackage;
        private String title;
        private String description;
        private String contactName;
        private String contactEmail;
        private String contactUrl;
        private String version;
        private Boolean enable;
    }
}

此時的文件截圖如下,可以看到有了兩個不同的分組:

如何新增授權資訊?

現在專案API肯定都需要許可權認證,否則不能訪問,比如請求攜帶一個TOKEN

在Swagger中也是可以配置認證資訊,這樣在每次請求將會預設攜帶上。

Docket中有如下兩個方法指定授權資訊,分別是securitySchemes()securityContexts()。在配置類中的配置如下,在構建Docket的時候設定進去即可:


    @Bean
    public Docket frontApi() {
        RequestParameter parameter = new RequestParameterBuilder()
                .name("platform")
                .description("請求頭")
                .in(ParameterType.HEADER)
                .required(true)
                .build();
        List<RequestParameter> parameters = Collections.singletonList(parameter);
        return new Docket(DocumentationType.OAS_30)
                //是否開啟,根據環境配置
                .enable(properties.getFront().getEnable())
                .groupName(properties.getFront().getGroupName())
                .apiInfo(frontApiInfo())
                .select()
                //指定掃描的包
                .apis(RequestHandlerSelectors.basePackage(properties.getFront().getBasePackage()))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    /**
     * 設定授權資訊
     */
    private List<SecurityScheme> securitySchemes() {
        ApiKey apiKey = new ApiKey("BASE_TOKEN", "token", In.HEADER.toValue());
        return Collections.singletonList(apiKey);
    }

    /**
     * 授權資訊全域性應用
     */
    private List<SecurityContext> securityContexts() {
        return Collections.singletonList(
                SecurityContext.builder()
                        .securityReferences(Collections.singletonList(new SecurityReference("BASE_TOKEN", new AuthorizationScope[]{new AuthorizationScope("global", "")})))
                        .build()
        );
    }

以上配置成功後,在Swagger文件的頁面中將會有Authorize按鈕,只需要將請求頭新增進去即可。如下圖:

如何攜帶公共的請求引數?

不同的架構可能發請求的時候除了攜帶TOKEN,還會攜帶不同的引數,比如請求的平臺,版本等等,這些每個請求都要攜帶的引數稱之為公共引數。

那麼如何在Swagger中定義公共的引數呢?比如在請求頭中攜帶。

Docket中的方法globalRequestParameters()可以設定公共的請求引數,接收的引數是一個List<RequestParameter>,因此只需要構建一個RequestParameter集合即可,如下:

@Bean
public Docket frontApi() {
   //構建一個公共請求引數platform,放在在header
   RequestParameter parameter = new RequestParameterBuilder()
      //引數名稱
      .name("platform")
      //描述
      .description("請求的平臺")
      //放在header中
      .in(ParameterType.HEADER)
      //是否必傳
      .required(true)
      .build();
      //構建一個請求引數集合
      List<RequestParameter> parameters = Collections.singletonList(parameter);
        return new Docket(DocumentationType.OAS_30)
                .....
                .build()
                .globalRequestParameters(parameters);
    }

以上配置完成,將會在每個介面中看到一個請求頭,如下圖:

粗略是一個BUG

作者在介紹自動配置類的時候提到了一嘴,現在來簡單分析下。

OpenApiAutoConfiguration這個自動配置類中已經匯入OpenApiDocumentationConfiguration這個配置類,如下一段程式碼:

@Import({
    OpenApiDocumentationConfiguration.class,
    ......
})

@EnableOpenApi的原始碼如下:

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = {java.lang.annotation.ElementType.TYPE})
@Documented
@Import(OpenApiDocumentationConfiguration.class)
public @interface EnableOpenApi {
}

從原始碼可以看出:@EnableOpenApi這個註解的作用就是匯入OpenApiDocumentationConfiguration這個配置類,納尼???

既然已經在自動配置類OpenApiAutoConfiguration匯入了,那麼無論需不需要在配置類上標註@EnableOpenApi註解不都會開啟Swagger支援嗎?

測試一下:不在配置類上標註@EnableOpenApi這個註解,看看是否Swagger執行正常。結果在意料之中,還是能夠正常執行。

總結:作者只是大致分析了下,這可能是個BUG亦或是後續有其他的目的,至於結果如此,不想驗證了,沒什麼意思。

總結

這篇文章也是嚐了個鮮,個人感覺不太香,有點失望。你喜歡嗎?

Spring Boot 整合的原始碼已經上傳,需要的朋友公號回覆關鍵詞Swagger3.0獲取。點選前往

相關文章