SpingBoot 2.1.3集成Swagger2

252 阅读8分钟

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。

Swagger2 集成

1. 依赖

<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>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-bean-validators</artifactId>
  <version>2.9.2</version>
</dependency>

2. 配置类

package com.zjw.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;

@Configuration
@EnableSwagger2
public class Swagger2Config {

  @Bean
  public Docket buildDocket() {
    return new Docket(DocumentationType.SWAGGER_2)
      .apiInfo(buildApiInf()) // 将api的元信息设置为包含在json resourcelisting响应中
      // .host("127.0.0.1:8080") //设置ip和端口,或者域名
      .select()  // 启动用于api选择的生成器
      // .apis(RequestHandlerSelectors.any())
      .apis(RequestHandlerSelectors.basePackage("com.zjw.controller")) // 指定controller路径
      .paths(PathSelectors.any())
      .build();
  }

  private ApiInfo buildApiInf() {

    Contact contact = new Contact("筑梦之人", "https://www.zjwblog.com/", "cn.zjwblog@gmail.com");
    return new ApiInfoBuilder()
      .title("员工货物网上管理系统") // 文档标题
      .description("员工货物网上管理系统用于简化公司工作流程,公司员工只需要进行线上申报和记录即可完成相关工作,此接口文档为系统前后端工作交接文档。")//文档描述
      .contact(contact )// 联系人
      .version("v1.0") // 版本号
      .license("The Apache License, Version 2.0") // 更新此API的许可证信息
      //.licenseUrl("") // 更新此API的许可证Url
      //.termsOfServiceUrl("") // 更新服务条款URL
      .build();

  }
}

3. 在模型类中使用 Swagger 注解

package com.zjw.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 电视机实体
 */
@ApiModel(value = "Television", description = "电视机实体")
@Entity
@Table(name = "television")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Television implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)//指定主键生成的方式,AUTO 指定 H2 数据库主键自动增长
  @Column(name = "tv_id")
  @ApiModelProperty(value = "电视ID,主键字段,采用自增", name = "tvId", dataType = "Integer", required = false, example = "1", hidden = false)
  private Integer tvId; // 电视机Id
  @ApiModelProperty(value = "电视机名称", name = "tvName", dataType = "String", required = false, example = "华为荣耀智慧屏S400", hidden = false)
  @Column(name = "tv_name")
  private String tvName; // 电视名称
  @ApiModelProperty(value = "电视机价格", name = "tvPrice", dataType = "Float", required = false, example = "5999", hidden = false)
  @Column(name = "tv_price")
  private Float tvPrice; // 电视价格
  @ApiModelProperty(value = "电视机生产日期", name = "dateProduction", dataType = "Date", required = false, example = "2019-11-13T02:30:00.000+0800", hidden = false)
  @Column(name = "date_production")
  private Date dateProduction; // 生产日期
}

4. 在 Controller 中使用 Swagger 注解

package com.zjw.controller;

import com.zjw.entity.Television;
import com.zjw.result.Result;
import com.zjw.result.ResultCode;
import com.zjw.service.TelevisionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(path = "/tv")
@Api(tags = {"电视机相关业务组"}, description = "电视机相关业务组接口描述信息.")
public class TVController {
  private static final Logger logger = LoggerFactory.getLogger(TVController.class);

  @Autowired
  private TelevisionService televisionService;

