Spring Boot集成Swagger2项目实战

一、Swagger简介

  上一篇文章中我们介绍了Spring Boot对Restful的支持,这篇文章我们继续讨论这个话题,不过,我们这里不再讨论Restful API如何实现,而是讨论Restful API文档的维护问题。

  在日常的工作中,我们往往需要给前端(WEB端、IOS、Android)或者第三方提供接口,这个时候我们就需要给他们提供一份详细的API说明文档。但维护一份详细的文档可不是一件简单的事情。首先,编写一份详细的文档本身就是一件很费时费力的事情,另一方面,由于代码和文档是分离的,所以很容易导致文档和代码的不一致。这篇文章我们就来分享一种API文档维护的方式,即通过Swagger来自动生成Restuful API文档。

  那什么是Swagger?我们可以直接看下官方的描述:

THE WORLD'S MOST POPULAR API TOOLING
Swagger is the world's largest framework of API developer tools for the OpenAPI Specification(OAS),
enabling development across the entire API lifecycle, from design and documentation, to test and deployment.

  这段话首先告诉大家Swagger是世界上最流行的API工具,并且Swagger的目的是支撑整个API生命周期的开发,包括设计、文档以及测试和部署。这篇文章中我们会用到Swagger的文档管理和测试功能。

  对Swagger的作用有了基本的认识后,我们现在来看看怎么使用。

二、Swagger与Spring boot集成

  第一步:引入对应jar包:

<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.6.0</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.6.0</version>
</dependency>

  第二步,基本信息配置:

@Configuration
@EnableSwagger2
public class Swagger2Config {
  @Bean
  public Docket createRestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
        .apiInfo(apiInfo())
        .select()
        .apis(RequestHandlerSelectors.basePackage("com.pandy.blog.rest"))
        .paths(PathSelectors.regex("/rest/.*"))
        .build();
  }

  private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
        .title("Blog系统Restful API")
        .description("Blog系统Restful API")
        .termsOfServiceUrl("http://127.0.0.1:8080/")
        .contact("liuxiaopeng")
        .version("1.0")
        .build();
  }
}

  基础的配置是对整个API文档的描述以及一些全局性的配置,对所有接口起作用。这里涉及到两个注解:

  @Configuration是表示这是一个配置类,是JDK自带的注解,前面的文章中也已做过说明。

  @EnableSwagger2的作用是启用Swagger2相关功能。

  在这个配置类里面我么实例化了一个Docket对象,这个对象主要包括三个方面的信息:

    (1)整个API的描述信息,即ApiInfo对象包括的信息,这部分信息会在页面上展示。

    (2)指定生成API文档的包名。

    (3)指定生成API的路径。按路径生成API可支持四种模式,这个可以参考其源码:

public class PathSelectors {
  private PathSelectors() {
    throw new UnsupportedOperationException();
  }

  public static Predicate<String> any() {
    return Predicates.alwaysTrue();
  }

  public static Predicate<String> none() {
    return Predicates.alwaysFalse();
  }

  public static Predicate<String> regex(final String pathRegex) {
    return new Predicate<String>() {
      public boolean apply(String input) {
        return input.matches(pathRegex);
      }
    };
  }

  public static Predicate<String> ant(final String antPattern) {
    return new Predicate<String>() {
      public boolean apply(String input) {
        AntPathMatcher matcher = new AntPathMatcher();
        return matcher.match(antPattern, input);
      }
    };
  }
}

  从源码可以看出,Swagger总共支持任何路径都生成、任何路径都不生成以及正则匹配和ant 模式匹配四种方式。大家可能比较熟悉的是前三种,最后一种ant匹配,如果不熟悉ant的话就直接忽略吧,前三种应该足够大家在日常工作中使用了。

  有了上面的配置我们就可以看到效果了,我在com.pandy.blog.rest这个包下面有一个ArticleRestController这个类,源码如下:

  启动Spring boot,然后访问:http://127.0.0.1:8080/swagger-ui.html即可看到如下结果:

  这个页面上可以看到,除了最后一个接口/test/{id}外,其他接口都生成对应的文档,最后一个接口因为不满足我们配置的路径——“/rest/.*”,所以没有生成文档。

  我们还可以点进去看一下每一个具体的接口,我们这里以“POST /rest/article”这个接口为例:

  可以看到,Swagger为每一个接口都生成了返回结果和请求参数的示例,并且能直接通过下面的"try it out"进行接口访问,方面大家对接口进行测试。整体上感觉Swagger还是很强大的,配置也比较简单。

