:::info 这里暂不记录入门配置,只记录一些相对有需求的针对性配置 :::
Model 名称生成
@ApiModel
public class AccountSearchReq extends PageQuery {
@ApiModelProperty("邮箱")
@Size(max = 50)
private String email;
使用 @ApiModel
作用的类的相关信息会出现在 Swagger 对应的接口上
但是当你有相同的 类名 时(不同包,都被 @ApiModel
作用时),对应接口里面的信息就不一定是实际接口上匹配的了。
上图实际接口对应的类,属性没有这么多,这个多属性的实际上是另一个接口的
造成这个的问题原因是:Swagger 的默认起名策略是类名(Class.getSimpleName()
),我们有三种办法解决这个问题:
- 手动命名成不同名的类
- 在
@ApiModel
中自定义名称:这种方式很简单,@ApiModel
的 value 就是自定义名称,如@ApiModel("A 模块 - 搜索请求")
- 使用插件功能
TypeNameProviderPlugin
自定义名称
这里主要讲解第三种,配置一次,所有的类都走这个策略,其实也很简单,步骤如下:
- 实现
springfox.documentation.spi.schema.TypeNameProviderPlugin
接口 - 交给 Spring 容器
实现 TypeNameProviderPlugin
package cn.mrcode.autoconfig;
import org.springframework.core.annotation.Order;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.TypeNameProviderPlugin;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
/**
* @author mrcode
* @date 2022/11/2 17:50
*/
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER - 100)
public class MyTypeNameProviderPlugin implements TypeNameProviderPlugin {
@Override
public String nameFor(Class<?> type) {
// 这里是 model 的类的 class
// 直接返回全路径的限定类名称
return type.getName();
}
@Override
public boolean supports(DocumentationType delimiter) {
// 说一些条件判定,是否支持这个文档(文档概念可以参考官方文档,一般项目是用不上的)
return true;
}
}
交给 Spring 容器
package cn.mrcode.autoconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.TypeNameProviderPlugin;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@EnableSwagger2 // http://localhost:11000/swagger-ui/index.html
@Component
public class SwaggerUiWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.
addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/swagger-ui/")
.setViewName("forward:/swagger-ui/index.html");
}
@Bean
public Docket customDocket() {
return new Docket(DocumentationType.SWAGGER_2)
// 修正 Byte 类型被识别为 string 类型的问题
.directModelSubstitute(Byte.class, Integer.class)
.select()
.apis(RequestHandlerSelectors.basePackage("cn.mrcode.web.controller"))
.build()
.apiInfo(apiInfo());
}
ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("系统名称")
.description("" +
"<h4>携带 accessToken 的两种方式:</h4>" +
"\n 1. 在 url 中使用参数形式 access_token" +
"\n 2. 在请求头中使 Authorization: bearer {{access_token}} 形式"
)
.version("1.0.0")
.build();
}
@Bean
public TypeNameProviderPlugin typeNameProviderPlugin() {
return new MyTypeNameProviderPlugin();
}
}
方案原理
官方文档的插件中有提到过这个插件,它的作用就是 用于覆盖 Model 的名称
在源码中是在 springfox.documentation.schema.TypeNameExtractor
被处理收集的。springfox.documentation.swagger.schema.ApiModelTypeNameProvider
是 Swagger 提供生成 Model 默认的名称生成类,也会被注册到 extractor 中去,但是它使用了 @Order
来排序,数字越小的会先执行,执行之后,后续的插件不会走了。所以我们在实现自己的插件的时候,需要设置比框架默认的插件数字要小,比如前面就设置的是 @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER - 100)