preface

Swagger 3.0 is a breakthrough change that has a lot of highlights. I don’t really believe it. Today, let’s take a look at the soup and see if it’s fresh….

What does the official document say?

The project is open source on Github at github.com/springfox/s… .

How does Swagger 3.0 change? The official document summarizes the following points:

  1. Delete thespringfox-swagger2The dependence of
  2. Delete all@EnableSwagger2...annotations
  3. addedspringfox-boot-starterdependency
  4. removedguavaAnd other third party dependencies
  5. The document access address has been changed tohttp://ip:port/project/swagger-ui/index.html.

So just looking at this, how do you feel initially?

Spring Boot can integrate Swagger 3.0 with Spring Boot.

Spring Boot version description

The author used the Spring Boot version 2.3.5.release

Add the dependent

Swagger 3.0 already has Boot integration with Spring Boot, just add the following dependencies:

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

What does Springfox-boot-starter do?

A big feature of the Swagger 3.0 main push is this launcher, so what does this launcher do?

Remember: All the initiator logic is in the auto-configuration class.

Find the auto-configuration class for Springfox-boot-starter in the/meta-INF /spring.factories file as follows:

OpenApiAutoConfiguration = OpenApiAutoConfiguration = OpenApiAutoConfiguration = 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 {}Copy the code

And this automatic configuration class didn’t dry anything, just Import a few configuration class (@ Import), and opened up the configuration properties (@ EnableConfigurationProperties).

Key: remember OpenApiDocumentationConfiguration this configuration, a preliminary opinion this is a BUG, and I don’t want to deeper, the inside of the code written really bad, don’t write comments.

Roll up your sleeves and you’re dry?

Really, it’s the same as before, really nothing much has changed, just follow the documentation step by step.

Customize a basic document example

Everything still needs to be configured manually by the configuration class. Honestly, I thought I would just do it myself in the global configuration file. Ah, too much thinking. The configuration classes are as follows:

@EnableOpenApi
@Configuration
@EnableConfigurationProperties(value = {SwaggerProperties.class})
public class SwaggerConfig {
  /** * Configure attributes */
    @Autowired
    private SwaggerProperties properties;

    @Bean
    public Docket frontApi(a) {
        return new Docket(DocumentationType.OAS_30)
                // Whether to enable the function based on the environment
                .enable(properties.getFront().getEnable())
                .groupName(properties.getFront().getGroupName())
                .apiInfo(frontApiInfo())
                .select()
                // Specify the packet to scan.apis(RequestHandlerSelectors.basePackage(properties.getFront().getBasePackage())) .paths(PathSelectors.any()) .build();  }/** * Foreground API information */
    private ApiInfo frontApiInfo(a) {
        return new ApiInfoBuilder()
                .title(properties.getFront().getTitle())
                .description(properties.getFront().getDescription())
                .version(properties.getFront().getVersion())
                .contact(    // Add some information about the developer
                        newContact(properties.getFront().getContactName(), properties.getFront().getContactUrl(), properties.getFront().getContactEmail())) .build(); }}Copy the code

@enableOpenAPI This annotation is documented as follows:

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
Copy the code

What does that mean? This annotation will only generate a Swagger document if the @enableOpenAPI annotation is used in the configuration class.

@ EnableConfigurationProperties the annotation is to open a custom attribute configuration, this is the author custom Swagger configuration.

Anyway, the same configuration as before, according to the official documentation requirements, need to add a @enableOpenAPI annotation on the configuration class.

How are documents grouped?

As we all know, a project may be divided into the foreground, background, APP side, small program side….. Each end of the interface may be the same, not all together, must be separated.

Therefore, documents are definitely grouped in real development.

Grouping is simple, Swagger injects a Docket into IOC that is a group document with a groupName() method that specifies the groupName.

Therefore, you only need to inject multiple Dockets to specify different group names. Of course, the title, description, and scan path of these documents can be customized differently.

Configure two dockets as follows: foreground and background

@EnableOpenApi
@Configuration
@EnableConfigurationProperties(value = {SwaggerProperties.class})
public class SwaggerConfig {
  /** * Configure attributes */
    @Autowired
    private SwaggerProperties properties;

