本文來自網易云社區
作者:李哲
二、Swagger-springmvc原理解析
上面介紹了如何將springmvc和springboot與swagger結合,通過簡單配置生成接口文檔,以及介紹了swagger提供的一些注解。下面將介紹swagger是如何做到與springmvc結合,自動生成接口文檔。
項目添加完成maven依賴后會加入swagger的依賴包,其中包括swagger- springmvc,swagger-annotations,swagger-models幾個依賴包。如下圖所示:
其中,swagger-annotations是swagger提供給spring的注解包,上面說的注解基本都在這個包里面;swagger-models是swagger自己的model類,主要用于將注解解析成后面需要使用的model和一些model數據的處理。Swagger-springmvc是swagger接入spring的一個最重要的包,通過這個包的處理可以將添加的注解信息解析出來,自動生成接口需要的數據,最后通過url請求就能返回接口的信息,通過前端處理就可以在頁面上看到接口的信息。下面將重點分析swagger-springmvc包下的文件,本文中分析的是1.0.2版本的swagger-springmvc,其他版本會存在差異,請自行研究。
下圖是swagger-springmvc包結構,圖中標紅的兩個類是swagger的入口類,根據包的名字大致能猜出各個模塊的功能。這里先簡單介紹下,annotation包下只有一個注解類ApiIgnore,用于忽略不被swagger處理;authorization包下主要用于處理需要認證的接口,添加認證信息;configuration主要處理配置相關的操作,其中包含了程序的配置SpringSwaggerConfig類,該類是swagger的默認配置類,也可以自己編寫封裝去修改配置(一般都會編寫自己的配置類,設置一些api信息等)。Controller用于處理請求swagger文檔時返回數據給前端ui;core是整個處理過程的核心模塊,例如注解的解析,model的處理,一些處理過程中的策略等等;ordering包中是用于處理頁面顯示接口時,一些排序問題,其中的class都繼承了Ordering<T>類,實現了Comparator<T>接口;paths包下了類主要是處理前端訪問swagger接口時的路徑問題;plugin是swagger和spring結合的適配處理,也是程序的入口,相對spring來說,swagger就像一個插件接入spring中;scanners和readers兩個包主要是處理注解的獲取和掃描解析。swagger- springmvc包下的大致結構就是這樣的,看到這是不是覺得swagger沒那么神奇了,其實swagger做的兩件最主要的事就是:掃描解析注解變成相應的model,前端請求接口文檔時返回后臺處理好的接口信息。
馬上就要進入程序入口了,是不是有點激動呢?可能有的人會問,怎么知道Swagger PluginAdapter是程序的入口?配置的文件不是SpringSwaggerConfig嗎?進入源代碼就能找到答案,下面來看下SwaggerPluginAdapter類:
這個類實現了ApplicationListener<ContextRefreshedEvent>接口,這是一個spring的接口,在spring的applicationcontext初始化完成后會執行onApplicationEvent方法,所以當spring啟動后,swagger就會被啟動。而SpringSwaggerConfig中使用了注解@configuration,會在spring啟動時進行swagger配置,在配置的時候會根據用戶自定義的配置進行設置,如果用戶沒有定義將用默認的配置。下面看下方法onApplicationEvent中的處理,如下圖所示,程序會先去判斷plugins是否存在,不存在直接使用默認的,如果配置中設置了plugin則使用配置中的SwaggerSpringMvcPlugin,最后都調用Swagger SpringMvcPlugin類的initialize方法。
SwaggerSpringMvcPlugin是swagger和spring框架核心的類。有好多可配置的屬性,并且提供了相應的get與set方法。 在該類中,初始化了SwaggerApiResourceListing類(用于掃描RequestMappingHandler方法)的屬性。 當調用initialize()方法的時候,調用的則是SwaggerApiResourceListing類的initialize()方法。
在initialize方法中主要做了兩件重要的事,第一通過apiListingReferenceScanner掃描所有的spring請求路徑(RequestMapping),過濾沒在配置類中設置的include Patterns,將掃描結果轉換為swagger自定義的model中。第二通過apiListingScanner類掃描第一步處理的每一個請求路徑,根據swagger的注解掃描每一個路徑對應的接口信息,最后將信息轉換為swagger中model并保存在swaggerCache中方便以后使用。
接下來分析具體的掃描過程,ApiListingReferenceScanner中的scan方法是調用該類中的scanSpringRequestMappings方法。在該方法中主要做的是根據spring中的Request MappingHandlerMapping找出符合條件的路徑并找出一些需要的信息保存起來。
ApiListingScanner類中主要掃描每個請求路徑的具體接口信息,具體的掃描過程是通過命令模式執行。代碼中的每一種reader對應一種具體要執行的命令操作,對所有的請求路徑(RequestMapping)分別獲取MediaType、接口描述、接口model等信息。其中,MediaTypeReader是解析請求的MediaType類型,ApiDescriptionReader是解析接口的信息,ApiModelReader是解析接口的model(即ApiModel標注的類)。解析完成后分別將這些信息保存起來。ApiDescriptionReader中主要處理了請求路徑,然后通過ApiOperationReader去處理真正的接口信息。execute方法中可以看到分別去處理寫在接口上的注解。
下面以一個OperationImplicitParametersReader為例介紹各種Reader是如何通過命令模式去處理對應的注解,其中通過AnnotationUtils.findAnnotation方法去查詢Api ImplicitParams注解去獲取接口上標注的參數信息,然后在繼承類SwaggerParameterReader中的execute方法中被調用。
?
其他的注解也是通過這種方式被讀取出來,最后會將這些信息保存到SwaggerCache中,到此swagger處理代碼中的注解就已完成,當然過程中還有處理一些其他信息,例如,需要登錄認證的信息,處理接口的請求路徑以方便swagger本身請求接口時應用等等。但是這些處理好的信息是怎么能在前端頁面顯示的呢?接下來就研究下swagger如何在前端顯示接口信息。在swagger的默認配置類中有個ComponentScan注解標注需要掃描的包com.mangofactory.swagger.controllers,在該包下有一個controller叫DefaultSwaggerController,代碼如下:
可以看到,swagger根據處理好的路徑對應返回相應的接口信息,從這里可以看到為什么解析的數據都放到SwaggerCache中,這樣后臺controller就可以返回請求的接口數據,通過前端頁面的解析就能在前端顯示接口的信息。下圖是前端代碼結構,通過index.html訪問接口信息。
至此swagger-springmvc是如何做到通過簡單注解配置就能實現自動生成接口文檔信息的原理就講完了,具體細節處理有興趣者可以自己研究。現在看來swagger也沒這么神奇了,但是其中用到的方法是值得我們學習使用的。例如,如何通過spring的方式獲取spring中管理的一些資源,命令模式,結合spring的插件開發等等。
三、Swagger其他功能
除了上面介紹的功能外,swagger還有一些其他功能,打開swagger的官網
https://swagger.io/可以看到除了介紹的功能,還有一些其他工具。
這里簡單介紹下swagger包含的其他功能,SwaggerEditor是一個swagger文檔編輯工具,通過該工具可以實現靜態接口文檔編寫,而且可以查看實時接口信息,上面一排按鈕可以實現保存,生成相關代碼等功能。如下圖所示:
SwaggerCodeGen是一個代碼生成的工具,即通過該工具可以實現根據接口信息生成各種語言的接口代碼,可以生產前端、后臺、移動端代碼框架,可以通過?swagger- codegen-cli腳手架工具或者訪問github地址:https://github.com/swagger-api/swagger- codegen根據提示操作,里面也有示例。生成前端、移動端的代碼根據各語言通用的框架實現接口請求,例如android的代碼中使用okhttp請求接口數據;同時可以通過靜態接口文檔生成服務器端代碼,這樣會根據文檔中定義的接口信息和model生成相應的model和controller接口。通過SwaggerCodeGen生成的代碼在大型項目中可能不太實用,因為里面很多代碼不符合人們編碼習慣,但是在快速開發的小型項目中可以嘗試使用。
Swagger UI是展示接口頁面的前端框架,接口信息就是通過這個框架顯示出來的,所以不管是靜態接口文檔還是通過后臺代碼生成的接口信息都可以通過SwaggerUI來顯示。上面介紹的swagger結合springmvc使用中使用的就是Swagger UI來顯示接口頁面。下圖是swagger官網上的一個示例:
Swagger Inspector是一個測試接口工具,類似postman,主要用來測試請求返回情況,可以通過在線Swagger Inspector測試接口,基本測試是免費使用的。swagger還提供了一些高級功能,如安全掃描、復雜功能測試、load測試及監控數據等,可以根據需求付費使用。如下圖所示,Swagger Inspector也可以保存請求歷史,可以選擇請求生成swagger文檔。
除此之外,swagger還提供了SwaggerHub,這是一個swagger倉庫,可以將文檔上傳保存,同時支持團隊協作,在線編輯,安全線上查閱等功能。Swagger還提供很多開源項目和活躍的社區,如果遇到問題可以去尋求幫助。
四、總結
本文主要介紹了swagger的簡介,如何在springmvc和springboot中使用swagger,swagger是如何在springmvc中發揮神奇功效的以及swagger的其他功能等。但是swagger也存在一些問題,例如需要在后臺代碼中加一些注解,過多的注解造成注解泛濫;接口文檔需要等到后臺接口寫好才能在前端展示,而一般開發可能需要先定義好接口,然后才開始寫代碼造成的流程混亂;要很深入的了解swagger需要時間和精力,對于忙業務的開發可能覺得不值得在上面花時間學習。其實對于這些問題都有很好的辦法解決,相比通過簡單學習就能方便的獲得接口信息而且不用反復更新文檔是很值得的一件事。對于接口文檔需要等后臺開發完才能展示的問題,可以先通過靜態的文檔書寫方式先寫文檔,之后再通過后臺接口方式實現。
通過上面的介紹,我們了解到swagger是一個功能非常強大的工具,如果能很好地利用這個工具將很大程度上提高我們的開發效率。雖然swagger之前也被爆出安全性問題,但這個問題在后續版本中得到了修復,所以趕快學習使用這個神器。由于時間倉促,如果文中有錯誤請諒解。
附(常用注解表):
相關閱讀:接口文檔神器Swagger(上篇)
網易云大禮包:https://www.163yun.com/gift
本文來自網易云社區,經作者李哲授權發布
?
相關文章:
【推薦】?用SolrJ操作Solr做搜索(上篇)
【推薦】?【專家坐堂】四種并發編程模型簡介
【推薦】?視覺設計師的進化