SpringBoot集成Swagger3,還想來份離線文檔?真酷炫
本文轉(zhuǎn)載自微信公眾號(hào)「程序新視界」,作者二師兄。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序新視界公眾號(hào)。
前言
隨著項(xiàng)目架構(gòu)的演化,前后端分離是不可阻擋的趨勢(shì)。這種模式的協(xié)作在實(shí)踐的過程中經(jīng)常會(huì)遇到的一個(gè)問題就是文檔。
在《一位CTO告訴我,項(xiàng)目中至少需要這3類文檔》一文我們已經(jīng)描述了文檔的重要性,而接口文檔便是其中之一,可以說是必不可少的。
但編寫接口文檔對(duì)開發(fā)人員來說是一大難題,而且接口還在不斷的變化,還要花費(fèi)精力去維護(hù)接口文檔的更新。
既然存在痛點(diǎn),那么必須會(huì)出現(xiàn)解決此痛點(diǎn)的產(chǎn)品,這就是Swagger,目前已經(jīng)更新到Swagger3版本了。如果你還停留在Swagger2,建議升級(jí)到Swagger3,整體UI風(fēng)格及交互友好了不少。
本篇將圍繞Swagger3與SpringBoot的集成和離線文檔的生成來進(jìn)行講解。
Swagger簡(jiǎn)介
Swagger是一個(gè)規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化RESTful風(fēng)格的Web服務(wù)??傮w目標(biāo)是使客戶端和文件系統(tǒng)作為服務(wù)器以同樣的速度來更新。文件的方法,參數(shù)和模型緊密集成到服務(wù)器端的代碼,允許API來始終保持同步。
官網(wǎng):https://swagger.io
Swagger解決的痛點(diǎn)
傳統(tǒng)方式提供文檔有以下痛點(diǎn):
- 接口眾多,實(shí)現(xiàn)細(xì)節(jié)復(fù)雜,編寫文檔耗費(fèi)費(fèi)力,需要持續(xù)維護(hù);
 - 接口文檔需要隨時(shí)進(jìn)行同步;
 - 接口返回的結(jié)果不明確,得構(gòu)造返回結(jié)構(gòu)體等;
 - 不能直接在線測(cè)試接口,通常需要額外的工具,比如PostMan等。
 
當(dāng)引入Swagger之后,以上痛點(diǎn)迎刃而解,同時(shí)還帶來以下優(yōu)點(diǎn):
- 及時(shí)性 (接口變更后,前后端人員可實(shí)時(shí)看到最新版本)
 - 規(guī)范性 (接口具體統(tǒng)一風(fēng)格,如接口地址,請(qǐng)求方式,參數(shù),響應(yīng)格式和錯(cuò)誤信息等)
 - 一致性 (接口信息一致,不會(huì)因接口文檔版本問題出現(xiàn)分歧)
 - 可測(cè)性 (可直接基于接口文檔進(jìn)行測(cè)試)
 
Swagger3的改變
Swagger3.0的改動(dòng),官方文檔總結(jié)如下幾點(diǎn):
- 刪除了對(duì)springfox-swagger2的依賴;
 - 刪除所有@EnableSwagger2...注解;
 - 添加了springfox-boot-starter依賴項(xiàng);
 - 移除了guava等第三方依賴;
 - 文檔訪問地址改為http://ip:port/project/swagger-ui/index.html。
 
下面就來實(shí)戰(zhàn)使用一下吧。
SpringBoot集成Swagger3
SpringBoot集成Swagger3與SpringBoot集成其他框架的套路基本一致,通常包括:引入依賴、指定配置文件、創(chuàng)建配置類和使用。
引入依賴
在SpringBoot項(xiàng)目的pom.xml中引入Swagger3依賴:
- <dependency>
 - <groupId>io.springfox</groupId>
 - <artifactId>springfox-boot-starter</artifactId>
 - <version>3.0.0</version>
 - </dependency>
 
