Spring專案如何優雅的生成介面文件與客戶端
背景
在開發 Restful
服務的過程中,大家或多或少都會碰到類似的問題,比如:介面如何文件化、怎樣自動生成 Client
。我們在開發 DMS
的過程,也碰到了類似的問題,並且積累了一些經驗,藉此跟大家分享,希望拋磚引玉。
概述
首先整體說下總的技術方案就是 Spring Boot
+ Springfox
+ Swagger Codegen
,其中 Spring Boot
+ Springfox
主要解決了介面如何文件化問題;Swagger Codegen
則主要解決了如何自動生成 Client
的問題。下面就詳細介紹這套方案的實現細節。
具體方案
介面文件化
Spring Boot
+Springfox
Springfox
是為基於 Spring
構建的介面自動生成文件的工具,它的原理就是根據 Spring
介面層的註解生成符合 Swagger
規範的介面描述檔案,然後通過內嵌的 Swagger UI
解析該描述檔案並渲染出來。
對於這個這個方案,知道的人比較多,內網也有很多介紹該方案的文章,附錄裡我羅列了些,在此我就不具體闡述,下面我只介紹下我們使用的一些經驗。
-
@Api
的tags
屬性請使用英文,該屬性值在Codegen
的時候會作為模組名。 -
建立多版本
Api
的方法@Configuration @EnableSwagger2 @ComponentScan(basePackages = {"com.tmall.pegasus.dms.controller"}) public class SwaggerConfiguration { @Bean public Docket v20DocumentationPlugin() { return new VersionedDocket("2.0"); } @Bean public Docket v10DocumentationPlugin() { return new VersionedDocket("1.0"); } class VersionedDocket extends Docket { public VersionedDocket(String version) { super(DocumentationType.SWAGGER_2); super.groupName(version) .select() .apis(RequestHandlerSelectors.any()) .paths(regex(API_BASE_PATH + "/.*")) .build() .apiInfo(getApiInfo(version)) .pathProvider(new BasePathAwareRelativePathProvider(API_BASE_PATH)) // 這裡記得設定 protocols,不然 Codegen 預設生成的 basePath 是 https 協議 .protocols(Sets.newHashSet("http")) .directModelSubstitute(LocalDate.class, String.class) .genericModelSubstitutes(ResponseEntity.class); } private ApiInfo getApiInfo(String version) { return new ApiInfo("Test Api", "Test Api Documentation", "1.0", "urn:tos", new Contact("xiaoming", "", "xiaoming@qq.com"), "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList()); } } @Bean UiConfiguration uiConfig() { return UiConfigurationBuilder.builder() .deepLinking(true) .displayOperationId(false) .defaultModelsExpandDepth(1) .defaultModelExpandDepth(1) .defaultModelRendering(ModelRendering.EXAMPLE) .displayRequestDuration(false) .docExpansion(DocExpansion.NONE) .filter(false) .maxDisplayedTags(null) .operationsSorter(OperationsSorter.ALPHA) .showExtensions(false) .tagsSorter(TagsSorter.ALPHA) .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS) .validatorUrl(null) .build(); } class BasePathAwareRelativePathProvider extends AbstractPathProvider { private String basePath; public BasePathAwareRelativePathProvider(String basePath) { this.basePath = basePath; } @Override protected String applicationPath() { return basePath; } @Override protected String getDocumentationPath() { return "/"; } @Override public String getOperationPath(String operationPath) { UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromPath("/"); return Paths.removeAdjacentForwardSlashes( uriComponentsBuilder.path(operationPath.replaceFirst(basePath, "")).build().toString()); } } }
-
在
Controller
上統一加上介面的字首,尤其介面有多個版本的時候,該方式會非常方便。@RequestMapping(path = "/api/v1") public class DataController { } @RequestMapping(path = "/api/v2") public class DataControllerV2 { }
-
方法註解記得設定
nickName
,設定該屬性的好處是在Codegen
的時候會用該屬性值作為對應的介面方法名。@ApiOperation(value = "新建資料", nickname = "createContent")
自動生成 Client
Swagger Codegen
, 官方 Usage Doc
在讓業務方使用我們介面的時候,自然而然的我們需要提供對應的 Client
,如果一個個手動封裝介面,會帶來很多的重複工作,維護起來也很麻煩,於是我們想尋求一些自動生成的方案。後來發現 Swagger
官方已經幫我們想好了,對應的就是 Swagger Codegen
,它的原理也不復雜,就是基於 Swagger
的介面描述檔案生成 Client
程式碼,當然它也支援生成 Server
端的專案骨架。
下面,我就詳細說下我們的使用經驗。
-
多模組專案生成
Client
針對多模組專案,我們會期望
Client
的pom
可以自定義,因為client
會依賴common
的一些Model
類,另外會依賴Parent Pom
,所以不能通過codegen
生成。這個可以通過.swagger-codegen-ignore
實現,該檔案你可以理解為類似.gitignore
的檔案,在codegen
的時候會忽略生成該檔案下的檔案列表。.swagger-codegen-ignore
要放到client
目錄下,配置的路徑都是相對Client
目錄而言,你可以把所有不想生成的檔案都列在裡面,下面就是一個具體示例:build.sh build.sbt build.gradle gradle.properties gradlew gradlew.bat pom.xml README.md settings.gradle .gitignore gradle .swagger-codegen/VERSION docs/** git_push.sh .travis.yml src/main/AndroidManifest.xml
-
推薦通過
maven
外掛配置生成Client
。對應的外掛配置示例如下:
<plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <id>clean-additional-generated-files</id> <phase>generate-sources</phase> <goals> <goal>clean</goal> </goals> <configuration> <excludeDefaultDirectories>true</excludeDefaultDirectories> <filesets> <fileset> <directory>${project.basedir}/src/main/java</directory> <!--<directory>${project.basedir}/src/test</directory>--> </fileset> </filesets> </configuration> </execution> </executions> </plugin> <plugin> <groupId>io.swagger</groupId> <artifactId>swagger-codegen-maven-plugin</artifactId> <version>2.3.1</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <templateDirectory>${project.basedir}/src/main/resources/template</templateDirectory> <inputSpec>${project.basedir}/src/main/resources/api.json</inputSpec> <!--<inputSpec>http://localhost:7001/v2/api-docs?group=1.0</inputSpec>--> <language>java</language> <output>${project.basedir}</output> <importMappings> <importMapping>ContentInfo=com.tmall.pegasus.dms.common.result.ContentInfo</importMapping> <importMapping>DataContent=com.tmall.pegasus.dms.common.params.DataContent</importMapping> <importMapping>DeliveryInfo=com.tmall.pegasus.dms.common.result.DeliveryInfo</importMapping> <importMapping>FieldInfo=com.tmall.pegasus.dms.common.result.FieldInfo</importMapping> <importMapping>ResourceInfo=com.tmall.pegasus.dms.common.result.ResourceInfo</importMapping> </importMappings> <invokerPackage>com.tmall.pegasus.dms.client</invokerPackage> <apiPackage>com.tmall.pegasus.dms.client.api</apiPackage> <modelPackage>com.tmall.pegasus.dms.common.result</modelPackage> <library>feign</library> <configOptions> <sourceFolder>src/main/java</sourceFolder> <ignoreFileOverride>${project.basedir}/.swagger-codegen-ignore</ignoreFileOverride> </configOptions> </configuration> </execution> </executions> </plugin>
第一個外掛是
maven-clean-plugin
,它幫助我們clean
掉上次生成的程式碼,第二個就是maven-swagger-codegen
外掛,可以看出裡面的配置非常豐富,各個配置的含義都可以在 官方文件 找到,有幾個配置我覺得會常用到,下面簡單介紹下。-
importMappings 當你不想用
Swagger Codegen
自己生成的Model
類,而是想用自己Common
包裡的Model
時,你可以用該配置實現,配置項就是一個個的對映關係,在Codegen
的時候會將Model
引用替換成你設定的值。 - apiPackage 就是你介面的包名
-
library
Codegen
預設支援多種http client
,你可以通過該引數指定。 -
ignoreFileOverride 就是
.swagger-codegen-ignore
對應的路徑。 -
templateDirectory 你如果想自定義生成
Client
程式碼,可以通過自定義Generator
實現,你如果只是想對系統生成的Client
做微小調整,可以通過修改系統自帶的的Template
實現。方法就是把Swaggen Codegen
的模板檔案拷貝一份到你的src/main/resources
裡,直接改裡面的檔案,同時記得配置templateDirectory
的路徑,再重新生成即可。
-
importMappings 當你不想用
- 將生成檔案均放到
.gitignore
中。
這樣的好處是可以避免大量無意義的提交其他
====
本文更多介紹的是這套方案中我們關注的點,並沒有一步步的介紹開發步驟,因為這方面的資料谷歌上有很多,大家可以自行查閱。如果閱讀中有不理解或疑惑的點,歡迎釘釘 @澶淵 、@亂我。
另外說點自己開發的一些感想,在開發的過程中,應儘可能的讓自己變的 “懶” 一些,要對 “重複” 保持足夠的敏感,每當感覺有重複程式碼出現時,就要考慮這裡是否可以複用,是否可以通過 AOP
實現,是否可以自動生成,總的來說就是用更少的程式碼做更多的事,最後謝謝閱讀本文。
相關文章
- 如何優雅的管理、測試、編輯API介面文件?API
- 【譯】更優秀的GraphQL官方中文文件-客戶端如何使用客戶端
- 在客戶端用JAVASCRIPT或VBSCRIPT生成WORD文件 (轉)客戶端JavaScript
- 如何優雅的使用介面
- 開源文件工具 showdoc 推出除錯介面的客戶端除錯客戶端
- 退避演算法實現之客戶端優雅回撥演算法客戶端
- Oracle 客戶端生成AWR方法Oracle客戶端
- spring系列—CAS客戶端與SpringSecurity整合Spring客戶端Gse
- 讓客戶參與他們的IT專案
- 在React專案中,如何優雅的優化長列表React優化
- 專案分享九:客戶端的異常處理客戶端
- 如何在vue專案中優雅的使用SVGVueSVG
- 生成Webservice客戶端的4中方法Web客戶端
- Android客戶端專案元件化實踐Android客戶端元件化
- React Native 專案(One 【一個】客戶端)React Native客戶端
- 專案中如何更好的控制客戶需求(轉)
- Spring Boot OAuth 2.0 客戶端Spring BootOAuth客戶端
- Spring Cloud構建客戶端SpringCloud客戶端
- 客戶端專案管理的挑戰及解決方法客戶端專案管理
- 如何在專案中優雅的校驗引數
- SnailSVN 專業版:與訪達整合的 SVN 客戶端AI客戶端
- 愛奇藝Android客戶端啟動優化與分析Android客戶端優化
- 如何配置WSUS客戶端客戶端
- 專案管理中如何更好的控制客戶的需求?專案管理
- 如果呼叫遠端遠端url介面為https,且存在客戶端證書驗證,如何在客戶端處理HTTP客戶端
- 介面文件生成
- 專案客製化文件
- CouchBase C 客戶端介面呼叫例項客戶端
- 在SelfHost專案中獲取客戶端IP地址客戶端
- 改造xxl-job的客戶端日誌檔案生成體系客戶端
- 優秀的Git客戶端:Tower for macGit客戶端Mac
- FileZilla - 優秀的免費 FTP 客戶端FTP客戶端
- 如何優雅地在React專案中使用ReduxReactRedux
- PHP介面與性狀的優雅應用PHP
- Redis:我是如何與客戶端進行通訊的Redis客戶端
- Spring Boot(六):如何優雅的使用 MybatisSpring BootMyBatis
- 如何建立NEO輕客戶端客戶端
- 如何優雅地生成測試資料