Spring Boot 2.x學習筆記:集成spring-boot-starter-swagger構建強大的API文檔

前言

隨着前後端分離架構和微服務架構的流行,我們使用Spring Boot來構建RESTful API項目的場景越來越多。通常我們的一個RESTful API就有可能要服務於多個不同的開發人員或開發團隊:IOS開發、Android開發、Web開發甚至其他的後端服務等。爲了減少與其他團隊平時開發期間的頻繁溝通成本,傳統做法就是創建一份RESTful API文檔來記錄所有接口細節,然而這樣的做法有以下幾個問題:

  • 由於接口衆多,並且細節複雜(需要考慮不同的HTTP請求類型、HTTP頭部信息、HTTP請求內容等),高質量地創建這份文檔本身就是件非常喫力的事,下游的抱怨聲不絕於耳;
  • 隨着時間推移,不斷修改接口實現的時候都必須同步修改接口文檔,而文檔與代碼又處於兩個不同的媒介,除非有嚴格的管理機制,不然很容易導致不一致現象;

爲了解決上面這樣的問題,Swagger2應運而生,通過將Swagger2整合到我們的Spring Boot應用中,我們可以快速的組織出強大RESTful API文檔,Swagger2大量的減少了我們創建文檔的工作量,同時通過簡單的Annotation將API說明內容整合入實現代碼中,讓維護文檔和修改代碼整合爲一體,可以讓我們在修改代碼邏輯的同時方便的修改文檔說明,進一步減少了我們維護文檔的成本。

本文將要介紹的是一個GitHub上的一個開源項目spring-boot-starter-swagger。該項目主要利用Spring Boot的自動化配置特性,對Swagger2進行了進一步的封裝,更加簡化了我們在Spring Boot應用中整合Swagger2的步驟。

Swagger2 簡介

Swagger2是一款業界比較流行的實現RESTful API的文檔在線自動生成及RESTful API在線調試的工具。優點有:

  1. Swagger2可以輕鬆的整合到Spring Boot工程中,並與Spring MVC程序配合組織出強大RestFul接口文檔,通過在項目中引入Swagger,可以使用簡單的Annotation,就實現了接口文檔化;
  2. Swagger2既可以減少我們創建文檔的工作量,同時說明內容又整合入實現代碼中,讓維護文檔和修改代碼整合爲一體,可以讓我們在修改代碼邏輯的同時方便的修改文檔說明;
  3. Swagger2提供標準的json或yaml文檔,方便做進一步解析,典型應用是接口自動化測試;
  4. Swagger2也提供了強大的頁面測試功能來調試每個RESTful API,Swagger2頁面可以直接進行測試(try-it-out功能,部分替代Postman);
  5. Swagger還提供類似於github的SwaggerHub,相當於公共的API文檔集散地

Swagger2項目主頁:https://swagger.io/

spring-boot-starter-swagger 簡介

spring-boot-starter-swagger是一個GitHub上的一個開源項目,該項目主要利用Spring Boot的自動化配置特性來實現快速的將swagger2引入spring boot應用來生成API文檔,簡化原生使用swagger2的整合代碼。

版本基礎

  • SpringBoot版本:1.5.x
  • Swagger版本:2.8.x

集成步驟

  • pom.xml中引入依賴:
<dependency>
  <groupId>com.spring4all</groupId>
  <artifactId>swagger-spring-boot-starter</artifactId>
	<version>1.9.0.RELEASE</version>
</dependency>

說明

1. 當前最新版本 1.9.0.RELEASE

2. 從1.6.0版本開始,artifactId修改爲swagger-spring-boot-starter1.6.0之前的版本不做修改,依然爲spring-boot-starter-swagger

  • 在應用主類中增加@EnableSwagger2Doc註解
/**
 *
 * @ClassName: DemoApplication
 * @Description: Demo應用啓動類
 * @author YuanXu
 * @date 2019年10月31日 上午10:53:23
 *
 */
@EnableSwagger2Doc
@SpringBootApplication
public class DemoApplication {

