Spring Boot之整合Swagger

前言

經(jīng)過(guò)之前文章的學(xué)習(xí),我們學(xué)會(huì)了:

有了這些基礎(chǔ)知識(shí),可以說(shuō),我們已經(jīng)擁有Spring Boot項(xiàng)目開(kāi)發(fā)的入門基礎(chǔ)了。

現(xiàn)實(shí)場(chǎng)景中,我們往往需要知道API的文檔,才能用于測(cè)試、交付等,土一點(diǎn)的做法是開(kāi)發(fā)人員編寫API文檔,如Wiki、Word、其他在線文檔等,實(shí)際上,有很多開(kāi)源資源幫我們從技術(shù)上實(shí)現(xiàn)了API規(guī)格的文檔化,而Swagger是Spring Boot生態(tài)中的佼佼者,也是官方推薦的。

Swagger的主要優(yōu)點(diǎn)有:

  1. 免費(fèi)開(kāi)源,并且官網(wǎng)提供了豐富的工具和文檔介紹;
  2. 通過(guò)代碼添加注解,自動(dòng)生成API文檔;
  3. 提供在線API文檔,API文檔隨API變化而自動(dòng)同步更新;
  4. 可開(kāi)啟UI界面,界面美觀、清晰;
  5. UI界面支持在線測(cè)試API;
  6. 支持多種語(yǔ)言(Java,PHP...);
  7. 采用OpenAPI 規(guī)范;
    (OpenAPI定義了RESTful APIs的編寫規(guī)范。規(guī)范中指定了一套模式/模型。這套規(guī)范是Swagger為各種編程語(yǔ)言編寫的服務(wù)提供接口文檔奠定了基礎(chǔ)。)
  8. ...

那么,我們今天就一起來(lái)學(xué)習(xí):

Spring Boot中通過(guò)Swagger來(lái)做API文檔。

本文使用的項(xiàng)目代碼,是基于上一篇文章使用的Spring Boot項(xiàng)目:
Spring Boot數(shù)據(jù)庫(kù)交互之Mybatis

主要步驟

  1. 添加依賴;
  2. 創(chuàng)建config包;
  3. 創(chuàng)建配置類;
  4. 編寫配置類;
  5. 修飾Controller;
  6. 修飾項(xiàng)目啟動(dòng)類;
  7. 啟動(dòng)項(xiàng)目、使用Swagger;

1.添加依賴;

//在pom.xml文件中的dependencies節(jié)點(diǎn)內(nèi)添加以下內(nèi)容:
<dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
</dependency>
<dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
</dependency>

2.創(chuàng)建config包;

項(xiàng)目根目錄下創(chuàng)建config包:

config包

3.創(chuàng)建配置類;

配置類

4.編寫配置類;

1. 編寫Swagger配置類;

該步驟的意義:

配置Swagger要掃描API的Controller位置、要顯示的API path的樣式、初始化的Swagger頁(yè)面的一些基礎(chǔ)信息(見(jiàn)apiInfo()方法);

  • 特別注意,要使用@EnableSwagger2注解;

  • 設(shè)置生成API接口信息的被掃描Controller路徑,常見(jiàn)寫法:

//生成指定包下的所有API接口信息
RequestHandlerSelectors.basePackage("com.mycompany.sample.controller")
//生成所有API接口
RequestHandlerSelectors.any()
//所有API接口都不生成
RequestHandlerSelectors.none()
//只生成被@Api 這個(gè)注解注解過(guò)的類接口
RequestHandlerSelectors.withClassAnnotation(Api.class)
//只生成被@ApiOperation 這個(gè)注解注解過(guò)的API接口
RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)
  • 設(shè)置API路徑篩選規(guī)則,常見(jiàn)寫法有:

//所有API均允許生成
PathSelectors.any()
//所有API均不允許生成
PathSelectors.none()
//正則表達(dá)式匹配,匹配上則允許生成,如包含getLead的API:
PathSelectors.regex("^(?!getLead).*$")
//只掃描指定的路徑下的請(qǐng)求,如只想掃描getLead API路徑下的:
//getLead為API path的一部分
PathSelectors.ant("/getLead/**")

代碼如下:

package com.mycompany.sample.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author : dylanz
 * @since : 07/17/2020
 **/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket api() {//名字不限
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(true)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.mycompany.sample.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {//名字不限
        Contact contact = new Contact("Dylan Zhang", "http://www.lxweimin.com/u/56578a39a99a", "997604787@qq.com");
        return new ApiInfoBuilder()
                .title("Lead API")
                .contact(contact)
                .description("Lead related operations")
                .termsOfServiceUrl("http://127.0.0.1:8080/getLead/10130546")
                .version("1.0")
                .build();
    }
}
  • 如果想關(guān)閉Swagger UI:

enable設(shè)置為:.enable(false),之后訪問(wèn)Swagger UI時(shí)就會(huì)如下:

關(guān)閉Swagger UI

2. 編寫WebMvcConfig配置類;

該步驟的意義:覆蓋、重寫項(xiàng)目配置的(如有)、默認(rèn)的靜態(tài)資源路徑,這樣才能讀取到Swagger jar包內(nèi)的靜態(tài)文件(html、css文件等);