    @Bean
    public Docket frontApi(a) {
        return new Docket(DocumentationType.OAS_30)
                // Whether to enable the function based on the environment
                .enable(properties.getFront().getEnable())
                .groupName(properties.getFront().getGroupName())
                .apiInfo(frontApiInfo())
                .select()
                // Specify the packet to scan.apis(RequestHandlerSelectors.basePackage(properties.getFront().getBasePackage())) .paths(PathSelectors.any()) .build();  }/** * Foreground API information */
    private ApiInfo frontApiInfo(a) {
        return new ApiInfoBuilder()
                .title(properties.getFront().getTitle())
                .description(properties.getFront().getDescription())
                .version(properties.getFront().getVersion())
                .contact(    // Add some information about the developer
                        new Contact(properties.getFront().getContactName(), properties.getFront().getContactUrl(),
                                properties.getFront().getContactEmail()))
                .build();
    }
    
    /** * background API */
    @Bean
    public Docket backApi(a) {
        return new Docket(DocumentationType.OAS_30)
                // Whether to enable the function based on the environment
                .enable(properties.getBack().getEnable())
                .groupName("Back office")
                .apiInfo(backApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(properties.getBack().getBasePackage()))
                .paths(PathSelectors.any())
                .build();
    }
    
    /** * background API information */
    private ApiInfo backApiInfo(a) {
        return new ApiInfoBuilder()
                .title(properties.getBack().getTitle())
                .description(properties.getBack().getDescription())
                .version(properties.getBack().getVersion())
                .contact(    // Add some information about the developer
                        newContact(properties.getBack().getContactName(), properties.getBack().getContactUrl(), properties.getBack().getContactEmail())) .build(); }}Copy the code

The SwaggerProperties property configuration file is as follows:

/** * Swagger attribute configuration class */
@ConfigurationProperties(prefix = "spring.swagger")
@Data
public class SwaggerProperties {

    /** * Front interface configuration */
    private SwaggerEntity front;

    /** * Background interface configuration */
    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;
        privateBoolean enable; }}Copy the code

Here is a screenshot of the document, showing two different groupings:

How do I add authorization information?

Nowadays, project apis must require permission authentication or they cannot be accessed, such as requesting a TOKEN.

Authentication information can also be configured in Swagger, so that each request will be carried by default.

There are two methods that specify authorization information in Docket, securitySchemes() and securityContexts(). In the configuration class, you can set the following configuration to the Docket construction time:


    @Bean
    public Docket frontApi(a) {
        RequestParameter parameter = new RequestParameterBuilder()
                .name("platform")
                .description("Request header")
                .in(ParameterType.HEADER)
                .required(true)
                .build();
        List<RequestParameter> parameters = Collections.singletonList(parameter);
        return new Docket(DocumentationType.OAS_30)
                // Whether to enable the function based on the environment
                .enable(properties.getFront().getEnable())
                .groupName(properties.getFront().getGroupName())
                .apiInfo(frontApiInfo())
                .select()
                // Specify the packet to scan
                .apis(RequestHandlerSelectors.basePackage(properties.getFront().getBasePackage()))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    /** * Set the authorization information */
    private List<SecurityScheme> securitySchemes(a) {
        ApiKey apiKey = new ApiKey("BASE_TOKEN"."token", In.HEADER.toValue());
        return Collections.singletonList(apiKey);
    }

    /** * Authorization information global application */
    private List<SecurityContext> securityContexts(a) {
        return Collections.singletonList(
                SecurityContext.builder()
                        .securityReferences(Collections.singletonList(new SecurityReference("BASE_TOKEN".new AuthorizationScope[]{new AuthorizationScope("global"."")})))
                        .build()
        );
    }
Copy the code

After the above configuration is successful, there will be a Authorize button in the page of Swagger document. You only need to add the request header. The diagram below:

How do I carry common request parameters?

Different architectures may send requests with tokens and different parameters, such as the platform and version of the request. These parameters are called public parameters for each request.

So how do you define common parameters in Swagger? Such as in the request header.

The globalRequestParameters() method in Docket can set the public request parameters. The received parameter is a List

, so you just need to build a collection of requestParameters as follows:

@Bean
public Docket frontApi(a) {
   // Build a public request parameter platform and place it in header
   RequestParameter parameter = new RequestParameterBuilder()
      // Parameter name
      .name("platform")
      / / description
      .description("Requested platform")
      // Put it in the header
      .in(ParameterType.HEADER)
      // Whether to upload
      .required(true)
      .build();
      // Build a set of request parameters
      List<RequestParameter> parameters = Collections.singletonList(parameter);
        return new Docket(DocumentationType.OAS_30)
                .....
                .build()
                .globalRequestParameters(parameters);
    }
Copy the code

Once the above configuration is complete, you should see a request header in each interface, as shown below:

Rough is a BUG

The author in the introduction of automatic configuration class mentioned a mouth, now to a simple analysis.

OpenApiAutoConfiguration this automatic configuration class have imported OpenApiDocumentationConfiguration the configuration class, following a piece of code:

@Import({ OpenApiDocumentationConfiguration.class, ...... })
Copy the code

The source code for @enableOpenAPI is as follows:

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

As can be seen from the source: @ EnableOpenApi this annotation is import OpenApiDocumentationConfiguration this configuration, what???

The @enableOpenAPI annotation on the OpenApiAutoConfiguration class will enable Swagger support regardless of whether it is required.

Test: Don’t annotate @enableOpenAPI on the configuration class to see if Swagger works. As expected, it worked.

Conclusion: the author just made a general analysis, this may be a BUG or other purpose, as for the result, do not want to verify, it is not interesting.

conclusion

This article also tasted a fresh, personal feeling is not very sweet, a little disappointed. Do you like it?

Spring Boot integration source code has been uploaded, need friends reply keyword Swagger3.0 obtain. Click to