  @GetMapping("")
  @ApiOperation(value = "获取所有电视机信息", notes = "获取所有电视机业务信息,正在调试中...", httpMethod = "GET")
  public Result getAll() {
    List<Television> televisions = null;
    try {
      televisions = televisionService.getAll();
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.success(televisions);
  }

  @GetMapping("/page")
  @ApiOperation(value = "根据根据page(0开始)和size,按ID排序分页获取电视机数据", notes = "需要再调试!", httpMethod = "GET")
  @ApiImplicitParams({
    @ApiImplicitParam(name = "page", value = "页码", example = "0", required = true, dataType = "int", paramType = "query"),
    @ApiImplicitParam(name = "size", value = "每页大小", example = "5", required = true, dataType = "int", paramType = "query")
  })
  public Result getAllWithPageable(
    @RequestParam(name = "page", required = false) Integer page,
    @RequestParam(name = "size", required = false) Integer size
  ) {
    Page<Television> televisions = null;
    try {
      televisions = televisionService.getAllWithPageable(page, size);
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.success(televisions);
  }

  @GetMapping("{tvId}")
  @ApiOperation(value = "根据tvId获取电视机信息", notes = "tvId必传", httpMethod = "GET")
  @ApiImplicitParam(name = "tvId", value = "电视机id", example = "1", required = true, dataType = "int", paramType = "path", defaultValue = "2")
  public Result getById(@PathVariable("tvId") Integer tvId) {
    Television tv = null;
    try {
      tv = televisionService.getById(tvId);
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.success(tv);
  }

  @PostMapping("")
  @ApiOperation(value = "修改电视机信息,要求tvId不能为空", notes = "正在调试中...", httpMethod = "POST")
  public Result update(@RequestBody Television tv) {
    try {
      televisionService.saveOrUpdate(tv);
      return Result.success(tv);
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.failure(ResultCode.PARAM_NOT_COMPLETE);
  }

  @PutMapping("")
  @ApiOperation(value = "保存电视机信息,要求tvId为空", notes = "正在调试中...", httpMethod = "PUT")
  public Result save(@RequestBody Television tv) {
    try {
      televisionService.saveOrUpdate(tv);
      return Result.success(tv);
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.failure(ResultCode.PARAM_NOT_COMPLETE);
  }

  @DeleteMapping("{tvId}")
  @ApiOperation(value = "根据tvId删除电视机信息", notes = "正在调试中...", httpMethod = "DELETE")
  @ApiImplicitParam(name = "tvId", value = "电视机id", example = "1", required = true, dataType = "int", paramType = "path", defaultValue = "3")
  public Result delete(@PathVariable("tvId") Integer tvId) {
    try {
      televisionService.deleteById(tvId);
      return Result.success(tvId);
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.failure(ResultCode.PARAM_NOT_COMPLETE);
  }
}

Swagger2常用Annotation

  • @Api: 用于类,表示标识这个类是swagger的资源.

  • @ApiOperation: 用于方法,表示一个http请求的操作

  • @ApiParam: 用于方法、参数、字段说明;表示对参数的添加元数据

  • @ApiModel: 用于类,表示对类进行说明,用于参数用实体类接受

  • @ApiModelProperty: 用于方法、字段,表示对model属性的说明或者数据操作更改

  • @ApiIgnore: 用于类、方法、方法参数,表示这个方法或者类被忽略,不在swagger-ui.html上显示

  • @ApiImplicitParam: 用于方法,表示单独的请求参数

  • @ApiImplicitParams: 用于方法,包含多个 @ApiImplicitParam

  • @ApiResponses: 用于类或者方法,描述操作的可能响应

  • @ApiResponse: 用于类或者方法,描述操作的可能响应

  • @ResponseHeader: 用于方法,响应头设置

1. @Api

  • tags 表示说明,tags如果有多个值,会生成多个列表

  • value 表示说明,可以使用tags替代

package com.zjw.controller;

@RestController
@RequestMapping(path = "/tv")
@Api(tags = {"电视机相关业务组"}, description = "电视机相关业务组接口描述信息.")
public class TVController {
  
}

2. @ApiOperation

  • value 用于方法描述

  • notes 用于提示内容

  • tags 用于API文档控制的标记列表,视情况而用,可以进行独立分组

package com.zjw.controller;

@RestController
@RequestMapping(path = "/tv")
@Api(tags = {"电视机相关业务组"}, description = "电视机相关业务组接口描述信息.")
public class TVController {
  @Autowired
  private TelevisionService televisionService;

  @GetMapping("")
  @ApiOperation(value = "获取所有电视机信息", notes = "获取所有电视机业务信息,正在调试中...", httpMethod = "GET")
  public Result getAll() {
    List<Television> televisions = null;
    try {
      televisions = televisionService.getAll();
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.success(televisions);
  }
}

3. @ApiParam

  • name 参数名

  • value 参数说明

  • required 是否必填

package com.zjw.controller;

@RestController
@RequestMapping(path = "/tv")
@Api(tags = {"电视机相关业务组"}, description = "电视机相关业务组接口描述信息.")
public class TVController {
 
  @DeleteMapping("{tvId}")
  @ApiOperation(value = "根据tvId删除电视机信息", notes = "正在调试中...", httpMethod = "DELETE")
//  @ApiImplicitParam(name = "tvId", value = "电视机id", example = "1", required = true, dataType = "int", paramType = "path", defaultValue = "3")
  public Result delete(
    @ApiParam(name = "tvId", value = "电视机id", required = true) @PathVariable("tvId") Integer tvId
  ) {
    try {
      televisionService.deleteById(tvId);
      return Result.success(tvId);
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.failure(ResultCode.PARAM_NOT_COMPLETE);
  }
}

4. @ApiModel

  • value 对象名

  • description 描述

package com.zjw.entity;

/**
 * 电视机实体
 */
@ApiModel(value = "Television", description = "电视机实体")
@Entity
@Table(name = "television")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Television implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)//指定主键生成的方式,AUTO 指定 H2 数据库主键自动增长
  @Column(name = "tv_id")
  @ApiModelProperty(value = "电视ID,主键字段,采用自增", name = "tvId", dataType = "Integer", required = false, example = "1", hidden = false)
  private Integer tvId; // 电视机Id
  @ApiModelProperty(value = "电视机名称", name = "tvName", dataType = "String", required = false, example = "华为荣耀智慧屏S400", hidden = false)
  @Column(name = "tv_name")
  private String tvName; // 电视名称
  @ApiModelProperty(value = "电视机价格", name = "tvPrice", dataType = "Float", required = false, example = "5999", hidden = false)
  @Column(name = "tv_price")
  private Float tvPrice; // 电视价格
  @ApiModelProperty(value = "电视机生产日期", name = "dateProduction", dataType = "Date", required = false, example = "2019-11-13T02:30:00.000+0800", hidden = false)
  @Column(name = "date_production")
  private Date dateProduction; // 生产日期
}

5. @ApiModelProperty

  • value 字段说明

  • name 重写属性名

  • dataType 重写属性数据类型

  • required 是否必填

  • example 举例说明

  • hidden 隐藏

package com.zjw.entity;

/**
 * 电视机实体
 */
@ApiModel(value = "Television", description = "电视机实体")
@Entity
@Table(name = "television")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Television implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)//指定主键生成的方式,AUTO 指定 H2 数据库主键自动增长
  @Column(name = "tv_id")
  @ApiModelProperty(value = "电视ID,主键字段,采用自增", name = "tvId", dataType = "Integer", required = false, example = "1", hidden = false)
  private Integer tvId; // 电视机Id
  @ApiModelProperty(value = "电视机名称", name = "tvName", dataType = "String", required = false, example = "华为荣耀智慧屏S400", hidden = false)
  @Column(name = "tv_name")
  private String tvName; // 电视名称
  @ApiModelProperty(value = "电视机价格", name = "tvPrice", dataType = "Float", required = false, example = "5999", hidden = false)
  @Column(name = "tv_price")
  private Float tvPrice; // 电视价格
  @ApiModelProperty(value = "电视机生产日期", name = "dateProduction", dataType = "Date", required = false, example = "2019-11-13T02:30:00.000+0800", hidden = false)
  @Column(name = "date_production")
  private Date dateProduction; // 生产日期
}

5. @ApiImplicitParam

  • name 参数名

  • value 参数说明

  • dataType 数据类型

  • paramType 参数类型

  • example 举例说明

package com.zjw.controller;

@RestController
@RequestMapping(path = "/tv")
@Api(tags = {"电视机相关业务组"}, description = "电视机相关业务组接口描述信息.")
public class TVController {
  
  @GetMapping("{tvId}")
  @ApiOperation(value = "根据tvId获取电视机信息", notes = "tvId必传", httpMethod = "GET")
  @ApiImplicitParam(name = "tvId", value = "电视机id", example = "1", required = true, dataType = "int", paramType = "path", defaultValue = "2")
  public Result getById(@PathVariable("tvId") Integer tvId) {
    Television tv = null;
    try {
      tv = televisionService.getById(tvId);
    } catch (Exception e) {
      logger.error("查询失败: {}", e.getMessage());
    }
    return Result.success(tv);
  }
}

6. @ApiResponses @ApiResponse

  • code 响应的HTTP状态代码

  • message 响应附带的可读消息

7. @ResponseHeader

  • name 响应头名称

  • description 头描述

  • response 默认响应类 void

  • responseContainer 参考ApiOperation中配置

生成html pdf文档

  • 新增插件
<plugins>
  <plugin>
    <groupId>io.github.swagger2markup</groupId>
    <artifactId>swagger2markup-maven-plugin</artifactId>
    <version>1.3.1</version>
    <configuration>
      <swaggerInput>http://127.0.0.1:8888/v2/api-docs</swaggerInput>
      <outputDir>./docs/asciidoc/generated</outputDir>
      <config>
        <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
      </config>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.asciidoctor</groupId>
    <artifactId>asciidoctor-maven-plugin</artifactId>
    <version>1.5.3</version>
    <!-- <version>2.0.0-RC.1</version> -->
    <!-- Include Asciidoctor PDF for pdf generation -->
    <dependencies>
      <dependency>
        <groupId>org.asciidoctor</groupId>
        <artifactId>asciidoctorj-pdf</artifactId>
        <version>1.5.0-alpha.10.1</version>
      </dependency>
      <dependency>
        <groupId>org.jruby</groupId>
        <artifactId>jruby-complete</artifactId>
        <version>1.7.21</version>
      </dependency>
    </dependencies>
    <configuration>
      <sourceDirectory>./docs/asciidoc/generated</sourceDirectory>
      <outputDirectory>./docs/html</outputDirectory>
      <backend>html</backend>
      <!--<outputDirectory>./docs/pdf</outputDirectory>-->
      <!--<backend>pdf</backend>-->
      <headerFooter>true</headerFooter>
      <doctype>book</doctype>
      <sourceHighlighter>coderay</sourceHighlighter>
      <attributes>
        <!-- 菜单栏在左边 -->
        <toc>left</toc>
        <!-- 多标题排列 -->
        <toclevels>3</toclevels>
        <!-- 自动打数字序号 -->
        <sectnums>true</sectnums>
      </attributes>
    </configuration>
  </plugin>
</plugins>
  • 生成文档
  1. 【访问URL http://localhost:8888/export/asciihttp://localhost:8888/export/asciiToFile】或者【运行swagger2markup插件】生成源文件

  2. 在子模块中运行mvn asciidoctor:process-asciidoc生成pdf或者html

  3. 访问http://localhost:8888/export/markdownToFilehttp://localhost:8888/export/markdown生成markdown文件