tags: springboot
swagger
doc
html
一句話歸納:基於springboot+swagger實現接口文檔顯示後,本文將給出在企業實踐的進階需求,包括接口按需過濾,前端mock數據,文檔離線導出。前端
在上一篇文章《springboot+swagger接口文檔企業實踐(上)》已對使用springboot+swagger的接口文檔構建及配置進行了介紹,能夠實時顯示接口的輸入輸出,還能夠調用接口調試。解決了後端開發人員寫接口文檔的難處。但在企業實踐中,還有一些問題須要解決,如如下幾種:java
針對以上的狀況,本文提供相應的解決方法,主要包含如下內容:node
本文配套的示例工程地址:https://github.com/mianshenglee/my-example/tree/master/springboot-swagger-demo/advance-swagger-demo
,讀者可fork或pull下來,結合學習。git
對於swagger的接口文檔,在實踐開發中,通常只須要發佈指定的接口,按需發佈便可,針對版本迭代,只須要對變動和新增的接口進行說明,而不是每次都輸出所有的接口。這些需求都屬於swagger的接口過濾功能。在springboot的swagger配置類(Swagger2Config.java
)中,Docket提供了apis()
和paths()
兩個方法用於接口過濾,下面詳細說明一下。github
通常接口都是寫在控制器(controller)中,而controller通常都統一放在一個package中,這樣,能夠經過包過濾顯示指定包的接口。經過在配置文件Swagger2Config.java
中使用apis()
函數進行過濾,把須要顯示的接口使用函數進行返回,注意,此處的參數enableClassFilter
,enableMethodFilter
和groupsFilters
分別對應後面的過濾方法,定義以下:redis
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())
,這樣,返回的內容就只是指定的包的接口描述。spring
接口通常是在Controller類中,對於springmvc的controller,都會使用@Controller
進行註解,甚至先後端分離通常都是使用@RestController
,所以,若是咱們想只顯示使用@RestController
註解的類的接口,則能夠對此進行過濾。在前面的apisFilter()
方法中。使用isAnnotationPresent
可判斷是否有某註解,以下所示mongodb
// 2.過濾被RestController註解的類
if(enableClassFilter){
Predicate<RequestHandler> predicate = input -> {
Class<?> declaringClass = input.declaringClass();
return declaringClass.isAnnotationPresent(RestController.class);
};
apis.add(predicate);
}
複製代碼
按類註解是把整個類過濾掉,粒度較大,若是隻想按方法過濾,可使用swagger的@ApiIgnore
註解對接口進行過濾,有此註解則不顯示。也能夠經過判斷是否存在某個指定方法註解來過濾。swagger的接口描述通常都用@ApiOperation
,所以,能夠經過判斷接口是否存在此註解,若是沒有則不顯示。以下:shell
// 3.過濾被ApiOperation註解的方法
if(enableMethodFilter){
apis.add(input -> input.isAnnotatedWith(ApiOperation.class));
}
複製代碼
swagger的接口文檔若是沒有指定groupName,則會默認以default
做爲分組名,對應的接口文檔是v2/api-docs?group=default
,它會按apis
過濾後的所有接口顯示出來。在迭代版本時,有個顯示的需求是隻須要顯示當前版本變動和新增的接口。其實也是使用註解過濾的方式,結合groupName進行設置便可。具體以下:
ApiVersion
此註解需自定義,用於指定版本號,注意能夠是多個版本(多版本兼容的狀況)。
@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下來,結合學習。
swagger2markup-maven-plugin: https://github.com/Swagger2Markup/swagger2markup-maven-plugin
asciidoctor-maven-plugin:https://asciidoctor.org/docs/asciidoctor-maven-plugin/
asciidoctor-pdf中文字體:https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic/releases
使用Swagger2Markup、asciidoctor-maven-plugin和asciidoctorj-pdf插件生成PDF格式的API文檔中文問題解決:https://blog.csdn.net/lihuaijun/article/details/79727863
關注個人公衆號,獲取更多技術記錄: