swagger文档分版本展示

363 阅读2分钟
  1. 背景
    日常前后端分离开发中,由于项目中接口众多,有时候前后端联调接口查看不方便,以及每个产品版本的接口不能更加直观的查看。

  2. swagger介绍
    Swagger是一个接口文档生成工具,同时提供接口测试调用的辅助功能

  3. 分版本效果展示

    1. v100版本接口
    2. v101版本接口
  4. 代码详解

    1. 好了,版本效果已经展示了,现在我们直接上干货,可以看到我们除了正常的swagger标签外,新增了一个版本@ApiVersion标签, 答案就在这个标签上
    @RestController
    @RequestMapping("/web/swaggerdemo")
    public class SwaggerDemoController {
    
        @ApiOperation(value = "测试demo1", notes = "测试demo1")
        @ApiImplicitParam(name = "version", value = "版本号, v100", example = "v100", required = true, paramType = "header", dataType = "String")
        @ApiVersion(group = {"v100"})
        @PostMapping("/demo1/{version}")
        public JsonResultAdapter<SwaggerDemoResponse> demo1(@PathVariable("version") String version) {
            if ("v100".equals(version)) {
                SwaggerDemoResponse swaggerDemoResponse = new SwaggerDemoResponse();
                swaggerDemoResponse.setDemoValue(1);
                return JsonResultAdapter.success(swaggerDemoResponse);
            }
            return JsonResultAdapter.apiError();
        }
    
        @ApiOperation(value = "测试demo2", notes = "测试demo2")
        @ApiImplicitParam(name = "version", value = "版本号, v100", example = "v100", required = true, paramType = "header", dataType = "String")
        @ApiVersion(group = {"v100", "v101"})
        @PostMapping("/demo2/{version}")
        public JsonResultAdapter<SwaggerDemoResponse> demo2(@PathVariable("version") String version) {
            if ("v101".equals(version)) {
                SwaggerDemoResponse swaggerDemoResponse = new SwaggerDemoResponse();
                swaggerDemoResponse.setDemoValue(1);
                return JsonResultAdapter.success(swaggerDemoResponse);
            }
            return JsonResultAdapter.apiError();
        }
    }
    
    1. @ApiVersion, 新增标签ApiVersion
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ApiVersion {
    
      /**
       * 接口版本号(对应swagger中的group)
       *
       * @return String[]
       */
      String[] group() default {""};
    }
    
    1. 核心配置, 我们看这段代码,通过判断接口上标签是否包含该标签来实现分版本控制,最后注册到容器中\
        @PostConstruct
        public void postProcessBeanFactory() throws BeansException {
            List<Docket> list = this.docketFactory();
            if (null != list) {
                list.forEach(o -> configurableListableBeanFactory.registerSingleton(o.getGroupName(), o));
            }
        }
    
        public Docket docketInstance(String version, String web) {
            List<ApiKey> apiKeys = apiSecurity();
            return new Docket(DocumentationType.SWAGGER_2).enable(true).apiInfo(apiInfo()).select()
                    .apis(o -> {
                        if (null != o) {
                            Optional<ApiVersion> annotation = o.findAnnotation(ApiVersion.class);
                            if (annotation.isPresent() && Arrays.asList(annotation.get().group()).contains(version)) {
                                RequestHandlerKey requestHandlerKey = o.key();
                                for (String mapping : requestHandlerKey.getPathMappings()) {
                                    if (mapping.toLowerCase().startsWith(web)) {
                                        return true;
                                    }
                                }
                            }
                        }
                        return false;
                    })
                    .paths(PathSelectors.any())
                    .build()
                    .groupName(version + "-" + "接口")
                    .ignoredParameterTypes(HttpServletResponse.class, HttpServletRequest.class)
                    .securitySchemes(apiKeys);
        }
    
        public List<Docket> docketFactory() {
            List<Docket> list = new ArrayList<>();
            List<String> versions = swaggerProperties.getVersions();
            if (!CollectionUtils.isEmpty(versions)) {
                versions.forEach(o -> {
                    list.add(this.docketInstance(o, "/web"));
                });
            }
            return list;
        }
    

    4. 其他配置类

     @ConfigurationProperties(
             prefix = "fant.swagger",
             ignoreUnknownFields = true
     )
     @Data
     public class SwaggerProperties {
    
         private boolean enable = false;
         /**
          * 分组名称是否正序排序
          */
         private boolean groupAsc = true;
         /**
          * 扫描包
          */
         private String packages = "com.fant.web";
         /**
          * 标题
          */
         private String title = "默认接口";
         /**
          * 说明
          */
         private String description = "默认访问接口";
         /**
          * 版本
          */
         private String version = "1.0.0";
         /**
          * 分组名称
          */
         private String groupName = "web-api";
         /**
          * url
          */
         private String url = "http://127.0.0.1:8080/";
         /**
          * 接口版本
          */
         private List<String> versions;
         private String serviceUrl = "http://127.0.0.1:8080/";
         private String licenseUrl = "http://127.0.0.1:8080/";
         private String authorName = "fant";
         private String authorEmail = "api@xx.com";
         private List<String> tokenKeyNames = Arrays.asList("token");
         private List<String> authKeyNames = Arrays.asList("Authorization");
         public boolean isEnable() {
             return enable;
         }
         public void setEnable(boolean enable) {
             this.enable = enable;
         }
     }
    
  5. 分组排序

    1. 上述我们已经介绍了怎么去分版本来展示接口,但是swagger默认排序是升序,这样如果版本多,就会造成我们需要下拉到最后,下面我们介绍下swagger的分组名称排序,通过查看源码得知,排序是在springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider.get()方法中进行排序
    2. 而swagger的默认排序重写的compareTo方法是根据版本,再根据名称升序排序,所以可以重写该类,然后通过参数配置随时改变分组排序