一句話歸納:基於springboot+swagger實現接口文檔顯示後,本文將給出在企業實踐的進階需求,包括接口按需過濾,前端mock數據,文檔離線導出。
在上一篇文章《springboot+swagger接口文檔企業實踐(上)》已對使用springboot+swagger的接口文檔構建及配置進行了介紹,能夠實時顯示接口的輸入輸出,還能夠調用接口調試。解決了後端開發人員寫接口文檔的難處。但在企業實踐中,還有一些問題須要解決,如如下幾種:html
針對以上的狀況,本文提供相應的解決方法,主要包含如下內容:前端
本文配套的示例工程地址: https://github.com/mianshenglee/my-example/tree/master/springboot-swagger-demo/advance-swagger-demo
,讀者可fork或pull下來,結合學習。java
對於swagger的接口文檔,在實踐開發中,通常只須要發佈指定的接口,按需發佈便可,針對版本迭代,只須要對變動和新增的接口進行說明,而不是每次都輸出所有的接口。這些需求都屬於swagger的接口過濾功能。在springboot的swagger配置類(Swagger2Config.java
)中,Docket提供了apis()
和paths()
兩個方法用於接口過濾,下面詳細說明一下。node
通常接口都是寫在控制器(controller)中,而controller通常都統一放在一個package中,這樣,能夠經過包過濾顯示指定包的接口。經過在配置文件Swagger2Config.java
中使用apis()
函數進行過濾,把須要顯示的接口使用函數進行返回,注意,此處的參數enableClassFilter
,enableMethodFilter
和groupsFilters
分別對應後面的過濾方法,定義以下:git
private List<Predicate<RequestHandler>> apisFilter(boolean enableClassFilter,boolean enableMethodFilter, String[]groupsFilters) { List<Predicate<RequestHandler>> apis = new ArrayList<>(); String basePackageStr = swaggerInfo.getBasePackage(); // 1.包過濾 if (StrUtil.isNotEmpty(basePackageStr)) { //支持多個包 String[] basePackages = basePackageStr.split(";"); if (null != basePackages && basePackages.length > 0) { Predicate<RequestHandler> predicate = input -> { // 按basePackage過濾 Class<?> declaringClass = input.declaringClass(); String packageName = declaringClass.getPackage().getName(); return Arrays.asList(basePackages).contains(packageName); }; apis.add(predicate); } } return apis; }
此處代碼做用是按配置項swagger.basePackage
的包(多個包用;
分隔),從接口所在類中獲取包名,若包名是在配置的包內,則返回,並把匹配的內容使用List
返回。而後在apis()
調用時對返回值進行and操做Predicates.and(apisFilter())
,這樣,返回的內容就只是指定的包的接口描述。github
接口通常是在Controller類中,對於springmvc的controller,都會使用@Controller
進行註解,甚至先後端分離通常都是使用@RestController
,所以,若是咱們想只顯示使用@RestController
註解的類的接口,則能夠對此進行過濾。在前面的apisFilter()
方法中。使用isAnnotationPresent
可判斷是否有某註解,以下所示redis
// 2.過濾被RestController註解的類 if(enableClassFilter){ Predicate<RequestHandler> predicate = input -> { Class<?> declaringClass = input.declaringClass(); return declaringClass.isAnnotationPresent(RestController.class); }; apis.add(predicate); }
按類註解是把整個類過濾掉,粒度較大,若是隻想按方法過濾,可使用swagger的@ApiIgnore
註解對接口進行過濾,有此註解則不顯示。也能夠經過判斷是否存在某個指定方法註解來過濾。swagger的接口描述通常都用@ApiOperation
,所以,能夠經過判斷接口是否存在此註解,若是沒有則不顯示。以下:spring
// 3.過濾被ApiOperation註解的方法 if(enableMethodFilter){ apis.add(input -> input.isAnnotatedWith(ApiOperation.class)); }
swagger的接口文檔若是沒有指定groupName,則會默認以default
做爲分組名,對應的接口文檔是v2/api-docs?group=default
,它會按apis
過濾後的所有接口顯示出來。在迭代版本時,有個顯示的需求是隻須要顯示當前版本變動和新增的接口。其實也是使用註解過濾的方式,結合groupName進行設置便可。具體以下:mongodb
ApiVersion
此註解需自定義,用於指定版本號,注意能夠是多個版本(多版本兼容的狀況)。shell
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ApiVersion { /** * 接口版本號(對應swagger中的group) * @return String[] */ String[] group(); }
當開發新的版本,在變動和新增的接口中添加此註解,並把版本號寫到對應的group中便可,如
@ApiVersion(group = {"v1.0.0"})
ApiVersion
過濾在apisFilter()
函數中,添加如下過濾代碼:
// 4.過濾組 if(groupsFilters !=null && groupsFilters.length >0){ Predicate<RequestHandler> predicate = input -> { ApiVersion apiVersion = input.getHandlerMethod().getMethodAnnotation(ApiVersion.class); return apiVersion!=null && ArrayUtil.containsAny(apiVersion.group(),groupsFilters); }; apis.add(predicate); }
從接口方法中獲取ApiVersion
註解,並獲取它的group
參數,經過與指定的分組進行比較,存在即顯示,不然不顯示。
添加新的一個Docket Bean,指定groupName
爲當前須要顯示的版本號,並輸入須要過濾的分組數組。以下:
@Bean public Docket v100Api() { Docket docket = new Docket(DocumentationType.SWAGGER_2) .groupName(ApiVersionConstant.VERVION_100) ...//略 ApiSelectorBuilder builder = docket.select(); //指定須要過濾的版本號 builder = builder.apis(Predicates.and(apisFilter(false,true,new String[]{ApiVersionConstant.VERVION_100}))); ...//略 return builder.build(); }
通過上面的處理,顯示的接口界面有兩個分組,一個是default,一個是指定的版本號(v1.0.0),指定版本顯示的接口便是當前版本變動或新增的接口描述,以下:
有了接口文檔,先後端能夠並行開發,此時前端須要模擬接口的返回數據來顯示效果,測試內容。雖然swagger提供example
屬性,能夠在返回結果中提供示例,但對於前端而言,單一的示例不足以知足顯示和測試的需求。須要對數據按接口狀況進行mock。easy-mock是一個很好的選擇,它能夠鏈接swagger,自動生成mock數據,也能夠自定義mock規則。下面對easy-mock+swagger的使用進行描述。
根據easy-mock的官網介紹(官網常常掛掉,建議直接使用它的github私有部署), Easy Mock 是一個可視化,而且能快速生成模擬數據的持久化服務。 可使用它的在線服務,也能夠私有部署。它是開源項目,github地址: https://github.com/easy-mock/easy-mock
,具備如下特徵:
它的官方文檔和github文檔中,已經對easymock的安裝和使用進行詳細描述,讀者可參考官方文檔,此處只列出安裝的關鍵點和須要注意的地方(本文使用的easy-mock及相關工具是在centos7上安裝的)。
$ git clone https://github.com/easy-mock/easy-mock.git $ cd easy-mock && npm install
ctrl+c
可關閉。$ npm run dev # 啓動後訪問 http://127.0.0.1:7300
netstat -ntlp
查看正在使用的端口(如mongodb的27017,redis的6379,easy-mock的7300等)$ [sudo] npm install pm2 -g $ pm2 start app.js
easy-mock啓動後,經過瀏覽器能夠訪問, 輸入用戶名和密碼(若是用戶不存在會自動註冊)。
easy-mock是使用項目來進行接口管理,能夠建立我的項目,也能夠加入到其它人建立的項目,項目便是須要mock的接口。
在建立項目時,能夠設置swagger的接口文檔地址,以此導入swagger的接口進行管理與模擬。前面提到,使用分組過濾能夠按版本號來顯示接口,所以,建立項目時,可使用版本號做爲項目名稱,一個版本對應一個項目。這樣,前端在mock數據時就能夠針對當前版本進行處理。以下爲示例項目中的v1.0.0版本(填寫的swagger接口文檔地址爲v2/api-docs?group=v1.0.0
):
填寫swagger地址後,會自動導入對應的接口,與前端看到swaggger-ui.html
的接口一致,執行測試時,也會按swgger的返回數據類型或example進行返回。
模擬數據使用的是 Mock.js ,在其官網中有相應的文檔、示例和代碼。讀者能夠上去詳細閱讀。簡單來講,mockjs提供了對String
,Number
, Boolean
, Object
, Array
等數據的模擬規則,只需按規則編寫,便可生成隨機數據,達到模擬數據效果。生成規則有 7 種格式:
'name|min-max': value
'name|count': value
'name|min-max.dmin-dmax': value
'name|min-max.dcount': value
'name|count.dmin-dmax': value
'name|count.dcount': value
'name|+step': value
使用了自定義的模擬數據後,須要注意如下幾點:
通常在開發過程當中使用swagger文檔,直接使用瀏覽器訪問swagger-ui.html
頁面便可知足要求,如有需求是須要導出離線接口文檔,整體能夠按如下思路進行:
swagger
的v2/api-docs
的url地址導出json文檔(不導出也能夠直接使用此url做爲輸入文檔的地址)swagger2markup
工具將json文檔轉爲asciidoc格式文檔。asciidoctor
工具將asciidoc文件轉html或pdf文件。在瀏覽器中訪問接口文檔頁面的地址是/swagger-ui.html
,而swagger的規範文檔的地址是/v2/api-docs
,ctrl+s
把此文件保存爲json文件,如api-docs.json
。在項目的根目錄添加一個docs
目錄,用於存放離線文檔相關內容,以下所示,分別創建對應文檔格式的目錄,並把api-docs.json
放在swagger目錄下:
├─asciidoc ├─html ├─pdf └─swagger └─api-docs.json
有了api-docs.json
文檔,便可使用swagger2markup導出asciidoc文檔,Swagger2Markup是Github上的一個開源項目。該項目主要用來將Swagger自動生成的文檔轉換成幾種流行的格式以便於靜態部署和使用,好比:AsciiDoc、Markdown、Confluence。使用swagger2markup導出asciidoc文檔有兩種方式:
第一種方式示例代碼中有提供SwaggerExportTest.java
,其中編寫了相應的測試代碼用於生成文檔,請讀者自行閱讀。本文主要使用第二種方式,即maven插件進行asciidoc文檔輸出。
如下插件版本在示例可正常運行,更高的版本有可能會出現不兼容的狀況,所以請讀者按本文設置的版本進行處理。文檔輸出的路徑之前面指定的相關docs目錄爲準(${basedir}
是項目的根目錄)。
<!-- 文檔輸出插件版本 --> <swagger.plugin.version>3.1.8</swagger.plugin.version> <swagger2markup.version>1.3.1</swagger2markup.version> <swagger2markup.plugin.version>1.3.3</swagger2markup.plugin.version> <asciidoctor.plugin.version>1.5.7</asciidoctor.plugin.version> <!-- 文檔輸出路徑 --> <docs.path>${basedir}/docs</docs.path> <docs.asciidoc.path>${docs.path}/asciidoc</docs.asciidoc.path> <docs.html.path>${docs.path}/html</docs.html.path> <docs.pdf.path>${docs.path}/pdf</docs.pdf.path> <docs.swagger.json.path>${docs.path}/swagger/api-docs.json</docs.swagger.json.path>
swagger2markup-maven-plugin
插件在build/plugins
元素下,添加如下元素:
<!-- 1.swagger.json文件轉asciidoc文件--> <plugin> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-maven-plugin</artifactId> <version>${swagger2markup.plugin.version}</version> <configuration> <!-- 訪問url --> <!--<swaggerInput>http://localhost:8080/swaggerdemo/v2/api-docs?group=default</swaggerInput>--> <!-- 訪問json文件--> <swaggerInput>${docs.swagger.json.path}</swaggerInput> <!-- 生成多個文檔輸出路徑 --> <!--<outputDir>${docs.asciidoc.path}</outputDir>--> <!-- 生成單個文檔輸出路徑 --> <outputFile>${docs.asciidoc.path}/all</outputFile> <config> <swagger2markup.pathsGroupedBy>TAGS</swagger2markup.pathsGroupedBy> <!-- 選擇:ASCIIDOC/MARKDOWN/CONFLUENCE_MARKUP--> <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage> </config> </configuration> </plugin>
說明:
v2/api-docs
),效果是同樣的。但若使用url,則須要確保先把應用啓動,能正常訪問url。ASCIIDOC/MARKDOWN/CONFLUENCE_MARKUP
三種格式的文檔,此處使用ASCIIDOC
便可。添加完此插件後,使用mvn swagger2markup:convertSwagger2markup
命令便可以導出文件到指定的目錄。如本示例中的輸出是docs/asciidoc/all.adoc
導出asciidoc文檔後,使用asciidoctor插件對其轉換爲html和pdf文檔輸出。
以下所示,經過添加asciidoctor-maven-plugin,並對它進行配置:
<!-- 2.asciidoc文件轉html/pdf文件--> <plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>${asciidoctor.plugin.version}</version> <!-- 轉換pdf使用的依賴 --> <dependencies> <dependency> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctorj-pdf</artifactId> <version>1.5.0-alpha.16</version> </dependency> <dependency> <groupId>org.jruby</groupId> <artifactId>jruby-complete</artifactId> <version>9.2.8.0</version> </dependency> </dependencies> <configuration> <sourceDirectory>${docs.asciidoc.path}</sourceDirectory> <doctype>book</doctype> <sourceHighlighter>coderay</sourceHighlighter> <headerFooter>true</headerFooter> <attributes> <!-- 菜單欄在左邊 --> <toc>left</toc> <!-- 三級目錄 --> <toclevels>3</toclevels> <!-- 數字序號 --> <sectnums>true</sectnums> </attributes> </configuration> <!-- 生成html和pdf兩種格式 --> <executions> <execution> <id>output-html</id> <phase>generate-resources</phase> <goals> <goal>process-asciidoc</goal> </goals> <configuration> <outputDirectory>${docs.html.path}</outputDirectory> <backend>html</backend> </configuration> </execution> <execution> <id>output-pdf</id> <phase>generate-resources</phase> <goals> <goal>process-asciidoc</goal> </goals> <configuration> <outputDirectory>${docs.pdf.path}</outputDirectory> <backend>pdf</backend> <!-- 處理中文字符問題 --> <attributes> <pdf-fontsdir>${docs.pdf.path}/fonts</pdf-fontsdir> <pdf-stylesdir>${docs.pdf.path}/themes</pdf-stylesdir> <pdf-style>cn</pdf-style> </attributes> </configuration> </execution> </executions> </plugin>
此配置相對較長,其實主要分爲三部分:
<dependencies>
元素,直接使用便可。<configuration>
元素,其中須要注意的是<sourceDirectory>
,此處須要配置上一個步驟生成的asiidoc
文件目錄路徑。<executions>
元素:因爲須要生成html和pdf兩種格式的文檔,所以分別使用executions
來實現。其中html相對簡單,配置outputDirectory
和backend
元素指定輸出目錄路徑和文件格式html便可,對應的pdf也同樣配置。對於pdf文檔的轉換,須要解決中文字體缺失的問題。
<attributes>
元素),則會出現中文亂碼或文字缺失的狀況,以下圖,缺失了戶
,對
這幾個字:
KaiGenGothicCN
開頭和RobotoMono
開頭的ttf字體,同時下載cn-theme.yml
文件,分別放到docs/pdf
目錄下:├─pdf │ ├─fonts │ │ ├─KaiGenGothicCN-Bold-Italic.ttf │ │ ├─KaiGenGothicCN-Bold.ttf │ │ ├─KaiGenGothicCN-Regular-Italic.ttf │ │ ├─KaiGenGothicCN-Regular.ttf │ │ ├─RobotoMono-Bold.ttf │ │ ├─RobotoMono-BoldItalic.ttf │ │ ├─RobotoMono-Italic.ttf │ │ └─RobotoMono-Regular.ttf │ └─themes │ └─cn-theme.yml
<attributes>
元素設置對應的pdf-fontsdir
,pdf-stylesdir
及pdf-style
,指定下載好的fonts目錄和themes目錄。使用命令mvn generate-resources
,便可生成對應的html和pdf文檔到對應的目錄,分別是docs/html/all.html
及docs/html/all.pdf
。效果以下圖所示:
本篇文章針對接口過濾顯示,前端mock數據和離線導出文檔等問題,提供相應的解決方法,包括接口過濾(包過濾、類註解過濾、方法註解過濾、分組過濾等方式),實現按需發佈指定接口的功能;使用easy-mock+swagger實現mock數據;使用maven插件實現接口文檔的離線導出。但願對有須要的同窗有所幫助。本文配套的示例工程地址: https://github.com/mianshenglee/my-example/tree/master/springboot-swagger-demo/advance-swagger-demo
,讀者可fork或pull下來,結合學習。
https://github.com/Swagger2Markup/swagger2markup-maven-plugin
https://asciidoctor.org/docs/asciidoctor-maven-plugin/
https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic/releases
https://blog.csdn.net/lihuaijun/article/details/79727863
關注個人公衆號,獲取更多技術記錄: