Spring Boot - 自动生成接口文档

前言

在目前主流的前后端分离项目中,桥接前后端的就是接口,因此,一份简洁易懂的接口文档就显得非常重要了。幸运的是,我们不必手动去编写这些接口文档,市面上已有许多成熟的第三方库可以自动为项目生成接口文档,在 Spring Boot 中,最常使用的接口文档自动生成库就是 Swagger。

本篇博文主要介绍在 Spring Boot 中集成 Swagger 3 的方法。

几个概念释义

  • OpenAPIOpenAPI规范(以前也被称为Swagger规范)制定了一份标准的对 REST API 接口的描述格式,具体的描述信息包含如下几方面:

    1. 可用终端接口(/user)及其各接口对应的操作(GET /user, POST /user
    2. 每个操作的输入、输出参数描述
    3. 认证方法
    4. 联系方式,许可证,使用条款等其他信息

    API规范 可以使用YAMLJSON格式进行描述,对于人和机器来说都是阅读友好的。

  • SwaggerSwagger是围绕OpenAPI规范构建的一系列开源工具,可以帮助我们设计、构建、记录和使用 REST API。主要的工具包含如下:

    1. Swagger Editor:可以在浏览器上编辑OpenAPI规范。
    2. Swagger UI:将OpenAPI规范渲染成可交互 API 接口文档。
    3. Swagger Codegen:依据OpenAPI规范文件生成服务器存根和客户端库。

更多详细信息,请参考官网:Specification

简单来说,OpenAPI就是定义描述 REST API 的规范,而Swagger就是对OpenAPI规范的实现。

基本使用

在 Spring Boot 中集成 Swagger 3,步骤如下:

  1. pom.xml中导入依赖:

    
        io.springfox
        springfox-boot-starter
        3.0.0
    
    
  2. 依赖导入完成后,直接在浏览器输入以下网址:

    http://localhost:8080/swagger-ui/
    

    此时就可以直接看到项目接口文档了。

  3. (可选)Swagger 3 提供了一些注解,可以让我们自定义接口描述信息。相关的注解如下表所示:

    :Swagger 3 提供的注解与 Swagger2 名称不同,下表列举了其对应关系:

    Swagger 2 Swagger 3 (OpenAPI 3) 注解位置
    @Api @Tag(name = "接口类描述") Controller类上
    @ApiOperation @Operation(summary = "接口方法描述") Controller方法上
    @ApiImplicitParams @Parameters Controller方法上
    @ApiImplicitParam @Parameter(description=“参数描述”) @Paramseters内部
    @ApiParam @Parameter(description=“参数描述”) Controller方法参数上
    @ApiIgnore @Parameter(hidden = true)@Operation(hidden = true)@Hidden -
    @ApiModel @Schema DTO 类上
    @ApiModelProperty @Schema DTO 属性上

    一个简单的示例如下所示:

    @RestController
    @RequestMapping("/user")
    @Tag(name = "用户接口")
    public class UserApi {
    
        @PostMapping
        @Operation(summary = "添加用户")
        public String addUser(@RequestBody User user) {
            //...
        }
    
        @GetMapping("/all")
        @Operation(description = "获取所有用户")
        public List getAllUsers() {
            //...
        }
    }
    

可以看到,Swagger 3 的使用还是非常简单的。

自定义配置

如果需要更细致的自定义配置,我们可以自定义一个配置类,然后注入一个Docket数据实例,自定义配置 Swagger。

以下列举几种常见的配置示例:

  1. 配置文档相关信息:

    @Configuration
    @ConditionalOnProperty(value = "springfox.documentation.enabled", havingValue = "true", matchIfMissing = true)
    public class SwaggerConfig {
        @Bean
        public Docket docket(){
            return new Docket(DocumentationType.OAS_30)
                    // 配置接口相关信息
                    .apiInfo(apiInfo())
                    // 选择哪些接口作为 swagger 的 doc 发布
                    .select()
                    .build();
        }
    
        private ApiInfo apiInfo(){
            return new ApiInfoBuilder()
                    .title("XX项目接口文档")
                    .description("XX项目描述")
                    .contact(new Contact("作者", "作者URL", "作者Email"))
                    .version("1.0")
                    .build();
        }
    }
    
  2. 配置包扫描路径:

    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                //apis: 添加swagger接口提取范围
                // 指定扫描包
                .apis(RequestHandlerSelectors.basePackage("com.yn.controller"))
                // 指定扫描方法注解
                // .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                // 所有路径
                .paths(PathSelectors.any())
                .build();
    }
    
  3. Api 分组:默认情况下,Swagger 将扫描到的接口都归属于default组,我们可以通过对每个接口路径(/public/admin)各自配置一个Docket,显式设置其分组:

    @Bean
    public Docket publicApi() {
        return new Docket(DocumentationType.OAS_30)
                .groupName("api-public")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.yn.controller.open"))
                // localhost:8080/public
                .paths(PathSelectors.regex("/public.*"))
                .build();
    }
    
    @Bean
    public Docket privateApi() {
        return new Docket(DocumentationType.OAS_30)
                .groupName("api-admin")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.yn.controller.admin"))
                .paths(PathSelectors.regex("/admin.*"))
                .build();
    }
    
  4. 请求头添加 token:越来越多的项目采用前后端分离架构,此时经常使用 token 来作为鉴权机制,因此前端每次请求都必须携带上 token,我们可以配置下 Swagger,让其每次请求自动携带我们设置的 token,只需对相应Docket进行配置即可,如下所示:

    @Bean
    public Docket addJwtToken() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .securitySchemes(Collections.singletonList(HttpAuthenticationScheme.JWT_BEARER_BUILDER
                         // 显示用
                        .name("JWT")
                        .build()))
                .securityContexts(Collections.singletonList(SecurityContext.builder()
                        .securityReferences(Collections.singletonList(SecurityReference.builder()
                                .scopes(new AuthorizationScope[0])
                                .reference("JWT")
                                .build()))
                        // 声明作用域
                        .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
                        .build()))
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();
    }
    

    配置完成后,打开该Docker配置对应的页面,就可以看到Authorize的按钮,如下图所示:

    Authorize

    点击该按钮,手动输入 token,最后点击Authorize按钮确认即可,如下图所示:

    Enter Token

