swagger3.0使用及踩坑

前言

OpenAPI阶段的Swagger也被称为Swagger 3.0。在Swagger 2.0后,Swagger规范正式更名为OpenAPI规范,并且根据OpenAPI规范的版本号进行了更新。因此,Swagger 3.0对应的就是OpenAPI 3.0版本,它是Swagger在OpenAPI阶段推出的一个重要版本。与前几个版本相比,Swagger 3.0更加强调对RESTful API的支持和规范化,提供了更丰富和灵活的定义方式,并且可以用于自动生成文档、客户端代码、服务器代码和测试工具等。

SpringFox工具(不推荐)

Springfox是一套可以帮助Java开发者自动生成API文档的工具,它是基于Swagger 2.x基础上开发的。Swagger已经成为了RESTful API文档生态系统的事实标准,而Springfox是一个用于集成Swagger2.x到Spring应用程序中的库。而且Springfox提供了一些注解来描述API接口、参数和返回值,并根据这些信息生成Swagger UI界面,从而方便其他开发人员查看和使用您的API接口。此外,Springfox还支持自动生成API文档和代码片段,简化了开发人员的工作量。

注意:随着时间的推移,Swagger2.x终究成为历史,所以我们可以看出springfox-boot-starter的坐标从3.0.0版本(2020年7月14日)开始就一直没有更新;也要注意的是springfox-swagger2坐标和springfox-boot-start是一样的,但springfox-boot-start只有3.0.0版本。Springfox不支持swagger3.0的注解。

简单使用

引入依赖

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

启用配置

@Configuration
@EnableOpenApi
public class Swagger3Config {

  /**
   * swagger配置
   */
  @Bean
  public Docket api() {
    return new Docket(DocumentationType.OAS_30)
        .select()
        .apis(RequestHandlerSelectors.basePackage("com.imooc.spring.web")) //扫描包路径
        .paths(PathSelectors.any())
        .build()
        .apiInfo(apiInfo())
        .enable("true".equals(swaggerEnable)); // 是否启用,我们可以使用这个属性关闭生产环境的swagger文档
  }

  // 文档的一些描述信息
  private ApiInfo apiInfo() {
    return new ApiInfo(
        "接口文档", "", "1.0", "",
        new Contact("strongmore", "", "xxx@163.com"),
        "strongmore", "", Collections.emptyList());
  }
}

@EnableOpenApi 注解替代 swagger2 的 @EnableSwagger2 注解,创建 Docket 时使用 DocumentationType.OAS_30,而不是之前的 DocumentationType.SWAGGER_2。其他注解如 @ApiModel 使用方式都一样。

页面访问路径为 http://localhost:8090/cnblogs/swagger-ui/index.html,之前的 swagger2 路径为 http://localhost:8090/cnblogs/swagger-ui.html

感觉和 swagger2 的页面没有太大区别。

SpringDoc工具(推荐)

SpringDoc对应坐标是springdoc-openapi-ui,它是一个集成Swagger UI和ReDoc的接口文档生成工具,在使用上与springfox-boot-starter类似,但提供了更为灵活、功能更加强大的工具。其中除了可以生成Swagger UI风格的接口文档,还提供了ReDoc的文档渲染方式,可以自动注入OpenAPI规范的JSON描述文件,支持OAuth2、JWT等认证机制,并且支持全新的OpenAPI 3.0规范。

SpringDoc是有着更加先进的技术架构和更好的扩展性,使得其逐渐取代了springfox-boot-starter工具包,成为了当前Spring Boot生态中最受欢迎的API文档工具之一。同时springdoc-openapi-ui还拥有更为完善的开发文档和社区支持,从而吸引了越来越多的开发者加入到这个项目中。

注意:SpringDoc不兼容swagger2的注解

简单使用

引入依赖

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.6.7</version>
</dependency>

启用配置

@Configuration
public class Swagger3Config {

    @Bean
    public OpenAPI customOpenAPI() {
        Contact contact = new Contact()
                .name("strongmore")                             // 作者名称
                .email("xxx@qq.com")                            // 作者邮箱
                .url("https://www.cnblogs.com/strongmore/")     // 介绍作者的URL地址
                .extensions(Collections.emptyMap());            // 使用Map配置信息(如key为"name","email","url")

        Info info = new Info()
                .title("接口文档")                               // Api接口文档标题(必填)
                .description("接口文档")                         // Api接口文档描述
                .version("1.2.1")                               // Api接口版本
                .contact(contact);                              // 设置联系人信息
        return new OpenAPI()
                .openapi("3.0.1")                               // Open API 3.0.1(默认)
                .info(info);                                    // 配置Swagger3.0描述信息
    }
}

