Interface documentation is always annoying, and I have tried using Postman to write and share project documentation, and it felt fine. But lately projects are tight and I don’t have extra time to spend on it, which led to my plan to try YApi (another kind of documentation) to go down the drain. Well, there is no faster and more foolproof tool than Swagger, although it has serious code pollution. I’ll take this for a while and play with YApi in my free time.

Swagger3 integration

The latest version of Swagger is 3.0.0 , and integrating Swagger3 in a Spring Boot application is much simpler than the old Swagger2. It provides a Starter component.

1
2
3
4
5
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

That’s all it takes, isn’t it?

As for some tutorials that say you have to turn on the annotation @EnableOpenApi, you don’t need it at all. Because under springfox-boot-starter-3.0.0.jar you can find a spring.facts, which anyone familiar with Spring Boot knows is a Spring Boot-specific SPI file that automatically discovers and registers the configuration of the Starter component. There is this configuration inside.

1
2
3
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration

Follow the trail and find the general configuration class OpenApiAutoConfiguration.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@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 {

}

Some findings

We found a key place where the @ConditionalOnProperty annotation declares that configuration is enabled when springfox.documentation.enabled is true, and the default value is true. This is very useful, Swagger is only recommended for development, and this is just the right switch. Sometimes it’s better to add this switch to our custom configuration as well.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 自定义swagger3文档信息
@Configuration
@ConditionalOnProperty(value = "springfox.documentation.enabled", havingValue = "true", matchIfMissing = true)
public class Swagger3Config {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Swagger3接口文档")
                .description("更多请咨询felord.cn")
                .contact(new Contact("码农小胖哥", "https://felord.cn", "dax@felord.cn"))
                .version("1.0.0")
                .build();
    }
}

At the beginning we mentioned that Swagger3 does not need to be enabled with @EnableOpenApi or @EnableSwagger2, and the answer can be found here.

1
2
3
@Import(OpenApiDocumentationConfiguration.class)
public @interface EnableOpenApi {
}
1
2
3
@Import(Swagger2DocumentationConfiguration.class)
public @interface EnableSwagger2 {
}

Both of the above import classes can be found in OpenApiAutoConfiguration, so Swagger3 provides a fully automated integration.

Incompatibility with global unified parameters

If you use a uniform return body wrapper to standardize the uniform return of Spring MVC interfaces.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * 返回体统一封装器
 *
 * @author n1
 */
@RestControllerAdvice 
public class RestBodyAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return !returnType.hasMethodAnnotation(IgnoreRestBody.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        if (body == null) {
            return RestBody.ok();
        }
        if (Rest.class.isAssignableFrom(body.getClass())) {
            return body;
        }
        return RestBody.okData(body);
    }
}

You will find that Swagger3 will report Unable to infer base url...... error, this is because the uniform return body affects some built-in interfaces of Swagger3. The solution is @RestControllerAdvice to control the scope of the package in effect, that is, to configure its basePackages parameter on the line, this potential conflict wasted me more than an hour.

Security framework

If you use the security framework, Swagger3’s built-in interface will have restricted access and we need to exclude it. If you use Spring Security you can configure it like this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Override
public void configure(WebSecurity web) throws Exception {
    //忽略swagger3所需要用到的静态资源,允许访问
    web.ignoring().antMatchers( "/swagger-ui.html",
            "/swagger-ui/**",
            "/swagger-resources/**",
            "/v2/api-docs",
            "/v3/api-docs",
            "/webjars/**");
}

If you are using Spring Security 5.4, you can customize WebSecurity this way.

1
2
3
4
5
@BeanWebSecurityCustomizer swaggerWebSecurityCustomizer() {    
    return (web) -> {       
        web.ignoring().antMatchers(new String[]{"/swagger-ui.html", "/swagger-ui/**", "/swagger-resources/**", "/v2/api-docs", "/v3/        api-docs", "/webjars/**"});    
        };
}

This way Swagger can be rendered and accessed properly.

Summary

I shared some swagger3 configuration tips today, and hope to help you get started with the latest swagger3 documentation tool.

Reference https://felord.cn/swagger3.html