Swagger 更多配置选项,请参考官方文档:springfox

其他注意事项

Swagger 在使用过程中,有一些事项可以注意一下,避免出现问题。比如:

  • 区分环境:通常情况下,Swagger 只在开发环境或测试环境下开启,在生产环境下必须进行关闭。可以通过在配置文件application.properties中配置使能或失能 Swagger:

    # 生产环境失能 Swagger
    springfox.documentation.enabled=false
    # 或者
    springfox.documentation.swagger-ui.enabled=false
    

    :在springfox-boot-starter.jar包中,我们可以找到/META-INF/spring.factories配置文件,其内容如下:

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

    可以看到,Swagger 的自动配置文件类为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 {
        public OpenApiAutoConfiguration() {
        }
    }
    

    这里我们主要关注@ConditionalOnProperty,可以看到,当springfox.documentation.enabled设置为true(缺省默认也为true)时,才会加载OpenApiAutoConfiguration自动配置类。因此,这里也是为什么我们前面自定义配置类SwaggerConfig也带上这个配置,这样可以确保在springfox.documentation.enabled=false时,我们的自定义配置类SwaggerConfig也不会被加载。

    :Spring Boot 多环境配置方法可参考文章:Spring Boot - 多环境配置

  • 安全框架放行:如果项目中使用了 Spring Security 这种权限认证框架,应当注意要把 Swagger 添加到白名单中:

    @Configuration
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            String[] SWAGGER_WHITELIST = {
                    "/swagger-ui.html",
                    "/swagger-ui/*",
                    "/swagger-resources/**",
                    "/v2/api-docs",
                    "/v3/api-docs",
                    "/webjars/**"
            };
            web.ignoring().antMatchers(SWAGGER_WHITELIST);
        }
    }
    
  • 统一数据下发异常:如果项目中使用了@RestControllerAdvice拦截所有接口请求,那么 Swagger 的内置接口也同样会被拦截修改,导致Unable to infer base url错误,此时,只需为@RestControllerAdvice设置拦截指定包目录即可,如下所示:

    // 只拦截 com.yn.controller 包
    @RestControllerAdvice(basePackages = {"com.yn.controller"})
    public class FormatResponseBodyAdvice implements ResponseBodyAdvice {...}
      
      
  • @EnableWebMvc异常:当项目中使用了@EnableWebMvc注解后,会导致 Swagger 无法访问。原因是在 Spring Boot 中,注解在配置类(即@Configuration)类上的@EnableWebMvc会完全掌控 SpringMVC 配置,导致 Spring Boot 对 SpringMVC 的自动配置失效(即不加载自动配置),从而间接影响到了 Swagger。解决该问题的方法有很多,这里列举几种:

    1. 移除@EnableWebMvc:对于 Spring Boot 项目,通常不建议在配置类(@Configuration)上直接使用@EnableWebMvc,很多对 SpringMVC 的配置,可以直接搜索 Spring Boot 对应的配置选项即可,大多数情况下无需直接配置原生 SpringMVC。
    2. 添加视图解析器ViewResolver:使用@EnableWebMvc后,SpringMVC 中,内置的视图解析器无法对 Swagger 的视图进行解析,因此手动为DispatcherServlet添加 Spring 内置的视图解析器即可:
    @Configuration
    @EnableWebMvc
    public class WebConfiguration implements WebMvcConfigurer {
    
        @Override
        public void configureViewResolvers(ViewResolverRegistry registry) {
            registry.viewResolver(new InternalResourceViewResolver());
        }
    }
    

    :可单步调式DispatcherServlet,在DispatcherServlet#resolveViewName方法内就是对视图进行解析的过程,此处可查看到DispatcherServlet具体所使用到的ViewResolver

  • 参考

    • Swagger3 注解使用(Open API 3)
    • Swagger3就是比2简单粗暴

    你可能感兴趣的:(Spring Boot - 自动生成接口文档)