@RestController
public class ArticleRestController {
  @Autowired
  private ArticleService articleService;
  @RequestMapping(value = "/rest/article", method = POST, produces = "application/json")
  public WebResponse<Map<String, Object>> saveArticle(@RequestBody Article article) {
    article.setUserId(1L);
    articleService.saveArticle(article);
    Map<String, Object> ret = new HashMap<>();
    ret.put("id", article.getId());
    WebResponse<Map<String, Object>> response = WebResponse.getSuccessResponse(ret);
    return response;
  }
  @RequestMapping(value = "/rest/article/{id}", method = DELETE, produces = "application/json")
  public WebResponse<?> deleteArticle(@PathVariable Long id) {
    Article article = articleService.getById(id);
    article.setStatus(-1);
    articleService.updateArticle(article);
    WebResponse<Object> response = WebResponse.getSuccessResponse(null);
    return response;
  }
  @RequestMapping(value = "/rest/article/{id}", method = PUT, produces = "application/json")
  public WebResponse<Object> updateArticle(@PathVariable Long id, @RequestBody Article article) {
    article.setId(id);
    articleService.updateArticle(article);
    WebResponse<Object> response = WebResponse.getSuccessResponse(null);
    return response;
  }
  @RequestMapping(value = "/rest/article/{id}", method = GET, produces = "application/json")
  public WebResponse<Article> getArticle(@PathVariable Long id) {
    Article article = articleService.getById(id);
    WebResponse<Article> response = WebResponse.getSuccessResponse(article);
    return response;
  }
  @RequestMapping(value = "/test/{id}", method = GET, produces = "application/json")
  public WebResponse<?> getNoApi(){
    WebResponse<?> response = WebResponse.getSuccessResponse(null);
    return response;
  }
}

三、Swagger API详细配置

  不过大家看到这里肯定会有点疑问:

    第一个问题:这个返回结果和请求参数都没有文字性的描述,这个可不可以配置?

    第二个问题:这个请求参应该是直接根据对象反射出来的结果,但是不是对象的每个属性都是必传的,另外参数的值也不一定满足我们的需求,这个能否配置?

  答案肯定是可以的,现在我们就来解决这两个问题,直接看配置的代码:

package com.pandy.blog.rest;
import com.pandy.blog.dto.WebResponse;
import com.pandy.blog.po.Article;
import com.pandy.blog.service.ArticleService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
@RestController
@RequestMapping("/rest")
public class ArticleRestController {
  @Autowired
  private ArticleService articleService;
  @RequestMapping(value = "/article", method = POST, produces = "application/json")
  @ApiOperation(value = "添加文章", notes = "添加新的文章", tags = "Article",httpMethod = "POST")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "title", value = "文章标题", required = true, dataType = "String"),
      @ApiImplicitParam(name = "summary", value = "文章摘要", required = true, dataType = "String"),
      @ApiImplicitParam(name = "status", value = "发布状态", required = true, dataType = "Integer")
  })
  @ApiResponses({
      @ApiResponse(code=200,message="成功",response=WebResponse.class),
  })
  public WebResponse<Map<String,Object>> saveArticle(@RequestBody Article article){
    articleService.saveArticle(article);
    Map<String,Object> ret = new HashMap<>();
    ret.put("id",article.getId());
    WebResponse<Map<String,Object>> response = WebResponse.getSuccessResponse(ret);
    return response;
  }
  @ApiOperation(value = "删除文章", notes = "根据ID删除文章", tags = "Article",httpMethod = "DELETE")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "id", value = "文章ID", required = true, dataType = "Long")
  })
  @RequestMapping(value = "/{id}",method = DELETE,produces = "application/json")
  public WebResponse<?> deleteArticle(@PathVariable Long id){
    Article article = articleService.getById(id);
    article.setStatus(-1);
    articleService.saveArticle(article);
    return WebResponse.getSuccessResponse(new HashMap<>());
  }
  @ApiOperation(value = "获取文章列表", notes = "可以根据标题进行模糊查询", tags = "Article",httpMethod = "GET")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "title", value = "文章标题", required = false, dataType = "String"),
      @ApiImplicitParam(name = "pageSize", value = "每页文章数量", required = false, dataType = "Integer"),
      @ApiImplicitParam(name = "pageNum", value = "分页的页码", required = false, dataType = "Integer")
  })
  @RequestMapping(value = "/article/list", method = GET, produces = "application/json")
  public WebResponse<?> listArticles(String title, Integer pageSize, Integer pageNum) {
    if (pageSize == null) {
      pageSize = 10;
    }
    if (pageNum == null) {
      pageNum = 1;
    }
    int offset = (pageNum - 1) * pageSize;
    List<Article> articles = articleService.getArticles(title, 1L, offset, pageSize);
    return WebResponse.getSuccessResponse(articles);
  }
  @ApiOperation(value = "更新文章", notes = "更新文章内容", tags = "Article",httpMethod = "PUT")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "id", value = "文章ID", required = true, dataType = "Long"),
      @ApiImplicitParam(name = "title", value = "文章标题", required = false, dataType = "String"),
      @ApiImplicitParam(name = "summary", value = "文章摘要", required = false, dataType = "String"),
      @ApiImplicitParam(name = "status", value = "发布状态", required = false, dataType = "Integer")
  })
  @RequestMapping(value = "/article/{id}", method = PUT, produces = "application/json")
  public WebResponse<?> updateArticle(@PathVariable Long id,@RequestBody Article article){
    article.setId(id);
    articleService.updateArticle(article);
    return WebResponse.getSuccessResponse(new HashMap<>());
  }
}

  我们解释一下代码中几个注解及相关属性的具体作用:

  @ApiOperation,整个接口属性配置:

    value:接口说明,展示在接口列表。

    notes:接口详细说明,展示在接口的详情页。

    tags:接口的标签,相同标签的接口会在一个标签页下展示。

    httpMethod:支持的HTTP的方法。

  @ApiImplicitParams,@ApiImplicitParam的容器,可包含多个@ApiImplicitParam注解

  @ApiImplicitParam,请求参数属性配置:

    name:参数名称

    value:参数说明

    required:是否必须

    dataType:数据类型  

  @ApiResponses,@ApiResponse容器,可以包含多个@ApiResponse注解

  @ApiResponse,返回结果属性配置:

    code:返回结果的编码。

    message:返回结果的说明。

    response:返回结果对应的类。    

  完成以上配置后,我们再看下页面效果:

