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 格式的数据。
- 因为两个方法的返回值为字符串,所以最终 SpringMVC 会使用 RequestResponseBodyMethodProcessor 来处理此返回值。
- 在这个过程中,根据返回值类型和 contentType,最终选择使用 StringHttpMessageConverter 这个转换器,但是它的默认编码是 ISO-8859-1,不是 UTF-8,所以会造成乱码。
SpringBoot 自动配置 HttpMessageConverters 的流程
- 通过 HttpMessageConvertersAutoConfiguration 来自动配置一个 UTF-8 编码的 StringHttpMessageConverter。
- HttpMessageConverters 会加载所有 HttpMessageConverter 实现类。
- WebMvcAutoConfigurationAdapter 配置类会使用 HttpMessageConverters 实例,将它的 converters 添加到总的列表中。
- 触发点为 DelegatingWebMvcConfiguration 的 configureMessageConverters() 方法,而它又是在 创建RequestMappingHandlerAdapter 这个 Bean 时被调用的,具体为 WebMvcConfigurationSupport 的 requestMappingHandlerAdapter() 方法。
所以,
- 如果我们项目中自己定义了 HttpMessageConverters,那么就没有编码为 UTF-8 的 StringHttpMessageConverter 转换器了。
- 如果我们自己定义了 WebMvcConfigurationSupport 的继承类,那么就会提前初始化它的 messageConverters 列表(getMessageConverters()),在 DelegatingWebMvcConfiguration 这个 Bean 之前执行,就会忽略所有 WebMvcConfigurer 的 configureMessageConverters() 方法调用了(包括 WebMvcAutoConfigurationAdapter 类)。这种情况也会造成 UTF-8 编码的 StringHttpMessageConverter 转换器的缺少。
总结
- 不要在项目中自定义 HttpMessageConverters,如果想添加自己的转换器,可以实现 HttpMessageConverter 或者继承 AbstractHttpMessageConverter,并配置为 Bean 就可以了,或者实现 WebMvcConfigurer 并重写 configureMessageConverters() 方法也可以。
- 不要自定义 WebMvcConfigurationSupport,如果想添加拦截器,实现 WebMvcConfigurer 并重写 addInterceptors() 方法就可以了。
参考
SpringBoot集成Swagger3.0(详细)
SpringBoot 集成 Swagger踩坑记录
Swagger3 注解使用(Open API 3)