指定配置文件
通常情況下swagger只能在開發(fā)環(huán)境或測(cè)試環(huán)境下開啟,生產(chǎn)環(huán)境下需要進(jìn)行關(guān)閉的。而swagger的開啟與關(guān)閉可在application.properties中進(jìn)行配置:
- # 生產(chǎn)環(huán)境需設(shè)置為false
 - springfox.documentation.swagger-ui.enabled=true
 
配置類
通過@EnableOpenApi注解啟動(dòng)用Swagger的使用,同時(shí)在配置類中對(duì)Swagger的通用參數(shù)進(jìn)行配置。
- @Configuration
 - @EnableOpenApi
 - public class Swagger3Config {
 - @Bean
 - public Docket createRestApi() {
 - //返回文檔摘要信息
 - return new Docket(DocumentationType.OAS_30)
 - .apiInfo(apiInfo())
 - .select()
 - .apis(RequestHandlerSelectors.withMethodAnnotation(Operation.class))
 - .paths(PathSelectors.any())
 - .build()
 - .globalRequestParameters(getGlobalRequestParameters())
 - .globalResponses(HttpMethod.GET, getGlobalResponseMessage())
 - .globalResponses(HttpMethod.POST, getGlobalResponseMessage());
 - }
 - /**
 - * 生成接口信息,包括標(biāo)題、聯(lián)系人等
 - */
 - private ApiInfo apiInfo() {
 - return new ApiInfoBuilder()
 - .title("Swagger3接口文檔")
 - .description("如有疑問,可聯(lián)系二師兄,微信:zhuan2quan")
 - .contact(new Contact("二師兄", "https://www.choupangxia.com/", "secbro2@gmail.com"))
 - .version("1.0")
 - .build();
 - }
 - /**
 - * 封裝全局通用參數(shù)
 - */
 - private List<RequestParameter> getGlobalRequestParameters() {
 - List<RequestParameter> parameters = new ArrayList<>();
 - parameters.add(new RequestParameterBuilder()
 - .name("uuid")
 - .description("設(shè)備uuid")
 - .required(true)
 - .in(ParameterType.QUERY)
 - .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
 - .required(false)
 - .build());
 - return parameters;
 - }
 - /**
 - * 封裝通用響應(yīng)信息
 - */
 - private List<Response> getGlobalResponseMessage() {
 - List<Response> responseList = new ArrayList<>();
 - responseList.add(new ResponseBuilder().code("404").description("未找到資源").build());
 - return responseList;
 - }
 - }
 
通過以上配置已經(jīng)完成了Spring Boot與Swagger的集成,下面展示一下如何在業(yè)務(wù)邏輯中進(jìn)行使用。
業(yè)務(wù)中使用
創(chuàng)建兩個(gè)實(shí)體類Goods(商品類)和CommonResult(通用返回結(jié)果類)。
Goods類:
- @ApiModel("商品模型")
 - public class Goods {
 - /**
 - * 商品id
 - */
 - @ApiModelProperty("商品ID")
 - Long goodsId;
 - /**
 - * 商品名稱
 - */
 - @ApiModelProperty("商品名稱")
 - private String goodsName;
 - /**
 - * 商品價(jià)格
 - */
 - @ApiModelProperty("商品價(jià)格")
 - private BigDecimal price;
 - // 省略getter/setter
 - }
 
