swagger筆記
-
- 介紹
- 子產品
- 版本選擇
-
-
- springfox
- xiaoymin
-
- 使用
-
-
- 依賴部分
- 代碼部分
-
- 資料文獻
-
-
- knife4j項目說明
- swagger使用示例
- springfox
-
介紹
- 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>
如果加入上面的依賴還是不行 那就因為該瓜娃子進入欠收拾模式 需要你調教下
可以看下依賴裡面是不是有沖突有多個guava子版本 把低版本的排除掉
可以借助idea的project structure的modules的依賴下删除低版本的瓜娃子 或者mvn依賴分析 在手工排除
代碼部分
- 單應用
- 直接引用依賴 建立個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就行了