package com.mycompany.sample.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import javax.annotation.PostConstruct;

/**
 * @author : dylanz
 * @since : 07/17/2020
 **/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @PostConstruct
    public void init() {
        System.out.println("Init in WebMvcConfig...");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/statics/");
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

5.修飾Controller;

package com.mycompany.sample.controller;

import com.mycompany.sample.domain.Lead;
import com.mycompany.sample.service.LeadService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author : dylanz
 * @since : 07/07/2020
 **/
@RestController
@Api
public class LeadController {
    @Autowired
    private LeadService leadService;

    @GetMapping("/getLead/{leadId}")
    @ResponseBody
    @ApiOperation(value = "get lead by leadId", httpMethod = "GET")
    @ApiImplicitParams(
            {@ApiImplicitParam(name = "leadId", value = "leadId", required = true, paramType = "path", dataType = "Long", example = "10130546")}
    )
    public Lead getLead(@PathVariable(name = "leadId") Long leadId) {
        return leadService.getLeadByLeadId(leadId);
    }
}
1. @Api 注解用來(lái)描述該服務(wù)的信息,如果不使用則顯示類名稱;
2. @ApiOperation 注解用于描述接口信息;
3. @ApiParam,@ApiImplicitParam,@ApiImplicitParams 注解用于描述接口的參數(shù);
4. @ApiResponse,@ApiResponses 注解用于描述API返回的信息,不使用會(huì)使用默認(rèn)的、根據(jù)接口情況自動(dòng)生成的描述信息,可在此處自定義錯(cuò)誤返回信息,如:

@ApiResponse(code = 400, message = "Bad Request", response = ErrorResponse.class),

5. @ApiVersion 注解用于描述接口的版本信息;

6.修飾項(xiàng)目啟動(dòng)類;

特別注意,只增加使用@EnableSwagger2注解即可;

package com.mycompany.sample;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author : dylanz
 * @since : 07/07/2020
 **/
@SpringBootApplication
@EnableSwagger2
@MapperScan(basePackages = "com.mycompany.sample.dao")
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

7.啟動(dòng)項(xiàng)目、使用Swagger;

  • 啟動(dòng)項(xiàng)目;

啟動(dòng)項(xiàng)目
  • 訪問(wèn)Swagger UI;

Swagger UI HTML站點(diǎn):http://localhost:8080/swagger-ui.html

HTML站點(diǎn)

頁(yè)面組成:

1. 標(biāo)題;
2. API文檔JSON入口:http://localhost:8080/v2/api-docs
3. 作者信息;
4. API文檔主體;
5. 等。

打開(kāi)折疊的API列表,我們能看到API的規(guī)格:

API規(guī)格

以及API使用的實(shí)體對(duì)象信息:

實(shí)體對(duì)象信息

我們還可以編輯實(shí)體類,修改、細(xì)化實(shí)體的展示:

package com.mycompany.sample.domain;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
 * @author : dylanz
 * @since : 07/07/2020
 **/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel
public class Lead implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "leadId", dataType = "Long", name = "id", example = "10130546")
    private Long leadId;
    @ApiModelProperty(value = "email", dataType = "String", name = "email", example = "dylan.zhang@xxxx.com")
    private String email;
}

@ApiModel:生成swagger時(shí)掃描的實(shí)體注解;
@ApiModelProperty:屬性注解,可用于描述實(shí)體屬性;

修改后,效果如下:

實(shí)體注解

還有我特別喜歡的測(cè)試API的功能

1. 點(diǎn)擊API規(guī)格右上角的"Try it out"按鈕:

Try it out

2. 點(diǎn)擊Execute按鈕,測(cè)試API:

Execute

3. API測(cè)試返回:

API返回

我們可以在頁(yè)面上修改API參數(shù),如本例為leadId,進(jìn)行不同參數(shù)值的測(cè)試(Request Body也支持),而不需要其他測(cè)試工具或測(cè)試代碼,相當(dāng)方便;

(本例中,我們?cè)赾ontroller內(nèi)@ApiImplicitParam注解中設(shè)置了默認(rèn)值:example = "10130546")

使用Swagger來(lái)管理API文檔是十分方便、快捷的,界面美觀、并且有測(cè)試API的功能,對(duì)開(kāi)發(fā)人員、測(cè)試人員十分友好,滿足了絕大多數(shù)API文檔化的需求。
凡事也要從不同的角度來(lái)看待,Swagger強(qiáng)大的背后,也有其一定的局限性:
  1. 僅對(duì)于Restful API支持較為友好,其他類型的API支持得不是很好;
  2. 對(duì)代碼有一定的侵入性;
  3. Swagger與代碼需要強(qiáng)綁定;
    (每個(gè)API都需要人為添加注解,如果有人偷懶,在API開(kāi)發(fā)時(shí)沒(méi)有加上Swagger對(duì)應(yīng)的注解,那么Swagger UI上是看不到該API的)
  4. ...
綜合來(lái)看,我還是很喜歡Swagger的,使用簡(jiǎn)單,功能強(qiáng)大!!!

你Get到了嗎?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。