CommonResult類:
- @ApiModel("API通用數(shù)據(jù)")
 - public class CommonResult<T> {
 - /**
 - * 標(biāo)識(shí)代碼,0表示成功,非0表示出錯(cuò)
 - */
 - @ApiModelProperty("標(biāo)識(shí)代碼,0表示成功,非0表示出錯(cuò)")
 - private Integer code;
 - /**
 - * 描述信息,通常錯(cuò)時(shí)使用
 - */
 - @ApiModelProperty("錯(cuò)誤描述")
 - private String msg;
 - /**
 - * 業(yè)務(wù)數(shù)據(jù)
 - */
 - @ApiModelProperty("業(yè)務(wù)數(shù)據(jù)")
 - private T data;
 - public CommonResult(Integer status, String msg, T data) {
 - this.code = status;
 - this.msg = msg;
 - this.data = data;
 - }
 - /**
 - * 成功
 - */
 - public static <T> CommonResult<T> success(T data) {
 - return new CommonResult<>(0, "成功", data);
 - }
 - public static <T> CommonResult<T> success(Integer code, String msg) {
 - return new CommonResult<>(code, msg, null);
 - }
 - /**
 - * 錯(cuò)誤
 - */
 - public static <T> CommonResult<T> error(int code, String msg) {
 - return new CommonResult<>(code, msg, null);
 - }
 - // 省略getter/setter
 - }
 
下面針對(duì)Controller層的接口來使用Swagger對(duì)應(yīng)的API。
GoodsController類:
- @Api(tags = "商品信息管理接口")
 - @RestController
 - @RequestMapping("/goods")
 - public class GoodsController {
 - @Operation(summary = "單個(gè)商品詳情")
 - @GetMapping("/findGoodsById")
 - public CommonResult<Goods> findGoodsById(
 - @Parameter(description = "商品ID,正整數(shù)")
 - @RequestParam(value = "goodsId", required = false, defaultValue = "0") Integer goodsId) {
 - System.out.println("根據(jù)商品ID=" + goodsId + "查詢商品詳情");
 - Goods goods = new Goods();
 - goods.setGoodsId(1L);
 - goods.setGoodsName("筆記本");
 - goods.setPrice(new BigDecimal(8888));
 - return CommonResult.success(goods);
 - }
 - }
 
OrderController類:
- @Api(tags = "訂單管理接口")
 - @RestController
 - @RequestMapping("/order")
 - public class OrderController {
 - @Operation(summary = "提交訂單")
 - @PostMapping("/order")
 - @ApiImplicitParams({
 - @ApiImplicitParam(name = "userId", value = "用戶id", dataTypeClass = Long.class, paramType = "query", example = "123"),
 - @ApiImplicitParam(name = "goodsId", value = "商品id", dataTypeClass = Integer.class, paramType = "query", example = "1")
 - })
 - public CommonResult<String> toBuy(@ApiIgnore @RequestParam Map<String, String> params) {
 - System.out.println(params);
 - return CommonResult.success("success");
 - }
 - }
 
