本文屬於原創,轉載註明出處,歡迎關注微信小程序小白AI博客
微信公衆號小白AI
或者網站 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分組功能,這裏另外加了一組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方法中的傳入參數進行參數說明的生成,不過參數說明默認就是變量名,由於這兩個註解不必定須要。相關參數設置說明以下: @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-api/swagger-ui#known-issues
這一篇從介紹Swagger2入手,講述在Spring Boot中如何集成和配置Swagger2,並生成生成環境中的在線API文檔,包括如何將API分組,組信息描述,API信息描述,API方法參數描述,若是對API版本進行管理等,最後還擴展了內容,包括如何爲每一個API配置全局Token等。內容很全,參考這一篇應該是夠了,繼續!
本文屬於原創,轉載註明出處,歡迎關注CSDNfreeape或微信小程序小白AI博客
微信公衆號小白AI
或者網站 xiaobaiai.net