快速接入例子 Swagger 官方文档

:::info 这里暂不记录入门配置,只记录一些相对有需求的针对性配置 :::

Model 名称生成

  1. @ApiModel
  2. public class AccountSearchReq extends PageQuery {
  3. @ApiModelProperty("邮箱")
  4. @Size(max = 50)
  5. private String email;

使用 @ApiModel 作用的类的相关信息会出现在 Swagger 对应的接口上
image.png
但是当你有相同的 类名 时(不同包,都被 @ApiModel 作用时),对应接口里面的信息就不一定是实际接口上匹配的了。

上图实际接口对应的类,属性没有这么多,这个多属性的实际上是另一个接口的

造成这个的问题原因是:Swagger 的默认起名策略是类名(Class.getSimpleName()),我们有三种办法解决这个问题:

  1. 手动命名成不同名的类
  2. @ApiModel中自定义名称:这种方式很简单,@ApiModel 的 value 就是自定义名称,如 @ApiModel("A 模块 - 搜索请求")
  3. 使用插件功能 TypeNameProviderPlugin自定义名称

这里主要讲解第三种,配置一次,所有的类都走这个策略,其实也很简单,步骤如下:

  1. 实现 springfox.documentation.spi.schema.TypeNameProviderPlugin接口
  2. 交给 Spring 容器

实现 TypeNameProviderPlugin

  1. package cn.mrcode.autoconfig;
  2. import org.springframework.core.annotation.Order;
  3. import springfox.documentation.spi.DocumentationType;
  4. import springfox.documentation.spi.schema.TypeNameProviderPlugin;
  5. import springfox.documentation.swagger.common.SwaggerPluginSupport;
  6. /**
  7. * @author mrcode
  8. * @date 2022/11/2 17:50
  9. */
  10. @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER - 100)
  11. public class MyTypeNameProviderPlugin implements TypeNameProviderPlugin {
  12. @Override
  13. public String nameFor(Class<?> type) {
  14. // 这里是 model 的类的 class
  15. // 直接返回全路径的限定类名称
  16. return type.getName();
  17. }
  18. @Override
  19. public boolean supports(DocumentationType delimiter) {
  20. // 说一些条件判定,是否支持这个文档(文档概念可以参考官方文档,一般项目是用不上的)
  21. return true;
  22. }
  23. }

交给 Spring 容器

  1. package cn.mrcode.autoconfig;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.stereotype.Component;
  4. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  5. import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
  6. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  7. import springfox.documentation.builders.ApiInfoBuilder;
  8. import springfox.documentation.builders.RequestHandlerSelectors;
  9. import springfox.documentation.service.ApiInfo;
  10. import springfox.documentation.spi.DocumentationType;
  11. import springfox.documentation.spi.schema.TypeNameProviderPlugin;
  12. import springfox.documentation.spring.web.plugins.Docket;
  13. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  14. @EnableSwagger2 // http://localhost:11000/swagger-ui/index.html
  15. @Component
  16. public class SwaggerUiWebMvcConfigurer implements WebMvcConfigurer {
  17. @Override
  18. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  19. registry.
  20. addResourceHandler("/swagger-ui/**")
  21. .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
  22. .resourceChain(false);
  23. }
  24. @Override
  25. public void addViewControllers(ViewControllerRegistry registry) {
  26. registry.addViewController("/swagger-ui/")
  27. .setViewName("forward:/swagger-ui/index.html");
  28. }
  29. @Bean
  30. public Docket customDocket() {
  31. return new Docket(DocumentationType.SWAGGER_2)
  32. // 修正 Byte 类型被识别为 string 类型的问题
  33. .directModelSubstitute(Byte.class, Integer.class)
  34. .select()
  35. .apis(RequestHandlerSelectors.basePackage("cn.mrcode.web.controller"))
  36. .build()
  37. .apiInfo(apiInfo());
  38. }
  39. ApiInfo apiInfo() {
  40. return new ApiInfoBuilder()
  41. .title("系统名称")
  42. .description("" +
  43. "<h4>携带 accessToken 的两种方式:</h4>" +
  44. "\n 1. 在 url 中使用参数形式 access_token" +
  45. "\n 2. 在请求头中使 Authorization: bearer {{access_token}} 形式"
  46. )
  47. .version("1.0.0")
  48. .build();
  49. }
  50. @Bean
  51. public TypeNameProviderPlugin typeNameProviderPlugin() {
  52. return new MyTypeNameProviderPlugin();
  53. }
  54. }

重启之后就能看到 Model 名称改变了,如下图所示
image.png

方案原理

官方文档的插件中有提到过这个插件,它的作用就是 用于覆盖 Model 的名称

在源码中是在 springfox.documentation.schema.TypeNameExtractor 被处理收集的。
springfox.documentation.swagger.schema.ApiModelTypeNameProvider 是 Swagger 提供生成 Model 默认的名称生成类,也会被注册到 extractor 中去,但是它使用了 @Order 来排序,数字越小的会先执行,执行之后,后续的插件不会走了。所以我们在实现自己的插件的时候,需要设置比框架默认的插件数字要小,比如前面就设置的是 @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER - 100)