展示效果
完成集成,啟動(dòng)SpringBoot項(xiàng)目,在訪問地址:
http://127.0.0.1:8080/swagger-ui/index.html
從整體上可以看到如下效果:
具體的商品信息管理接口,可以看到請(qǐng)求參數(shù)、返回結(jié)果數(shù)據(jù)結(jié)構(gòu)等信息,點(diǎn)擊“Try it out”,可輸入?yún)?shù)請(qǐng)求參數(shù),進(jìn)行接口的調(diào)用:
調(diào)用之后會(huì)返回對(duì)應(yīng)的處理結(jié)果:
在最下面的Schemas中還可以看到對(duì)應(yīng)返回結(jié)果數(shù)據(jù)和被Swagger注解的實(shí)體類信息。
Swagger3注解使用說明
經(jīng)過上述實(shí)例之后,我們知道大多數(shù)API是如何使用的了,這了再匯總一下相關(guān)API的功能:
- @Api:用在請(qǐng)求的類上,表示對(duì)類的說明
 - tags="說明該類的作用,可以在UI界面上看到的注解"
 - value="該參數(shù)沒什么意義,在UI界面上也看到,所以不需要配置"
 - @ApiOperation:用在請(qǐng)求的方法上,說明方法的用途、作用
 - value="說明方法的用途、作用"
 - notes="方法的備注說明"
 - @ApiImplicitParams:用在請(qǐng)求的方法上,表示一組參數(shù)說明
 - @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一個(gè)請(qǐng)求參數(shù)的各個(gè)方面
 - name:參數(shù)名
 - value:參數(shù)的漢字說明、解釋
 - required:參數(shù)是否必須傳
 - paramType:參數(shù)放在哪個(gè)地方
 - · header --> 請(qǐng)求參數(shù)的獲?。篅RequestHeader
 - · query --> 請(qǐng)求參數(shù)的獲?。篅RequestParam
 - · path(用于restful接口)--> 請(qǐng)求參數(shù)的獲取:@PathVariable
 - · body(不常用)
 - · form(不常用)
 - dataType:參數(shù)類型,默認(rèn)String,其它值dataType="Integer"
 - defaultValue:參數(shù)的默認(rèn)值
 - @ApiResponses:用在請(qǐng)求的方法上,表示一組響應(yīng)
 - @ApiResponse:用在@ApiResponses中,一般用于表達(dá)一個(gè)錯(cuò)誤的響應(yīng)信息
 - code:數(shù)字,例如400
 - message:信息,例如"請(qǐng)求參數(shù)沒填好"
 - response:拋出異常的類
 - @ApiModel:用于響應(yīng)類上,表示一個(gè)返回響應(yīng)數(shù)據(jù)的信息
 - (這種一般用在post創(chuàng)建的時(shí)候,使用@RequestBody這樣的場(chǎng)景,
 - 請(qǐng)求參數(shù)無法使用@ApiImplicitParam注解進(jìn)行描述的時(shí)候)
 - @ApiModelProperty:用在屬性上,描述響應(yīng)類的屬性
 
集成knife4j導(dǎo)出離線文檔
Swagger為我們提供了方便的在線文檔支持,但某些場(chǎng)景下我們需要把接口文檔提供給合作人員,而不是直接給一個(gè)地址。此時(shí),我們就需要將接口文檔導(dǎo)出為離線文檔。
這里我們集成增強(qiáng)文檔knife4j來實(shí)現(xiàn)離線文檔的導(dǎo)出。
添加knife4j依賴
在pom.xml中增加knife4j的依賴:
- <dependency>
 - <groupId>com.github.xiaoymin</groupId>
 - <artifactId>knife4j-spring-boot-starter</artifactId>
 - <version>3.0.2</version>
 - </dependency>
 
啟動(dòng)knife4j
在上面配置Swagger的Swagger3Config中添加@EnableKnife4j注解,該注解可以開啟knife4j的增強(qiáng)功能。
- @EnableKnife4j
 - @Configuration
 - @EnableOpenApi
 - public class Swagger3Config {
 - // ...
 - }
 
此時(shí),如果依舊訪問http://localhost:8080/swagger-ui/index.html會(huì)發(fā)現(xiàn)顯示并沒有變化。這里我們需要訪問http://localhost:8088/doc.html。
整個(gè)項(xiàng)目源碼地址:https://github.com/secbr/springboot-all/tree/master/springboot-swagger3。
展示效果
此時(shí)啟動(dòng)項(xiàng)目,訪問doc.html之后,你會(huì)發(fā)現(xiàn)現(xiàn)在文檔風(fēng)格變得非??犰拧U故編讉€(gè)效果圖來看看:
其中在“離線文檔”一欄中可以看到四種形式的離線文檔下載:Markdown、HTML、Word、OpenAPI。
其中個(gè)人感覺HTML格式的文檔更具有沒敢,也更方便查看,來一張圖看看效果。
小結(jié)
文檔是項(xiàng)目中必須的,但隨著開源框架的發(fā)展,對(duì)技術(shù)人員來說文檔的痛點(diǎn)也在逐步解決。如果你還處于手寫文檔的階段,真的可以嘗試一下這類更友好的文檔展現(xiàn)形式。

























 
 
 











 
 
 
 