介绍
- swagger是用来管理api的开源项目
- 可以用来给团队共享api文档和提供测试api接口的工具
- 文档和测试工具会随着代码的更新而更新
- 只需要很少的配置就能实现
模块
- swagger分为swagger模块和swagger-ui模块 前后端分离
版本选择
springfox
- 目前最新版本2.9.2
- 接受或返回map时 需要借助bean对象或插件(有缺陷)使接口文档中包含具体的参数和返回字段
- api ui是以上下滚动折叠框分组的形式提供的
- 不符合国人习惯
- 不过习惯吗用着用着就改变了
- 最重要的是api测试功能输入没有记忆功能
- 重新进入网页后再次测试相同的接口参数没有提示功能 这要这么搞
- 当你需要同时测试多个接口时这感觉很酸爽 因为没有面包屑 你会迷失在滚动的海洋
xiaoymin
- 核心还是使用的swagger 把swagger-ui换了 在加了些曾强功能
- 提供独立的注解来解决map问题
- ui符合国人习惯 左右分栏
- 测试有输入记忆功能
- 有面包屑需要同时请求多个接口也方便
- 对于我这种把测试接口当ui来用的人来说还是蛮好用的
使用
- 分文单应用和多应用两种情况
依赖部分
- springfox
<!-- 集成 swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!-- 集成 swagger-ui 需提供ui访问的服务引用 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
- xiaoymin
<!-- ui+服务端 --> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>2.0.2</version> </dependency> <!-- 单服务端 --> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-micro-spring-boot-starter</artifactId> </dependency>
- 注意事项
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NoSuchMethodError: com.google.common.collect.FluentIterable.append(Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable; at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:184) ~[spring-context-5.0.8.RELEASE.jar:5.0.8.RELEASE] Caused by: java.lang.NoSuchMethodError: com.google.common.collect.FluentIterable.append(Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable;
如果运行时报上面的错那就是需要引入瓜娃子
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>29.0-jre</version> </dependency>
代码部分
-
单应用
- 直接引用依赖 创建个Docket(这名字貌似很牛逼啊)交给spring管理 开启swagger
@EnableKnife4j //knife4j独有 提供增强功能 @EnableSwagger2 @Configuration @Profile({"dev","test","local","tt"}) public class SwaggerConfig { @Bean @Order(value = 1) public Docket groupRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.xiaominfo.swagger.service.user.controller")) .paths(PathSelectors.any()) .build() // 用来设置Authorization和Authorization-x用来token访问 .securityContexts(Lists.newArrayList(securityContext(),securityContext1())) .securitySchemes(Lists.<SecurityScheme>newArrayList(apiKey(),apiKey1())); } private ApiInfo apiInfo(){ return new ApiInfoBuilder() .title("api文档") .description("<div style='font-size:14px;color:red;'>api文档</div>") .termsOfServiceUrl("http://www.shangtian.com/") .contact("[email protected]") .version("1.0") .build(); } private ApiKey apiKey() { return new ApiKey("BearerToken", "Authorization", "header"); } private ApiKey apiKey1() { return new ApiKey("BearerToken1", "Authorization-x", "header"); } private SecurityContext securityContext() { return SecurityContext.builder() .securityReferences(defaultAuth()) .forPaths(PathSelectors.regex("/.*")) .build(); } private SecurityContext securityContext1() { return SecurityContext.builder() .securityReferences(defaultAuth1()) .forPaths(PathSelectors.regex("/.*")) .build(); } List<SecurityReference> defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; return Lists.newArrayList(new SecurityReference("BearerToken", authorizationScopes)); } List<SecurityReference> defaultAuth1() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; return Lists.newArrayList(new SecurityReference("BearerToken1", authorizationScopes)); } }
-
多应用
-
可以在每个应用按照单应用的来
-
但是这样一来如果有20个工程或者更多的话 访问起来这滋味应该相当的爽
-
要提供api文档的所有服务都引用swagger模块
-
需要提供访问swagger界面的服务引用swagger-ui模块 并且提供路由信息 通常为网关服务
-
如果是其他服务需要收集路由信息 可以是到网关或注册中心获取 获取广播采集 再不济采用录入方式
-
步骤为根据路由信息生成接口请求地址 -> 根据请求地址请求目标服务接口
-
这样就解决了需要访问多个服务的api时需要开多个网站的问题
-
假如现在有5个服务除了注册中心其他需要提供api文档 服务如下
-
1个注册中心 1个user服务 1个订单服务 1个商品服务 1个网关服务(zuul)
-
注册中心不用管 user、订单、商品服务 引入服务端依赖 按单应用的配置走
-
网关服务引入服务端和ui依赖 配置如下
@EnableSwagger2 @Configuration @Profile({"dev","test","local","tt"}) public class SwaggerConfig { @Bean @Order(value = 1) public Docket groupRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()); } private ApiInfo apiInfo(){ return new ApiInfoBuilder() .title("api文档") .description("<div style='font-size:14px;color:red;'>api文档</div>") .termsOfServiceUrl("http://www.shangtian.com/") .contact("[email protected]") .version("1.0") .build(); } }
@Component @Primary @Profile({"dev","test","local","tt"}) public class SwaggerResourceConfig implements SwaggerResourcesProvider { Logger logger= LoggerFactory.getLogger(SwaggerResourceConfig.class); @Autowired RouteLocator routeLocator; @Override public List<SwaggerResource> get() { //获取所有router List<SwaggerResource> resources = new ArrayList<>(); List<Route> routes = routeLocator.getRoutes(); logger.info("Route Size:{}",routes.size()); for (Route route:routes) { resources.add(swaggerResource(route.getId(), route.getFullPath().replace("**", "v2/api-docs"))); } return resources; } private SwaggerResource swaggerResource(String name, String location) { logger.info("name:{},location:{}",name,location); SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setName(name); swaggerResource.setLocation(location); swaggerResource.setSwaggerVersion("1.0"); return swaggerResource; } }
- 通过上面的配置就可以通过网关访问user、订单、商品服务的api文档了
- 如果网关服务不是zuul或者没有网关 可以借助nginx的反向代理 在实现对应的SwaggerResourceConfig就行了
-