本文屬於原創,轉載註明出處,歡迎關注微信小程序小白AI博客
微信公衆號小白AI
或者網站 https://xiaobaiai.nethtml
[TOC]前端
在現在先後端分離開發的模式下,前端調用後端提供的API去實現數據的展現或者相關的數據操做,保證及時更新和完整的REST API文檔將會大大地提升兩邊的工做效率,減小沒必要要的溝通成本。本文采用的Swagger2就是一個當前流行的經過少許的註解就能夠生成漂亮的API文檔工具,且在生成的在線文檔中提供相似POSTMAN直接調試能力,不只僅是靜態的文檔。接下來將會利用這個工具與Spring Boot項目結合,最終生成咱們上一篇文章中所涉及到的REST API文檔。java
這一篇文章基本將Swagger2在生產環境中可能會用到的配置都有涉及,慢慢看吧,看了這一篇因該是夠了。git
Swagger是與用於實現 OpenAPI 文檔普遍使用的工具,Swagger工具集包括開源工具,免費工具和商業工具的組合,可在API生命週期的不一樣階段使用。github
Swagger Editor
(開源):使用Swagger編輯器,能夠在瀏覽器內的YAML文檔中編輯OpenAPI規範並支持實時預覽文檔,能夠參考官方的Demo https://editor.swagger.io/ Swagger UI
(開源):讓Swagger產生的文檔更漂亮,並且支持API交互操做,在生成文檔後,直接在瀏覽器中瀏覽,並能夠實現相似curl
命令或者postman
訪問咱們的API,並返回相關數據。Swagger Codegen
(開源): 是一個代碼生成器,能夠經過Swagger API定義生成不一樣語言版本的服務端和客戶端工程代碼。Swagger Core
(開源):用於生成Swagger API規範的示例和服務器集成,可輕鬆訪問REST API,結合Swagger UI
,讓生成的文檔更漂亮。Swagger Parser
(開源): Java開發,解析OpenAPI定義的獨立庫Swagger Inspector
(免費):API在線測試工具,驗證API並從現有API生成OpenAPI定義功能 https://goo.gl/fZYHWz SwaggerHub
(免費和商用版):API設計和文檔化,爲使用OpenAPI的團隊打造。參考《Spring Boot從零入門5_五臟俱全的RESTful Web Service構建》。構建好後有以下REST API:web
# 獲取全部用戶信息 GET http://localhost:8080/api/v1/users # 新增一個用戶,參數經過body傳遞 POST http://localhost:8080/api/v1/users # 更新一個用戶信息 PUT http://localhost:8080/api/v1/users/{id} # 刪除指定用戶 DELETE http://localhost:8080/api/v1/users/{id}
構建好RESTful WEB服務後,接下來咱們集成Swagger,而後對上節中的REST API自動生成接口文檔。正則表達式
集成Swagger2,須要在pom.xml中添加依賴源:spring
<dependencies> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <!-- 截至2019年11月7日爲止,最新版本爲2.9.2 --> <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <version>2.9.2</version> </dependency> </dependencies>
springfox
有一個專用對象Docket,能夠靈活的配置Swagger的各類屬性,首先咱們簡單的建立一個Swagger配置類Swagger2Config.java
:json
@Configuration @EnableSwagger2 public class Swagger2Config { @Bean("UsersApis") public Docket usersApis() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build(); } }
這裏的@Configuration
註解用於定義配置類,被註解的類內部包含有一個或多個被@Bean
註解的方法,這些方法將會被AnnotationConfigApplicationContext
類進行掃描,並用於構建Bean定義,初始化對象。@ComponentScan
會自動獲取全部的Spring Components,包括@Configuration
類。另外這裏的「用戶管理模塊」API生成配置很簡單,對全部路徑上API都去生成文檔。小程序
當完成Swagger2的配置類時,啓動WEB服務,經過http://localhost:8080/v2/api-docs就能夠訪問生成文檔內容,可是瀏覽器返回的是JSON內容,基本上很難給須要用到相關API的開發人員進行參考。這個時候就須要用到Swagger2 UI
了。
pom.xml添加依賴,而後重啓WEB服務就能夠了,再次訪問http://localhost:8080/swagger-ui.html,這時候看到的就是WEB文檔了。
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
從swagger-ui頁面看到的內容有一部無關的內容,或者是如何明顯表現跟項目相關的內容呢?下面章節詳細講解Swagger的各類配置,可以應用到實際生產環境中去。
首先,若是要將咱們最後生成的API文檔給生產環境的開發人員查閱,那麼友好的展現信息和歸類是頗有必要的,咱們接下來實現以下目標:
文檔的各類信息說明
API分組
爲了更好地展現API分組功能,這裏另外加了一組REST API (代碼層面上只須要將User相關的代碼所有複製一份,將User關鍵字所有改成Product就能夠了,包括大小寫):
# 獲取全部產品信息 GET http://localhost:8080/api/v1/products # 新增一個產品,參數經過body傳遞 POST http://localhost:8080/api/v1/products # 更新一個產品信息 PUT http://localhost:8080/api/v1/products/{id} # 刪除指定產品 DELETE http://localhost:8080/api/v1/products/{id}
@Configuration @EnableSwagger2 public class Swagger2Config { @Bean("UsersApis") public Docket usersApis() { return new Docket(DocumentationType.SWAGGER_2) // select()返回的是ApiSelectorBuilder對象,而非Docket對象 .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) // build()返回的是Docket對象 .build() // 測試API時的主機URL .host("https://xiaobaiai.net") // API前綴 .pathProvider(new RelativePathProvider(null) { @Override public String getApplicationBasePath() { return "/prefix"; } }) .apiInfo(apiInfo()); } public ApiInfo apiInfo() { // API負責人的聯繫信息 final Contact contact = new Contact( "Ethan", "https://xiaobaiai.net", "ycm_hy@163.com"); return new ApiInfoBuilder() // API文檔標題 .title("X系統平臺接口文檔") // API文檔描述 .description("用戶/產品相關API, 更多請關注公衆號: 小白AI 或微信小程序:小白AI博客") // 服務條款URL .termsOfServiceUrl("https://github.com/yicm") // API文檔版本 .version("1.0") // API負責人的聯繫信息 .contact(contact) // API的許可證Url .licenseUrl("http://license.coscl.org.cn/MulanPSL") .license("MulanPSL") .build(); } }
經過添加文檔信息編譯對象ApiInfoBuilder
能夠配置API文檔的各類信息,包括標題、描述、服務條款、版本、責任人、許可證等。最後在Docket中添加信息配置對象便可生效。
上面的文檔信息配置中默認是沒有對API分組的,即全部的API都展現在了一個頁面,沒有隔離,若是須要分組,那咱們須要對不一樣API組分配Bean,目前示例能夠分爲用戶API組和產品API組,而後經過apis()
和 paths()
進行API過濾。
爲了避免顯示某個包下面API或某個URL路徑下API, Docket
提供了 apis()
和 paths()
兩 個方法來幫助咱們在不一樣級別上過濾接口(上面示例咱們默認對這兩個設置是不作任何過濾,掃描全部API):
apis()
:這種方式能夠經過指定包名的方式,讓 Swagger2 只去某些包下面掃描paths()
:這種方式能夠經過篩選 API 的 URL 來進行過濾apis和paths中的Predicates
除了any
、ant
、none
,還支持regex
正則表達式。
如:
PathSelectors.regex("/api/v2/users.*")
下面就是分組示例代碼,實現分組,很簡單,就是在Docket中配置組名就行了:
@Configuration @EnableSwagger2 public class Swagger2Config { @Bean public Docket usersApis() { return new Docket(DocumentationType.SWAGGER_2) .groupName("用戶管理接口") // select()返回的是ApiSelectorBuilder對象,而非Docket對象 .select() .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user")) .paths(Predicates.or( // 兩個**,能夠匹配底下全部URL // 一個*,只能匹配一級URL分段 PathSelectors.ant("/api/v1/users/**"), PathSelectors.ant("/api/v1/users/*"))) // build()返回的是Docket對象 .build() // 測試API時的主機URL .host("https://xiaobaiai.net") // API前綴,最終全部API的基礎地址就是host+prefix: https://xiaobaiai.net/prefix .pathProvider(new RelativePathProvider(null) { @Override public String getApplicationBasePath() { return "/prefix"; } }) .apiInfo(apiInfo()); } @Bean public Docket productsApis() { return new Docket(DocumentationType.SWAGGER_2) .groupName("產品管理接口") // select()返回的是ApiSelectorBuilder對象,而非Docket對象 .select() .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product")) .paths(Predicates.or( // 兩個**,能夠匹配底下全部URL // 一個*,只能匹配一級URL分段 PathSelectors.ant("/api/v1/products/**"), PathSelectors.ant("/api/v1/products/*"))) // build()返回的是Docket對象 .build() // 測試API時的主機URL .host("https://xiaobaiai.net") // API前綴 .pathProvider(new RelativePathProvider(null) { @Override public String getApplicationBasePath() { return "/prefix"; } }) .apiInfo(apiInfo()); } public ApiInfo apiInfo() { // API負責人的聯繫信息 final Contact contact = new Contact( "Ethan", "https://xiaobaiai.net", "ycm_hy@163.com"); return new ApiInfoBuilder() // API文檔標題 .title("X系統平臺接口文檔") // API文檔描述 .description("用戶/產品相關API, 更多請關注公衆號: 小白AI 或微信小程序:小白AI博客") // 服務條款URL .termsOfServiceUrl("https://github.com/yicm") // API文檔版本 .version("1.0") // API負責人的聯繫信息 .contact(contact) // API的許可證Url .licenseUrl("http://license.coscl.org.cn/MulanPSL") .license("MulanPSL") .build(); } }
分組配置完成後,從新啓動,打開瀏覽器就能夠看到效果了:
雖然上面咱們已經能夠控制API的顯示和分組了,可是對於API一些更詳細,對組內API再次歸類之類的,好比小組的描述信息,以及每一個API如何去控制它的參數說明,返回值說明等。這些都是經過註解去實現的,接下來咱們講述經常使用的註解及做用:
@Api
: 將這個註解添加到控制器類上,則能夠給控制器添加描述類信息:相關可設置參數有:
示例:
// Swagger配置類 @Configuration @EnableSwagger2 public class Swagger2Config { @Bean public Docket productsApis() { return new Docket(DocumentationType.SWAGGER_2) .groupName("產品管理接口") .select() .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product")) .paths(Predicates.or( PathSelectors.ant("/api/v1/products/**"), PathSelectors.ant("/api/v1/products/*"))) .build() .host("https://xiaobaiai.net") .pathProvider(new RelativePathProvider(null) { @Override public String getApplicationBasePath() { return "/prefix"; } }) .apiInfo(apiInfo()) .tags(new Tag("產品操做分組1", "產品查詢相關操做."), new Tag("產品操做分組2", "產品添加或刪除相關操做."), new Tag("產品操做分組3", "產品更新相關操做."), new Tag("產品操做分組4", "產品相關所有操做.")); } }
// 控制器類 @RestController @RequestMapping("/api/v1") @Api(tags={"產品接口文檔列表"}) public class ProductServiceController { ... }
效果以下:
@ApiIgnore
: 做用在REST API控制器方法
上,則該API不會被顯示出來:@ApiIgnore @RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE) public ResponseEntity<Object> delete(@PathVariable("id") String id) { ... }
@ApiOperation
註解用於控制器方法
上面,用於對方法的描述,相關參數設置描述以下:示例:
@ApiOperation(value = "獲取全部產品", notes = "每調用一次,就耗費流量100M", response = String.class) @GetMapping(value = "/products") public ResponseEntity<Object> getProduct() { return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK); }
最後效果就是:
@ApiImplicitParams
和@ApiImplicitParam
註解用於控制器方法傳入參數的說明。默認狀況下,Swagger會根據API方法中的傳入參數進行參數說明的生成,不過參數說明默認就是變量名,由於這兩個註解不必定須要。相關參數設置說明以下:paramType:參數傳遞類型
@RequestHeader
(代碼中接收註解)@RequestParam
(代碼中接收註解)@PathVariable
(代碼中接收註解)@RequestBody
(代碼中接收註解)示例:
// 若是隻有一個參數,則僅僅@ApiImplicitParam就能夠了 @ApiImplicitParams({ @ApiImplicitParam(name="id", value="產品ID值", required = true), @ApiImplicitParam(name="product", value="產品內容", required = true) }) @RequestMapping(value = "/products/{id}", method = RequestMethod.PUT) public ResponseEntity<Object> updateProduct(@PathVariable("id") String id, @RequestBody Product product) { productService.updateProduct(id, product); return new ResponseEntity<>("Product is updated successsfully", HttpStatus.OK); }
@ApiParam
: 做用同ApiImplicitParam,單個參數描述通常經常使用該註解,並且該註解只能與JAX-RS 1.x/2.x註解結合使用。參數設置說明以下:@ApiResponses
、@ApiResponse
: 用於控制器方法返回值的說明,參數設置說明以下:示例:
@ApiOperation(value = "獲取全部產品", notes = "每調用一次,就耗費流量100M",response =Product.class, responseContainer="List") @ApiResponses({ @ApiResponse(code = 200, message = "成功!", response=Product.class), @ApiResponse(code = 401, message = "未受權!", response=Product.class), @ApiResponse(code = 404, message = "頁面未找到!", response=Product.class), @ApiResponse(code = 403, message = "出錯了!", response=Product.class) }) @GetMapping(value = "/products") public ResponseEntity<Object> getProduct() { return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK); }
效果以下:
@Deprecated
: 做用於控制器方法上,標註該方法已通過時,建議開發者採用新的方式之類的。@ApiModel
:做用在JavaBean類上,說明JavaBean的用途,如咱們定義的Product.java類。經常使用參數設置以下:示例:
@ApiModel(value="Product",description="對產品定義的描述") public class Product { ... }
@ApiModelProperty
: 一樣用於在JavaBean類的屬性上面,說明相關屬性。相似於方法上說明的@ApiImplicitParam
。設置參數有:管理不一樣API版本有好幾種方式:
/api/v1/users
。經過這種方式,咱們能夠在Docket中過濾出不一樣版本,結合分組,能夠實現不一樣版本的API管理。/api/users?version=1
curl -H "Accept: application/vnd.piomin.v1+json" http://localhost:8080/api/users
這裏咱們對第一種方式示例展現:
在Swagger2Config.java中新添加一個用戶API Docket:
@Configuration @EnableSwagger2 public class Swagger2Config { @Bean("UsersApis_V1") public Docket usersApisV1() { return new Docket(DocumentationType.SWAGGER_2) .groupName("用戶管理接口V1") .select() .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user")) .paths(Predicates.or( // 過濾版本v1 PathSelectors.ant("/api/v1/users/**"), PathSelectors.ant("/api/v1/users/*"))) .build() .host("https://xiaobaiai.net") .pathProvider(new RelativePathProvider(null) { @Override public String getApplicationBasePath() { return "/prefix"; } }) .apiInfo(apiInfo()); } @Bean("UsersApis_V21") public Docket usersApisV2() { return new Docket(DocumentationType.SWAGGER_2) .groupName("用戶管理接口V2") .select() .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user")) .paths(Predicates.or( // 過濾版本v1 PathSelectors.ant("/api/v2/users/**"), PathSelectors.ant("/api/v2/users/*"))) .build() .host("https://xiaobaiai.net") .pathProvider(new RelativePathProvider(null) { @Override public String getApplicationBasePath() { return "/prefix"; } }) .apiInfo(apiInfo()); } @Bean public Docket productsApis() { return new Docket(DocumentationType.SWAGGER_2) ..... } public ApiInfo apiInfo() { final Contact contact = new Contact( "Ethan", "https://xiaobaiai.net", "ycm_hy@163.com"); return new ApiInfoBuilder() .title("X系統平臺接口文檔") .description("用戶/產品相關API, 更多請關注公衆號: 小白AI 或微信小程序:小白AI博客") .termsOfServiceUrl("https://github.com/yicm") .version("1.0") .contact(contact) .licenseUrl("http://license.coscl.org.cn/MulanPSL") .license("MulanPSL") .build(); } }
而後控制器添加新版本API方法:
@RestController @RequestMapping("/api") public class UserServiceController { @Autowired UserService userService; @DeleteMapping({"/v1/users/{id}", "/v2/users/{id}"}) public ResponseEntity<Object> delete(@PathVariable("id") String id) { userService.deleteUser(id); return new ResponseEntity<>("User is deleted successsfully", HttpStatus.OK); } @PutMapping({"/v1/users/{id}", "/v2/users/{id}"}) public ResponseEntity<Object> updateUser(@PathVariable("id") String id, @RequestBody User user) { userService.updateUser(id, user); return new ResponseEntity<>("User is updated successsfully", HttpStatus.OK); } @PostMapping({"/v1/users", "/v2/users"}) public ResponseEntity<Object> createUser(@RequestBody User user) { userService.createUser(user); return new ResponseEntity<>("User is created successfully", HttpStatus.CREATED); } @GetMapping({"/v1/users"}) @Deprecated public ResponseEntity<Object> getUser() { return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK); } @GetMapping(value = "/v2/users") public ResponseEntity<Object> getUser(@RequestParam String id) { return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK); } }
最後效果:
其餘的方式相似也差很少,如在Header中區分版本,這裏就不展開了。
當咱們的REST API加入的受權機制時,即需具備對該API的訪問權限,纔可以操做該API,可是咱們想在Swagger UI中去調試API,那麼如何解決每一個API一次性受權,所有API可訪問呢?增長使用的方便性,不用每次都對每一個API進行受權。不過須要在WEB服務中已經使用了API受權機制纔會須要這項配置。這裏暫不展開,後面單獨講述Spring Security
+ Swagger2 UI
配置。
應該是不能的: https://github.com/swagger-ap...
這一篇從介紹Swagger2入手,講述在Spring Boot中如何集成和配置Swagger2,並生成生成環境中的在線API文檔,包括如何將API分組,組信息描述,API信息描述,API方法參數描述,若是對API版本進行管理等,最後還擴展了內容,包括如何爲每一個API配置全局Token等。內容很全,參考這一篇應該是夠了,繼續!
本文屬於原創,轉載註明出處,歡迎關注CSDNfreeape或微信小程序小白AI博客
微信公衆號小白AI
或者網站 https://xiaobaiai.net