当前位置: 代码迷 >> 综合 >> SpringBoot 集成 Springfox Swagger 2 实时文档框架
  详细解决方案

SpringBoot 集成 Springfox Swagger 2 实时文档框架

热度:96   发布时间:2023-12-08 12:47:49.0

文章目录

        • 一、场景描述
        • 二、优点缺点
        • 三、Spring Boot 集成 Swagger
        • 四、Swagger 注解的使用

一、场景描述

Spring Boot 是为简化 Spring 应用的创建、运行、调试、部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的只需要关注业务本身而不是外部的 XML 配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工程

??随着互联网技术的发展,前后端分离的开发模式基本在所有的互联网企业都成为了一种标准。前后端程序员衔接的唯一纽带便是 API 接口,那么 API 文档成为了前后端开发人员沟通的主要方式。Swagger 就是一款让你更好的书写 API 文档的接口自动生成框架。

??没有 API 文档工具之前,基本都是手写 API 文档的,如:有在 Word 上写的、有在对应的项目目录下 Readme.md 上写的。每个公司都有每个公司的玩法,无所谓好坏。但是这种手写文档带来的弊端就是维护起来苦不堪言,对于接口容易发生变化的开发者来说,维护文档就是噩梦。

??相信无论是前端还是后端开发人员或多或少的被接口文档所折磨过,前端经常抱怨后端提供的接口文档与实际的功能不一致,后端又觉得编写和维护接口文档会耗费许多精力,经常来不及更新,不论是前端调用后端,还是后端调用后端,调用者都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟写注释一样,经常抱怨别人写的代码没有写详细的注释,然而自己写起代码来最讨厌的也是写注释。

??所以,仅仅只是依靠强制来规范是远远不够的,随着时间的推移和版本的不断迭代更新,接口文档往往很快就跟不上程序的功能了。好在现如今市场上书写 API 文档的工具有很多,常见的有 PostmanYapi、阿里的 RAP 但是能称之为框架的,估计也只有 Swagger 了,它不仅仅是一个框架,更是一个接口管理工具。

二、优点缺点

发现痛点就要去寻找解决方案,解决方案用的人多了,就慢慢的形成了一种行业规范,这就是 Swagger 的由来。作为 JAVA 程序开发者最受欢迎的 Spring 框架,看到这种简单易用的框架后,迅速将 Swagger 融入了本身。就是目前的 Springfox Swagger,通过这套规范,你只要在项目中集成 Springfox Swagger 框架,在编写接口的时候加上 Springfox Swagger 提供的标准注解,Springfox Swagger 就会帮我们自动生成接口文档,以及在线调试界面等等。做到调用者的接口文档和开发者的接口功能始终一致。

  • 集成方便且功能强大

  • 在线调试和文档自动生成

  • 代码耦合,需要 Swagger 本身提供的注解的支持,但是不影响程序的性能

    在这里插入图片描述