列表页:   

         

  可以看到,现在接口都位于Article这个tag下,并且接口后面也有了我们配置好的说明。我们再看下”POST /rest/article“这个接口的详情页:

  图片太大,只截取了title属性的展示,其他几个参数的类似。我们可以从页面上看到请求参数的说明是有的,不过这不是我们预期的效果,如果我们的参数仅仅是简单类型,这种方式应该没问题,但现在的问题是我们的请求参数是一个对象,那如何配置呢?这就涉及到另外两个注解:@ApiModel和@ApiModelProperty,我们还是先看代码,然后再解释,这样更容易理解:

@ApiModel(value="article对象",description="新增&更新文章对象说明")
public class Article {
  @Id
  @GeneratedValue
  @ApiModelProperty(name = "id",value = "文章ID",required = false,example = "1")
  private Long id;
  @ApiModelProperty(name = "title",value = "文章标题",required = true,example = "测试文章标题")
  private String title;
  @ApiModelProperty(name = "summary",value = "文章摘要",required = true,example = "测试文章摘要")
  private String summary;
  @ApiModelProperty(hidden = true)
  private Date createTime;
  @ApiModelProperty(hidden = true)
  private Date publicTime;
  @ApiModelProperty(hidden = true)
  private Date updateTime;
  @ApiModelProperty(hidden = true)
  private Long userId;
  @ApiModelProperty(name = "status",value = "文章发布状态",required = true,example = "1")
  private Integer status;
  @ApiModelProperty(name = "type",value = "文章分类",required = true,example = "1")
  private Integer type;
}

  @ApiModel是对整个类的属性的配置:

    value:类的说明

    description:详细描述

  @ApiModelProperty是对具体每个字段的属性配置:

    name:字段名称

    value:字段的说明

    required:是否必须

    example:示例值

    hidden:是否显示

  完成上面的配置后,我们再来看效果:

  现在我们可以看到,字段的说明都已经展示出来,并且,示例中字段的值也变成了我们配置的example属性对应的值了。这样,一份完整的API文档就生成了,并且该文档与代码紧密的联系在一起,而不是隔离的两个部分。除此之外,我们还可以直接通过该文档很方便的进行测试,我们只需要点击Example Value下黄色的框,里面的内容就会自动复制到article对应的value框中,然后在点击“Try it out”就可以发起http请求了。

  点击Try it out后,我们就可以看到返回的结果:

  操作还是很方便的,相比Junit和postman,通过Swagger来测试会更加便捷,当然,Swagger的测试并不能代替单元测试,不过,在联调的时候还是有非常大的作用的。