swagger2 和 swagger3 的注解的区别

swagger2 swagger3 注解位置
@Api @Tag(name) Controller类上
@ApiOperation @Operation(summary) Controller方法上
@ApiImplicitParams @Parameters Controller方法上
@ApiImplicitParam @Parameter(description) Controller方法上
@ApiParam @Parameter(description) Controller方法参数上
@ApiIgnore @Parameter(hidden=true) 或 @Operation(hidden=true) 或 @Hidden 类或方法或参数上
@ApiModel @Schema 实体类上
@ApiModelProperty @Schema 实体类属性上

遇到的问题

问题1
@Schema(description = "测试对象信息")
@Data
@Accessors(chain = true)
public class TestObjectInfo {
    @Schema(description = "商品ID")
    private String goodsId;
    @Schema(description = "商品名称")
    @JsonProperty("pName")
    private String pName;
}

对于属性中第二个字符为大写的属性名称比如pName,swagger会将其转换为 pname,且会丢失 @Schema 注解信息。通过添加 @JsonProperty 注解可以解决此问题,这是因为它底层依赖 jackson 这个 json 库,具体源码可以看 ModelResolver 类。

问题2

swagger3.0 对 Date,LocalTime 等类型支持不是很好,会忽略example。

@Schema(description = "创建时间",example = "2024-04-01",format = "yyyy-MM-dd")
private Date createDate;
问题3

页面乱码问题

swagger3.0 中的 OpenApiWebMvcResource 提供了 /v3/api-docs/v3/api-docs.yaml 两个地址来分别返回 json 格式和 yaml 格式的数据。

  1. 因为两个方法的返回值为字符串,所以最终 SpringMVC 会使用 RequestResponseBodyMethodProcessor 来处理此返回值。
  2. 在这个过程中,根据返回值类型和 contentType,最终选择使用 StringHttpMessageConverter 这个转换器,但是它的默认编码是 ISO-8859-1,不是 UTF-8,所以会造成乱码。

SpringBoot 自动配置 HttpMessageConverters 的流程

  1. 通过 HttpMessageConvertersAutoConfiguration 来自动配置一个 UTF-8 编码的 StringHttpMessageConverter。
  2. HttpMessageConverters 会加载所有 HttpMessageConverter 实现类。
  3. WebMvcAutoConfigurationAdapter 配置类会使用 HttpMessageConverters 实例,将它的 converters 添加到总的列表中。
  4. 触发点为 DelegatingWebMvcConfiguration 的 configureMessageConverters() 方法,而它又是在 创建RequestMappingHandlerAdapter 这个 Bean 时被调用的,具体为 WebMvcConfigurationSupport 的 requestMappingHandlerAdapter() 方法。

所以,

  1. 如果我们项目中自己定义了 HttpMessageConverters,那么就没有编码为 UTF-8 的 StringHttpMessageConverter 转换器了。
  2. 如果我们自己定义了 WebMvcConfigurationSupport 的继承类,那么就会提前初始化它的 messageConverters 列表(getMessageConverters()),在 DelegatingWebMvcConfiguration 这个 Bean 之前执行,就会忽略所有 WebMvcConfigurer 的 configureMessageConverters() 方法调用了(包括 WebMvcAutoConfigurationAdapter 类)。这种情况也会造成 UTF-8 编码的 StringHttpMessageConverter 转换器的缺少。

总结

  1. 不要在项目中自定义 HttpMessageConverters,如果想添加自己的转换器,可以实现 HttpMessageConverter 或者继承 AbstractHttpMessageConverter,并配置为 Bean 就可以了,或者实现 WebMvcConfigurer 并重写 configureMessageConverters() 方法也可以。
  2. 不要自定义 WebMvcConfigurationSupport,如果想添加拦截器,实现 WebMvcConfigurer 并重写 addInterceptors() 方法就可以了。

参考

SpringBoot集成Swagger3.0(详细)
SpringBoot 集成 Swagger踩坑记录
Swagger3 注解使用(Open API 3)

posted @ 2024-04-16 19:09  strongmore  阅读(8078)  评论(0编辑  收藏  举报