三、Spring Boot 集成 Swagger
  • 引入依赖

    <!-- Swagger -->
    <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version>
    </dependency><!-- 简洁 API 界面(非必要,另一种简洁等界面)-->
    <dependency><groupId>com.github.xiaoymin</groupId><artifactId>swagger-bootstrap-ui</artifactId><version>1.9.6</version>
    </dependency>
    
  • 配置信息

    package com.rambo.springbootsample.config;import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Value;
    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;/*** Copyright (C), 1998-2021, Shenzhen XXX Technology Co., Ltd* Swagger3 配置类** @author Rambo* @date 2020/7/8 17:46* @since 1.0.0.0*/
    @Configuration
    public class SwaggerConfig {
          private static final String BASE_PACKAGE = "com.rambo.springbootsample.controller";private static final String TITLE = "Spring-boot-sample演示案例";private static final String DESCRIPTION = "Spring-boot-sample演示案例,用于新模块开发参考";private static final String CONTACT_NAME = "Rambo";private static final String CONTACT_URL = "http://www.rambo123.com";private static final String CONTACT_EMAIL = "rambo1203@sina.com";private static final String LICENSE = "The Apache License";private static final String LICENSE_URL = "http://apache.org/";private static final String PROFILES = "prod";/** 迭代版本*/@Value("${platform.version}")private String platformVersion;/** 默认禁用 SWAGGER UI*/private Boolean isEnable = false;/** 获取应用程序运行概要(默认生产环境)主要区分打出日志打种类和级别*/@Value("${spring.profiles.active:prod}")private String profilesActive;@Beanpublic Docket createRestApi() {
          if (!profilesActive.equals(PROFILES)) {
          isEnable = true;}return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo()).enable(isEnable).groupName("具体开发人员所负责的功能模块,不同的人 new Docket 即可").select()// RequestHandlerSelectors 配置要扫描接口的方式// 只收集展示包含 @xxx 注解的类.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))// 只收集展示以下根目录下的类// .apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE))// PathSelectors 配置扫描的路径.paths(PathSelectors.any()).build();}private ApiInfo apiInfo() {
          return new ApiInfoBuilder().title(TITLE).description(DESCRIPTION).version(platformVersion).contact(new Contact(CONTACT_NAME, CONTACT_URL, CONTACT_EMAIL)).license(LICENSE).licenseUrl(LICENSE_URL).build();}
    }
    
  • 拦截器放行

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
          @AutowiredTokenInterceptor tokenInterceptor;/*** 拦截器* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {
          // 注册token拦截器registry.addInterceptor(tokenInterceptor).addPathPatterns("/**").excludePathPatterns("/**/swagger-ui/**").excludePathPatterns("/**/swagger-resources/**").excludePathPatterns("/**/v3/**");}
    }
    
  • 访问地址

    http://localhost:9000/sample/swagger-ui/index.html  # 如果加了定制的 UI 界面,还可以采用此方式访问
    http://localhost:9000/sample/doc.html
    
  • 注意事项

    • 生产环境中必须要关闭 Swagger

    • 生产环境关闭的操作必须采用自动的机制,人为的操作可能会疏忽

四、Swagger 注解的使用
  • @Api

    • 作用:用于指定接口或者控制器的描述文字

    • 修饰范围:用在类上

    • 示例代码:

      @RestController
      @RequestMapping("/swagger")
      @Slf4j
      @Api(tags = "用来对指定接口对象或者控制器对象的说明")
      public class SwaggerDemoController {
              ... ...
      }
      
  • @ApiOperation

    • 作用:用于对接口中具体方法的描述文字

    • 修饰范围:用在方法上

    • 示例代码:

      @GetMapping("/employees")
      @ApiOperation(value = "获取雇员列表信息", notes = "<font color='red'>描述:</font>&nbsp;&nbsp;用于查询所有雇员信息的接口")
      public DataResult<List<Employee>> listEmployeeInfo () {
              List<Employee> employeeList = employeeService.listEmployee();return DataResult.getDataResult(employeeList);
      }       
      
  • @ApiImplicitParams

  • @ApiImplicitParams

    • 作用:用于对接口中的参数进行说明,单数形式描述单个入参信息,复数形式描述多个入参信息

    • 修饰范围:用在方法上

    • 示例代码:

      @GetMapping("/employee/params")
      @ApiOperation(value = "根据 URL 问号入参获取雇员信息", notes = "<font color='red'>描述:</font>&nbsp;&nbsp;根据 URL 问号接上 id、name、age获取雇员信息雇员信息的接口")
      @ApiImplicitParams({
              @ApiImplicitParam(name = "id", value = "主键ID", dataType = "Long"),@ApiImplicitParam(name = "name", value = "雇员名字", dataType = "String"),@ApiImplicitParam(name = "age", value = "雇员年龄", dataType = "Integer")
      })
      public DataResult<Employee> saveEmployeeParams(@RequestParam("id") Long id,@RequestParam("name") String name,@RequestParam("age") Integer age) {
              log.info("id = {} , name = {} , age = {}" , id, name, age);return null;
      }
      
      @GetMapping("/employee/path/{id}/{name}/{age}")
      @ApiOperation(value = "根据 URL 地址入参获取雇员信息", notes = "<font color='red'>描述:</font>&nbsp;&nbsp;根据 URL 地址拼接id、name、age获取雇员信息雇员信息的接口")
      @ApiImplicitParams({
              @ApiImplicitParam(name = "id", value = "主键ID", dataType = "Long", paramType = "path"),@ApiImplicitParam(name = "name", value = "雇员名字", dataType = "String", paramType = "path"),@ApiImplicitParam(name = "age", value = "雇员年龄", dataType = "Integer", paramType = "path")
      })
      public DataResult<Employee> saveEmployeePath(@PathVariable("id") Long id,@PathVariable("name") String name,@PathVariable("age") Integer age) {
              log.info("id = {} , name = {} , age = {}" , id, name, age);return null;
      }      
      
      @PutMapping("save")
      @ApiOperation(value = "根据请求体 Employee 保存雇员信息", notes = "<font color='red'>描述:</font>&nbsp;&nbsp;根据请求体 Employee 保存雇员信息的接口")
      public DataResult<Integer> saveEmployee(@RequestBody Employee employee) {
              int result = employeeService.saveEmployee(employee);return DataResult.getDataResult(result);
      }
      
  • @ApiParam

    • 作用:单个参数描述,与 @ApiImplicitParam 不同的是,它是写在参数左侧的

    • 修饰范围:用在接口方法中参数上

    • 示例代码:

      @GetMapping("/employee/single/params")
      @ApiOperation(value = "根据 URL 问号入参获取雇员信息", notes = "<font color='red'>描述:</font>&nbsp;&nbsp;根据 URL 问号接上 id、name、age获取雇员信息雇员信息的接口")
      public DataResult<Employee> saveEmployeeSingleParams(@ApiParam("ID") @RequestParam("id") Long id,@ApiParam("雇员名称") @RequestParam("name") String name,@ApiParam("雇员年龄") @RequestParam("age") Integer age) {
              log.info("id = {} , name = {} , age = {}" , id, name, age);return null;
      }
      
  • @ApiModel

    • 作用:用于 POJO 的实体对象上

    • 修饰范围:POJO 实体类上

    • 示例代码:

      @ApiModel(value = "Employee - 雇员信息")
      public class Employee implements Serializable {
              ... ...
      }
      
  • @ApiProperty

    • 作用:用于 POJO 的实体对象的属性上

    • 修饰范围:POJO 实体类的属性上

    • 示例代码:

      @ApiModelProperty(value = "雇员ID")
      private Long id;@ApiModelProperty(value = "雇员名称")
      private String name;
      
  • @ApiResponses

  • @ApiResponse

    • 作用:描述接口方法的响应出参信息,单数形式描述单个出参信息,复数形式描述多个出参信息

    • 修饰范围:接口方法上

    • 示例代码:

      @PutMapping("save")
      @ApiOperation(value = "根据请求体 Employee 保存雇员信息", notes = "<font color='red'>描述:</font>&nbsp;&nbsp;根据请求体 Employee 保存雇员信息的接口")
      @ApiResponses({
              @ApiResponse(code = 200, message = "请求成功"),@ApiResponse(code = 201, message = "创建成功"),@ApiResponse(code = 401, message = "没有权限"),@ApiResponse(code = 403, message = "禁止访问"),@ApiResponse(code = 404, message = "没有资源")
      })
      public DataResult<Integer> saveEmployee(@RequestBody Employee employee) {
              int result = employeeService.saveEmployee(employee);return DataResult.getDataResult(result);
      }
      
  • @ApiIgnore

    • 作用:用于指定接口或者控制器是否需要被 Swagger 扫描显示

    • 修饰范围:用在控制器或者接口上

    • 示例代码:

      @RestController
      @RequestMapping("/swagger")
      @Slf4j
      @ApiIgnore
      @Api(tags = "Swagger API 注解使用演示控制器")
      public class SwaggerDemoController {
              
      

      P.S
      该注解加在控制器或者接口类上以后,不管该控制器或者接口中写了多少 Swagger 的注解,最终都不会被 Swagger 扫描到并生成接口文档