    /**
     * @Title main
     * @Description 測試應用啓動入口
     * @author YuanXu
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

默認情況下就能產生所有當前Spring MVC加載的請求映射文檔。

參數配置

全局配置說明

swagger:
  base-package: swagger掃描的基礎包,默認:全掃描
  base-path: 需要處理的基礎URL規則,默認:/**
  contact:
    email: 維護人email
    name: 維護人
    url: 維護人URL
  description: 描述
  enabled: 是否啓用swagger,默認:true
  exclude-path: 需要排除的URL規則,默認:空
  globalOperationParameters:
  - description: 描述信息
    modelRef: 指定參數類型
    name: 參數名
    parameterType: 指定參數存放位置,可選header,query,path,body.form
    required: 指定參數是否必傳,true,false
  host: 文檔的host信息,默認:空
  license: 許可證
  licenseUrl: 許可證URL
  termsOfServiceUrl: 服務條款URL
  title: 標題
  version: 版本

全局配置示例

swagger:
  apply-default-response-messages: false # 取消使用默認預定義的響應消息,並使用自定義響應消息
  base-package: com.yuanx
  base-path: /**
  contact:
    email: [email protected]
    name: YuanXu
    url: https://blog.csdn.net/yx_222
  description: Starter for swagger 2.x
  enabled: true
  exclude-path: /error, /ops/**
  global-response-message:
    get:
    - code: 401
      message: 頁面不存在
    - code: 500
      message: 系統內部錯誤
      modelRef: ERROR
    post:
    - code: 500
      message: 系統內部錯誤
      modelRef: ERROR
  globalOperationParameters:
  - description: some description one
    modelRef: string
    name: name one
    parameterType: header
    required: true
  - description: some description two
    modelRef: string
    name: name two
    parameterType: body
    required: false
  license: Apache License, Version 2.0
  licenseUrl: https://www.apache.org/licenses/LICENSE-2.0.html
  termsOfServiceUrl: https://github.com/dyc87112/spring-boot-starter-swagger
  title: spring-boot-starter-swagger
  version: 1.9.0.RELEASE

path規則說明

swagger.base-pathswagger.exclude-path使用ANT規則配置。

我們可以使用swagger.base-path來指定所有需要生成文檔的請求路徑基礎規則,然後再利用swagger.exclude-path來剔除部分我們不需要的。

例如:

management:
  context-path: /ops

swagger:
  base-path: /**
  exclude-path: /ops/**, /error

上面的設置將解析所有除了/ops/開始以及spring boot自帶/error請求路徑。

其中,exclude-path可以配合management.context-path=/ops設置的spring boot actuator的context-path來排除所有監控端點。

分組配置說明

當我們一個項目的API非常多的時候,我們希望對API文檔實現分組。從1.2.0.RELEASE開始,將支持分組配置功能,具體配置內容如下:

swagger:
  docket:
    <name>:
      base-package: swagger掃描的基礎包,默認:全掃描
      base-path: 需要處理的基礎URL規則,默認:/**
      contact:
        email: 維護人email
        name: 維護人
        url: 維護人URL
      description: 描述
      exclude-path: 需要排除的URL規則,默認:空
      globalOperationParameters:
      - description: 描述信息
        modelRef: 指定參數存放位置,可選header,query,path,body.form
        name: 參數名
        parameterType: 指定參數是否必傳,true,false
      license: 許可證
      licenseUrl: 許可證URL
      modelRef: 指定參數類型
      name: 參數名
      parameterType: 指定參數存放位置,可選header,query,path,body.form
      required: true=指定參數是否必傳,true,false
      termsOfServiceUrl: 服務條款URL
      title: 標題
      version: 版本

<name>爲swagger文檔的分組名稱,同一個項目中可以配置多個分組,用來劃分不同的API文檔。

分組配置示例

swagger:
  docket:
    group-a:
      contact:
        email: [email protected]
        name: YuanXu
        url: https://blog.csdn.net/yx_222
      description: Starter for swagger 2.x
      excludePath: /ops/**, /error
      globalOperationParameters:
      - description: some description three override
        modelRef: string
        name: name three
        parameterType: header
      termsOfServiceUrl: https://gitee.com/didispace/spring-boot-starter-swagger
      title: group-a
      basePackage: com.yuanxu.aaa
      version: 1.3.0.RELEASE
    group-b:
      title: group-b
      basePackage: com.yuanxu.bbb
      version: 1.3.0.RELEASE

默認配置與分組配置可以一起使用。在分組配置中沒有配置的內容將使用默認配置替代,所以默認配置可以作爲分組配置公共部分屬性的配置。swagger.docket.aaa.globalOperationParameters[0].name會覆蓋同名的全局配置。

公共參數配置說明

像每個接口都需要鑑權這種參數,可以在配置文件中統一定義,這樣省去每個接口再寫的麻煩,也能兼顧頁面的測試。

swagger:
  global-operation-parameters:
  - name: TOKEN
    description: 鑑權
    modelRef: string
    parameterType: header
    required: true # 公共參數寫成requierd, 對於不需要登錄的接口隨便寫一個字符串即可

忽略參數類型配置說明

基礎配置

swagger:
  ignored-parameter-types:
  - com.didispace.demo.User
  - com.didispace.demo.Product

分組配置

swagger:
  group-a:
    ignored-parameter-types:
    - com.didispace.demo.User
    - com.didispace.demo.Product

自定義全局響應消息配置說明(1.6.0 + 支持)

支持 POST,GET,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE 全局響應消息配置,具體配置內容如下:

swagger:
  apply-default-response-messages: false # 取消使用默認預定義的響應消息,並使用自定義響應消息
  global-response-message:
    get:
    - code: 401
      message: 401get
    - code: 500
      message: 500get
      modelRef: ERROR
    post:
    - code: 500
      message: 500post
      modelRef: ERROR

UI功能配置說明(1.6.0 + 支持)

調試按鈕的控制(try it out)

swagger:
  ui-config:
    submit-methods: get,delete

該參數值爲提供調試按鈕的HTTP請求類型,多個用逗號分割,如果不想開啓調試功能,只需要如下設置即可:

swagger:
  ui-config:
    submit-methods:

其他配置

swagger:
  ui-config:
    json-editor: false  # json編輯器
    request-timeout: 5000 # 頁面調試請求的超時時間
    show-request-headers: true # 顯示請求頭

更多配置說明見官方說明:https://github.com/SpringForAll/spring-boot-starter-swagger

使用Annotation添加API文檔內容

在整合完Swagger之後,在http://localhost:8080/swagger-ui.html頁面中可以看到,關於各個接口的描述還都是英文或遵循代碼定義的名稱產生的。這些內容對用戶並不友好,所以我們需要自己增加一些說明來豐富文檔內容。我們通過@Api@ApiOperation註解來給API增加說明、通過@ApiImplicitParam@ApiModel@ApiModelProperty註解來給參數增加說明。
如下所示:

UserController.java 類

/**
 *
 * @ClassName: UserController
 * @Description: 用戶管理Controller
 * @author YuanXu
 * @date 2019年10月31日 下午4:49:00
 *
 */
@Api(tags = "用戶管理")
@RestController
@RequestMapping(value = "/users") // 通過這裏配置使下面的映射都在/users下
public class UserController {