四、总结

  总体上来说,Swagger的配置还是比较简单的,并且Swagger能够自动帮我们生成文档确实为我们节省了不少工作,对后续的维护也提供了很大的帮助。除此之外,Swagger还能根据配置自动为我们生成测试的数据,并且提供对应的HTTP方法,这对我们的自测和联调工作也有不少的帮助,所以我还是推荐大家在日常的开发中去使用Swagger,应该可以帮助大家在一定程度上提高工作效率的。最后,留一个问题给大家思考吧,就是该文档是可以直接通过页面来访问的,那我们总不能把接口直接暴露在生产环境吧,尤其是要对外提供服务的系统,那我们怎么才能在生产环节中关闭这个功能呢?方法有很多,大家可以自己尝试一下。

以上所述是小编给大家介绍的Spring Boot集成Swagger2项目实战,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

您可能感兴趣的文章:

  • 详解如何在SpringBoot里使用SwaggerUI
  • Spring Boot 项目中使用Swagger2的示例
  • Springboot中集成Swagger2框架的方法
  • SpringBoot集成swagger的实例代码
  • SpringBoot集成Swagger2实现Restful(类型转换错误解决办法)
  • springboot + swagger 实例代码
  • spring-boot 禁用swagger的方法
(0)

相关推荐

  • SpringBoot集成swagger的实例代码

    Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件.本文简单介绍了在项目中集成swagger的方法和一些常见问题.如果想深入分析项目源码,了解更多内容,见参考资料. Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步.Swagger 让部署管理和使用功能强大的API从未如此简单. 对于

  • Spring Boot 项目中使用Swagger2的示例

    本文介绍了Spring Boot 项目中使用Swagger2的示例,分享给大家,具体如下: 添加Swagger2依赖 在pom.xml中加入Swagger2的依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.2.2</version> </dependency&g

  • Springboot中集成Swagger2框架的方法

    摘要:在项目开发中,往往期望做到前后端分离,也就是后端开发人员往往需要输出大量的服务接口,接口的提供方无论是是Java还是PHP等语言,往往会要花费一定的精力去写接口文档,比如A接口的地址.需要传递参数情况.返回值的JSON数据格式以及每一个字段说明.当然还要考虑HTTP请求头.请求内容等信息.随着项目的进度快速高速的迭代,后端输出的接口往往会面临修改.修复等问题,那也意味着接口文档也要进行相应的调整.接口文档的维护度以及可读性就大大下降. 既然接口文档需要花费精力去维护,还要适当的进行面对面交

  • spring-boot 禁用swagger的方法

    在使用spring-boot开发的时候,我们很多时候会使用swagger作为api文档输出.可以在UI界面上看到api的路径,参数等等. 当然,作为开发环境是很方便的,但是上生产环境的时候,我们需要把swagger禁掉.怎么通过配置文件的方法来禁用swagger呢? 代码如下: import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cont

  • 详解如何在SpringBoot里使用SwaggerUI

    Swagger Swagger是一种和语言无关的规范和框架,用于定义服务接口,主要用于描述RESTful的API.它专注于为API创建优秀的文档和客户端库.支持Swagger的API可以为API方法生成交互式的文档,让用户可以通过以可视化的方式试验,查看请求和响应.头文件和返回代码,从而发现API的功能. swagger用于定义API文档. 好处: 前后端分离开发 API文档非常明确 测试的时候不需要再使用URL输入浏览器的方式来访问Controller 传统的输入URL的测试方式对于post请

  • springboot + swagger 实例代码

    swagger用于定义API文档. 好处: 前后端分离开发 API文档非常明确 测试的时候不需要再使用URL输入浏览器的方式来访问Controller 传统的输入URL的测试方式对于post请求的传参比较麻烦(当然,可以使用postman这样的浏览器插件) spring-boot与swagger的集成简单的一逼 1.项目结构 和上一节一样,没有改变. 2.pom.xml 引入了两个jar. <dependency> <groupId>io.springfox</groupId

  • SpringBoot集成Swagger2实现Restful(类型转换错误解决办法)

    pom.xml增加依赖包 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <

  • Spring Boot集成Swagger2项目实战

    一.Swagger简介 上一篇文章中我们介绍了Spring Boot对Restful的支持,这篇文章我们继续讨论这个话题,不过,我们这里不再讨论Restful API如何实现,而是讨论Restful API文档的维护问题. 在日常的工作中,我们往往需要给前端(WEB端.IOS.Android)或者第三方提供接口,这个时候我们就需要给他们提供一份详细的API说明文档.但维护一份详细的文档可不是一件简单的事情.首先,编写一份详细的文档本身就是一件很费时费力的事情,另一方面,由于代码和文档是分离的,所

  • Spring Boot 集成 Swagger2构建 API文档

    目录 一.Swagger是什么 1.SwaggerEditor 2.SwaggerUI 3.SwaggerCodegen 4.SwaggerUI 二.SpringBoot集成Swagger 1.创建SpringBoot项目 2.引入依赖 3.构建Swagger配置类 4.编写接口 5.查看并测试接口 前言: 不管你是从事前端还是后端开发,相信都难免被接口文档折磨过.如果你是一个前端开发者,可能你会经常发现后端给的接口文档跟实际代码有所出入.而假设你是一个后端开发者,你可能又会觉得自己开发后端接口

  • Spring boot集成swagger2生成接口文档的全过程

    一.Swagger介绍 Swagger是一个规范和完整的框架,用于生成.描述.调用和可视化RESTful风格的web服务.目标是使客户端和文件系统作为服务器以同样的速度来更新文件的方法,参数和模型紧密集成到服务器.这个解释简单点来讲就是说,swagger是一款可以根据restful风格生成的接口开发文档,并且支持做测试的一款中间软件. 二.使用swagger优势 1.对于后端开发人员来说 不用再手写Wiki接口拼大量参数,避免手写错误 对代码侵入性低,采用全注解的方式,开发简单 方法参数名修改.

  • Spring Boot集成Druid出现异常报错的原因及解决

    Spring Boot集成Druid异常 在Spring Boot集成Druid项目中,发现错误日志中频繁的出现如下错误信息: discard long time none received connection. , jdbcUrl : jdbc:mysql://******?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8, version : 1.2.3, las

  • spring boot 集成shiro的配置方法

    spring boot提供了一个自带的认证框架,同时也提供自定义的javaconfig配置扩展,spring-sercurity同样也是优秀的框架,但是习惯了用apache shiro框架,而且原项目就是集成的shiro框架,到网上找了一下配置方式,没找到完全配置的方法,因此决定自己动手,丰衣足食! 要在spring boot上集成其他框架,首先要会spring javaconfig方法,利用此方法同样可以配置其他模块,废话少说,开始... 开始前需要导入maven依赖(shiro-web可选)

  • spring boot集成shiro详细教程(小结)

    我们开发时候有时候要把传统spring shiro转成spring boot项目,或者直接集成,name我们要搞清楚一个知识,就是 xml配置和spring bean代码配置的关系,这一点很重要,因为spring boot是没有xml配置文件的(也不绝对,spring boot也是可以引用xml配置的) 引入依赖: <dependency> <artifactId>ehcache-core</artifactId> <groupId>net.sf.ehcac

  • Spring Boot集成 Spring Boot Admin 监控

    [前言] 程序开发完实现相应的功能只是一个部分,如何让系统在线上运行更好创造更高的价值是另外一个部分:监控是一个生产级项目避不可少重要组成部分:最近研究一下针对SpringBoot的监控项目---Spring Boot Admin,并集成项目中,在此与大家共享: [SpringBootAdmin] 一.SpringBootAdmin简介 1.github地址:https://github.com/codecentric/spring-boot-admin 2.重要功能列表: 二.项目中集成Spr

  • Spring Boot 集成接口管理工具 Knife4j

    目录 前言 集成过程 创建 Spring Boot 项目 添加依赖 配置添加 编写 Controller 层 启动测试 踩过的坑 空指针异常 请求路径未找到 总结 前言 之前介绍了如何在 Spring Boot 中集成 Swagger2 和 Swagger3,对于我们日常的接口管理已经够用了.但是作为一个颜值党,无论是 Swagger2 还是 Swagger3,都难以满足我们的审美.而且 Swagger2 和 Swagger3 都已经好久没更新了,更新还是比较慢的. 偶然之间发现了一个国产的接口

  • Spring Boot 集成Mybatis实现主从(多数据源)分离方案示例

    本文将介绍使用Spring Boot集成Mybatis并实现主从库分离的实现(同样适用于多数据源).延续之前的Spring Boot 集成MyBatis.项目还将集成分页插件PageHelper.通用Mapper以及Druid. 新建一个Maven项目,最终项目结构如下: 多数据源注入到sqlSessionFactory POM增加如下依赖: <!--JSON--> <dependency> <groupId>com.fasterxml.jackson.core<

  • 详解spring Boot 集成 Thymeleaf模板引擎实例

    今天学习了spring boot 集成Thymeleaf模板引擎.发现Thymeleaf功能确实很强大.记录于此,供自己以后使用. Thymeleaf: Thymeleaf是一个java类库,他是一个xml/xhtml/html5的模板引擎,可以作为mvc的web应用的view层. Thymeleaf还提供了额外的模块与Spring MVC集成,所以我们可以使用Thymeleaf完全替代jsp. spring Boot 通过org.springframework.boot.autoconfigu

随机推荐