介紹
什麼是Swagger
Swagger是一個規範和完整的框架,用於生成、描述、調用和可視化 RESTful 風格的 Web 服務。總體目標是使客戶端和文件系統作爲服務器以同樣的速度來更新。文件的方法,參數和模型緊密集成到服務器端的代碼,允許API來始終保持同步。
作用
- 接口文檔在線自動生成
- 功能測試
Swagger是一組開源項目,其中主要要項目如下:
-
Swagger-tools:提供各種與Swagger進行集成和交互的工具。例如模式檢驗、Swagger 1.2文檔轉換成Swagger 2.0文檔等功能。
-
Swagger-core: 用於Java/Scala的的Swagger實現。與JAX-RS(Jersey、Resteasy、CXF...)、Servlets和Play框架進行集成。
-
Swagger-js: 用於JavaScript的Swagger實現。
-
Swagger-node-express: Swagger模塊,用於node.js的Express web應用框架。
-
Swagger-ui:一個無依賴的HTML、JS和CSS集合,可以爲Swagger兼容API動態生成優雅文檔。
-
Swagger-codegen:一個模板驅動引擎,通過分析用戶Swagger資源聲明以各種語言生成客戶端代碼。
在Spring使用Swagger
在Spring中集成Swagger會使用到springfox-swagger
,它對Spring和Swagger的使用進行了整合
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
使用
Spring中配置Swagger
/**
* Swagger2配置類
* 在與spring boot集成時,放在與Application.java同級的目錄下。
* 或者通過 @Import 導入配置
*/
@Configuration
@EnableSwagger2
public class Swagger2 {
/**
* 創建API應用
* apiInfo() 增加API相關信息
* 通過select()函數返回一個ApiSelectorBuilder實例,用來控制哪些接口暴露給Swagger來展現,
* 本例採用指定掃描的包路徑來定義指定要建立API的目錄。
* @return
*/
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.turbo.demo.controller"))
.paths(PathSelectors.any())
.build();
}
/**
* 創建該API的基本信息(這些基本信息會展現在文檔頁面中)
* 訪問地址:http://項目實際地址/swagger-ui.html
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring Boot中使用Swagger2構建RESTful APIs")
.description("")
.termsOfServiceUrl("")
.contact("zou", "", "[email protected]")
.version("1.0")
.build();
}
}
API註解
@Api
用在類上,該註解將一個Controller(Class)標註爲一個swagger資源(API)。在默認情況下,Swagger-Core只會掃描解析具有@Api註解的類,而會自動忽略其他類別資源(JAX-RS endpoints,Servlets等等)的註解。該註解包含以下幾個重要屬性
- tags
API分組標籤。具有相同標籤的API將會被歸併在一組內展示。 - value
如果tags沒有定義,value將作爲Api的tags使用 - description
API的詳細描述,在1.5.X版本之後不再使用,但實際發現在2.0.0版本中仍然可以使用
@ApiOperation
在指定的(路由)路徑上,對一個操作或HTTP方法進行描述。具有相同路徑的不同操作會被歸組爲同一個操作對象。不同的HTTP請求方法及路徑組合構成一個唯一操作。此註解的屬性有:
- value
對操作的簡單說明,長度爲120個字母,60個漢字。 - notes
對操作的詳細說明。 - httpMethod
HTTP請求的動作名,可選值有:"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS" and "PATCH"。 - code
默認爲200,有效值必須符合標準的HTTP Status Code Definitions。
@ApiImplicitParams
用在方法上,註解ApiImplicitParam的容器類,以數組方式存儲。
@ApiImplicitParam
對API的單一參數進行註解。雖然註解@ApiParam同JAX-RS參數相綁定,但這個@ApiImplicitParam註解可以以統一的方式定義參數列表,也是在Servelet及非JAX-RS環境下,唯一的方式參數定義方式。注意這個註解@ApiImplicitParam必須被包含在註解@ApiImplicitParams之內。可以設置以下重要參數屬性:
- name
參數名稱 - value
參數的簡短描述 - required
是否爲必傳參數 - dataType
參數類型,可以爲類名,也可以爲基本類型(String,int、boolean等) - paramType
參數的傳入(請求)類型,可選的值有path, query, body, header or form。
@ApiParam
增加對參數的元信息說明。這個註解只能被使用在JAX-RS 1.x/2.x的綜合環境下。其主要的屬性有
- required
是否爲必傳參數,默認爲false - value
參數簡短說明
@ApiResponses
註解@ApiResponse的包裝類,數組結構。即使需要使用一個@ApiResponse註解,也需要將@ApiResponse註解包含在註解@ApiResponses內。
@ApiResponse
描述一個操作可能的返回結果。當REST API請求發生時,這個註解可用於描述所有可能的成功與錯誤碼。可以用,也可以不用這個註解去描述操作的返回類型,但成功操作的返回類型必須在@ApiOperation中定義。如果API具有不同的返回類型,那麼需要分別定義返回值,並將返回類型進行關聯。但Swagger不支持同一返回碼,多種返回類型的註解。注意:這個註解必須被包含在@ApiResponses註解中。
- code
HTTP請求返回碼。有效值必須符合標準的HTTP Status Code Definitions。 - message
更加易於理解的文本消息 - response
返回類型信息,必須使用完全限定類名,比如“com.xyz.cc.Person.class”。 - responseContainer
如果返回類型爲容器類型,可以設置相應的值。有效值爲 "List", "Set" or "Map",其他任何無效的值都會被忽略。
Model註解
對於Model的註解,Swagger提供了兩個:@ApiModel及@ApiModelProperty,分別用以描述Model及Model內的屬性。
@ApiModel
描述一個Model的信息(一般用在請求參數無法使用@ApiImplicitParam註解進行描述的時候)
提供對Swagger model額外信息的描述。在標註@ApiOperation註解的操作內,所有的類將自動被內省(introspected),但利用這個註解可以做一些更加詳細的model結構說明。主要屬性有:
- value
model的別名,默認爲類名 - description
model的詳細描述
@ApiModelProperty
描述一個model的屬性
對model屬性的註解,主要的屬性值有:
- value
屬性簡短描述 - example
屬性的示例值 - required
是否爲必須值
註解示例
Api 示例
@AllArgsConstructor
@RestController
@RequestMapping("/api/category")
@Api(value = "/category", tags = "組件分類")
public class BizCategoryController {
private IBizCategoryService bizCategoryService;
@GetMapping("/list")
@ApiOperation(value = "列表", notes = "分頁列表")
public R<PageModel<BizCategory>> list(PageQuery pageQuery,
@RequestParam @ApiParam("組件分類名稱") String name) {
IPage<BizCategory> page = bizCategoryService.page(pageQuery.loadPage(),
new LambdaQueryWrapper<BizCategory>().like(BizCategory::getName, name));
return R.success(page);
}
@GetMapping("/list/all")
@ApiOperation(value = "查詢所有", notes = "分頁列表")
public R<List<BizCategory>> listAll() {
List<BizCategory> categories = bizCategoryService.list();
return R.success(categories);
}
@GetMapping("/{categoryId}")
@ApiOperation(value = "詳情", notes = "組件分類詳情")
public R<BizCategory> detail(@PathVariable @ApiParam("分類Id") Long categoryId) {
BizCategory category = bizCategoryService.getById(categoryId);
return R.success(category);
}
@PostMapping("/save")
@ApiOperation(value = "保存", notes = "新增或修改")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "form", name = "categoryId", value = "組件id(修改時爲必填)"),
@ApiImplicitParam(paramType = "form", name = "name", value = "組件分類名稱", required = true)
})
public R<BizCategory> save(Long categoryId, String name) {
BizCategory category = new BizCategory();
category.setId(categoryId);
category.setName(name);
bizCategoryService.saveOrUpdate(category);
return R.success(category);
}
@DeleteMapping("/{categoryId}")
@ApiOperation(value = "刪除", notes = "刪除")
public R delete(@PathVariable @ApiParam("分類Id") Long categoryId) {
bizCategoryService.delete(categoryId);
return R.success();
}
}
ApiModel 示例
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="BizComponent對象", description="組件")
public class BizComponent implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "分類")
private Long categoryId;
@ApiModelProperty(value = "組件名稱")
private String name;
@ApiModelProperty(value = "組件描述")
private String description;
@ApiModelProperty(value = "日期字段")
private LocalDateTime componentTime;
@ApiModelProperty(value = "創建時間")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty(value = "修改時間")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime modifiedTime;
}
swagger-ui界面
swagger生成的api文檔信息接口爲/v2/api-docs
,不過我們可以使用ui界面更加清晰的查看文檔說明,並且還能夠在線調試
springfox-swagger-ui
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
如果是使用springfox-swagger-ui
,啓動項目後的api文檔訪問路徑是 /swagger-ui.html
image
swagger-bootstrap-ui
swagger-bootstrap-ui是springfox-swagger的增強UI實現,我個人更推薦使用這個ui,api文檔結構更加清晰,在線調試也很方便
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>${swagger.bootstrap.ui.version}</version>
</dependency>
訪問的url爲 /doc.html
image
Swagger分組
Swagger的分組接口是通過後端配置不同的掃描包,將後端的接口,按配置的掃描包基礎屬性響應給前端
後端java的配置如下,指定分組名和各自要掃描的包
@Bean(value = "defaultApi")
public Docket defaultApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("默認接口")
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
.paths(PathSelectors.any())
.build();
}
@Bean(value = "groupApi")
public Docket groupRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(groupApiInfo())
.groupName("分組接口")
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo.group"))
.paths(PathSelectors.any())
.build();
}
分組信息的接口爲 /swagger-resources
[
{
"name": "分組接口",
"url": "/v2/api-docs?group=分組接口",
"swaggerVersion": "2.0",
"location": "/v2/api-docs?group=分組接口"
},{
"name": "默認接口",
"url": "/v2/api-docs?group=默認接口",
"swaggerVersion": "2.0",
"location": "/v2/api-docs?group=默認接口"
}
]
在swagger-ui中也可以通過分組來查看api文檔