    /**
     * 創建線程安全的Map,模擬users信息的存儲
     */
    static Map<Long, User> users = Collections.synchronizedMap(new HashMap<>());

    @GetMapping("/")
    @ApiOperation(value = "獲取用戶列表")
    public List<User> getUserList() {
        List<User> r = new ArrayList<>(users.values());
        return r;
    }

    @PostMapping("/")
    @ApiOperation(value = "創建用戶", notes = "根據User對象創建用戶")
    public String postUser(@RequestBody User user) {
        users.put(user.getId(), user);
        return "success";
    }

    @GetMapping("/{id}")
    @ApiOperation(value = "獲取用戶詳細信息", notes = "根據url的id來獲取用戶詳細信息")
    public User getUser(@PathVariable Long id) {
        return users.get(id);
    }

    @PutMapping("/{id}")
    @ApiImplicitParam(paramType = "path", dataType = "Long", name = "id", value = "用戶編號", required = true, example = "1")
    @ApiOperation(value = "更新用戶詳細信息", notes = "根據url的id來指定更新對象,並根據傳過來的user信息來更新用戶詳細信息")
    public String putUser(@PathVariable Long id, @RequestBody User user) {
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    @DeleteMapping("/{id}")
    @ApiOperation(value = "刪除用戶", notes = "根據url的id來指定刪除對象")
    public String deleteUser(@PathVariable Long id) {
        users.remove(id);
        return "success";
    }
}

User.java 類

/**
 *
 * @ClassName: User
 * @Description: 用戶 實體
 * @author YuanXu
 * @date 2019年10月31日 下午4:53:23
 *
 */
@Data
@ApiModel(description = "用戶實體")
public class User {

    @ApiModelProperty("用戶編號")
    private Long id;

    @ApiModelProperty("用戶姓名")
    private String name;

    @ApiModelProperty("用戶年齡")
    private Integer age;
}

完成上述代碼添加後,啓動Spring Boot程序,訪問:http://localhost:8080/swagger-ui.html,就能看到中文說明的文檔了。

API效果查看

打開API文檔頁面地址:http://localhost:8080/swagger-ui.html

API文檔JSON數據獲取地址:http://localhost:8080/v2/api-docs

Zuul整合Swagger2彙總API接口文檔

Zuul工程pom.xml引入依賴

<!-- 引入 springboot parent ,幫我們實現了很多jar包的依賴管理 -->
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.7.RELEASE</version>
</parent>

<dependencyManagement>
  <dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Greenwich.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
	<!-- 引入spring-cloud-starter-zuul的依賴 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
	</dependency>

	<!-- 引入spring-cloud-starter-netflix-eureka-client的依賴 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>

  <!-- 引入swagger-spring-boot-starter的依賴 -->
  <dependency>
		<groupId>com.spring4all</groupId>
		<artifactId>swagger-spring-boot-starter</artifactId>
		<version>1.9.0.RELEASE</version>
	</dependency>
</dependencies>

添加DocumentationConfig.java

通過遍歷eureka路由方式自動添加所有微服務 API 文檔,SwaggerResourcesProvider 是資源提供者,我們重寫他,把各個微服務的API文檔資源路徑返回,註釋部分爲手動添加的方式。

/**
 *
 * @ClassName: DocumentationConfig
 * @Description: Zuul整合Swagger2彙總API接口文檔
 * @author YuanXu
 * @date 2019年11月1日 上午10:30:37
 *
 */
@Primary
@Component
public class DocumentationConfig implements SwaggerResourcesProvider {

    private final RouteLocator routeLocator;

    public DocumentationConfig(RouteLocator routeLocator) {
        this.routeLocator = routeLocator;
    }

    /*
     * (非 Javadoc)
     * <p>Title: get </p>
     * <p>遍歷eureka路由方式自動添加所有微服務API文檔</p>
     * <p>Author: YuanXu </p>
     * @return
     * @see com.google.common.base.Supplier#get()
     */
    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<SwaggerResource>();
        List<Route> routes = routeLocator.getRoutes();
        routes.forEach(route -> {
            resources.add(swaggerResource(route.getId(), route.getFullPath().replace("**", "v2/api-docs"), "1.0"));
        });
        return null;
    }

    /*
     * (非 Javadoc)
     * <p>Title: get </p>
     * <p>手動添加微服務API文檔</p>
     * <p>Author: YuanXu </p>
     * @return
     * @see com.google.common.base.Supplier#get()
     */
    /*
     * @Override
     * public List<SwaggerResource> get() {
     * List resources = new ArrayList<>();
     * resources.add(swaggerResource("基礎服務API文檔", "/yx-base-service/v2/api-docs", "1.0"));
     * resources.add(swaggerResource("文件服務API文檔", "/yx-file-service/v2/api-docs", "1.0"));
     * return resources;
     * }
     */

    private SwaggerResource swaggerResource(String name, String location, String version) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion(version);
        return swaggerResource;
    }

}

查看API整合效果
運行相關服務和zuul網關服務

瀏覽器輸入:http://localhost:8090/swagger-ui.html可查看API文檔整合後的效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章