博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
手把手教你如何玩转Swagger
阅读量:4125 次
发布时间:2019-05-25

本文共 12809 字,大约阅读时间需要 42 分钟。

文章目录

情景引入

  • 小白:起床,起床,,赶快起床!!!!
  • 我:你又怎么了呢~~好不容易有个假期,都不能消停消停的吗?
  • 小白:我也想你多休息,但是我又遇到问题了,需要你的帮助~
  • 我:说说,你又遇到什么问题了呢?这么火急火燎的 ~ 真烦人
  • 小白:你是知道的,我们平常开发都是有接口开发文档的,但是,前后端处理挺麻烦的,而且更新又不及时,有时候字段改了,又不及时通知,然后调试的时候就出Bug,到最后谁也说不清楚,还引来一堆麻烦事和无用功。
  • 我:对的,接口开发文档是非常必须的,这个可以便于沟通和交流。然后呢?~
  • 小白:我就在想,有没有好的办法,可以方便进行开发文档的交流呢?需求的改变很头疼,开发文档的改变也很头疼的呢。
  • 我:emmmmmmmmmm,这个嘛,容我想想。
  • 我:既然,你有这样的需求的话,那么好的,我就好好给你上一课,那你可要好好的听哦~
  • 小白:小板凳,都搬来了··········

Swagger描述

接口开发文档的那些事

接口开发文档对于我们程序员来说,这是非常普通的东西了,而且在前后端分离来说,则是对于前端和后端人员进行沟通的一大法宝。但是,这也有一定的局限性,就是无法及时的进行更新和交流。对于我们平常来说,我们可以采取的开发文档的形式有:

  1. Word文件:简单,但是开起来真麻烦
  2. redmine:一个开源的项目管理软件,可视化,功能强大,但是界面太花哨,细节很多,无法捕捉到重点
  3. Teambition:很好,但是,需要费用,只能免费使用一定时间
  4. Xmind:一种思维导图的形式,客观性好,但是编写麻烦
  5. Showdoc:这是非常好的软件,可控性也比较强,个人自己用得也比较多。
  6. PostMan: 这不只能进行接口调试,还可以进行接口文档管理的
  7. MinDoc :这个也还行吧。。知道的人很少
  8. RAP : 这个也非常不错,大家可以试试
    基本的话,自己主要用的也就是上面这些啦(还有些其他的,大家可以留言哦)。
    我们可以观察到,上面这些方法,都有一个共性,就是项目和接口文档的管理是分开的,这样实时性肯定会存在问题,另外的话,管理起来也不是非常方便,使用起来也许多多个不同界面的来回管理。
    那么,既然有了这个问题,有什么办法可以解决的呢?当然有的,根据自己的经历吧,我就来讲解一个工具------Swagger

Swagger是啥呢?

总的来说:

  1. Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
  2. 总体目标是使客户端和文件系统作为服务器以同样的速度来更新。
  3. 文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
  4. Swagger是国外使用非常多的,就类似我们国内一般使用Showdoc一样。
  5. Swagger集成方便,可视化强大
  6. Swagger集接口文档和测试于一体,就类比将postman和showdoc的结合体
    细一点来说:
    Swagger是一组开源项目,其中主要要项目如下:
  • Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.0文档等功能。
  • Swagger-core: 用于Java/Scala的的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF…)、Servlets和Play框架进行集成。
  • Swagger-js: Swagger通过JavaScript来进行实现。
  • Swagger-node-express: Swagger模块,用于node.js的Express web应用框架
  • Swagger-ui:一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。(界面的效果就是这个模块
  • Swagger-codegen:代码生成器,脚手架。可以根据swagger.json或者swagger.yml文件生成指定的计算机语言指定框架的代码。(用得比较少)

开发环境

架构:SpringBoot +Mybatis + Mysql

系统软件:Idea + win7
具体的集成步骤都在我的博文有详细的介绍

开发步骤(小试牛刀)

  1. 搭建基本的SpringBoot+Mybatis+Mysql的环境(这个在开发环境中已经说明)
  2. 引入Swagger的pom依赖
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2

备注:版本的话,自己根据需求来即可,不一定就要用我的版本

  1. 编写Swagger的配置类
    备注:这个类的话,要与springboot的启动类在同级即可
package com.scw.springboot.swagger.config;import io.swagger.annotations.ApiOperation;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;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.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;/** * @ Author     :scw * @ Date       :Created in 上午 11:44 2018/12/5 0005 * @ Description:对于swagger的配置类,@Configuration表示是一个配置类,@EnableSwagger2表示是swagger的配置 *                ConditionalOnProperty注解是对于是否开启了swagger的灵活配置(这个适合在开发环境中开启,而正式的时候应该关闭) * @ Modified By: * @Version: 1 */@Configuration@EnableSwagger2@ConditionalOnProperty(prefix = "swagger", name = "button-open", havingValue = "true")public class SwaggerConfig {    /**     * 创建获取api应用     * @return     */    @Bean    public Docket createRestApi() {        return new Docket(DocumentationType.SWAGGER_2)                .apiInfo(apiInfo())                .select()                //这里采用包含注解的方式来确定要显示的接口(建议使用这种)                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))                //.apis(RequestHandlerSelectors.basePackage("com.scw.springboot.swagger.controller"))    //这里采用包扫描的方式来确定要显示的接口                .paths(PathSelectors.any())                .build();    }    /**     * 配置swagger文档显示的相关内容标识(信息会显示到swagger页面)     * @return     */    private ApiInfo apiInfo() {        return new ApiInfoBuilder()                .title("swagger使用")                .description("本人博客地址如下:")                .termsOfServiceUrl("https://blog.csdn.net/Cs_hnu_scw")                .contact("hnuscw")                .version("1.0")                .build();    }}

    1. 编写application.properties文件
      备注:因为我的swagger的类中是采用了“开关”来控制,是否要进行swagger的处理的,而我的开关的控制就在application.properties文件中,所以,需要稍微编写即可。
    # Swagger相关的配置,这个要与swagger的配置类中设置一样即可,不需要说完全和我写的一样都是可以的哦!!!!swagger.button-open = true
    1. 编写controller层代码
      备注:因为Swagger是一种进行前后端文档开发的方便,所以,既然是开发文档的处理,那么很明显就是要在controller层的代码进行相关的处理了,那么如何进行处理的话,就看下面的简单内容。
    package com.scw.springboot.swagger.controller;import com.scw.springboot.swagger.model.Person;import com.scw.springboot.swagger.service.PersonService;import io.swagger.annotations.*;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;/** * @author scw * @create 2018-01-03 10:31 * @desc swagger的牛刀小试 **/@Controller@Api(value = "swagger牛刀小试")public class PersonController {    @Autowired    public PersonService personService;    /**     * 根据ID查询数据     * @param id     * @return 返回字符串     */    @ApiOperation(value = "测试根据id获取用户信息的方法(1)" ,notes="测试查询方法", tags = {"query"})    @ApiImplicitParam(paramType = "query", name = "id", value = "用户Id", required = true, dataType = "int")    @RequestMapping(value = "person/getperson1", method = RequestMethod.GET)    @ResponseBody    public String queryPerson1(@RequestParam Integer id ){        Person person = personService.getPersonById(id);        return "hello";    }}
    1. 启动我们的SpringBoot项目
      备注:
      springboot的启动方式,我就不多说了,稍微提一下
      (1)main方法的启动,这也是我们开发中用得最多的形式。
      (2)jar包启动,因为springboot是自带maven管理的,所以,可以先用maven打成jar包,然后在控制台(CMD)中运行java 的jar包的命令也是可以。
      (3)war包启动:这种一般是上线的形式,打成一个war包,然后放到服务器tomcat中来进行运行。这个类型第二种方法,只是需要把pom中的jar修改成war格式即可。
      在这里插入图片描述
    2. 访问项目地址
    3. 查看效果
      在这里插入图片描述
    4. 大功告成
      通过上面的这些步骤,我们就可以看到在线的开发文档啦。是不是挺方便的呢?

    项目结构

    在这里插入图片描述

    好好看,这些细节你不能放过

    备注:虽然,我们通过前面的知识,大体的已经对Swagger有了了解,并且也搭了最简单的环境,但是,这都还只是皮毛,我们应该认真的分析里面的内容,便于我们以后集成到我们项目,来方便前后端的交流,所以,下面这些内容你应该都要深度了解。

    出现如下的问题(非常普遍)

    访问链接弹出提示框(如下)

    备注:Swagger Unable to infer base url 问题

    在这里插入图片描述
    **原因:**其实这个是因为Swagger无法对我们要进行扫描的controller进行标识,所以,导致内容无法进行显示,而提示这个URL链接。
    解决方法:
    方法(1)在我们的Controller层的类代码添加Swagger的注解。

    @Api(value = "XXXXX")public class PersonController {

    如:

    在这里插入图片描述
    方法二(2)在Swagger的配置类中添加注解@EnableSwagger2
    如:
    在这里插入图片描述

    页面中的测试方法无反应

    描述:在这里插入图片描述

    **原因:**这个的话,我们要保证一点,就是我们先测试了controller的代码是正常的(就是说逻辑不存在问题,这样才保证是由于swagger的某些地方出现问题)。这个点了没反应并不是说没有执行还是什么,而是由于程序出现了问题。具体的原因,就是因为我们测试的方法中的参数类型和设置不一致而导致
    **解决方法:**确保接受参数类型和设置类型一致
    比如:
    在这里插入图片描述
    **描述:**就是大致一看,都是Integer不是一样吗?其实,不是的,在dataType中,我们不需要用包装类型,而是用对应的基本类型即可,所以,Integer使用int,Long 使用long就好了,否则就会发生我描述的这个问题。
    分析:其实这个问题,我也看了很多内容,发现很多人都是用的dataType=Integer这样的博文,但是我无法保证他们是否真正有进行测试过,还有就是不知道是不是版本的原因,因为我用的是2.9的版本(试过其他的版本,我测的都是一样的结果)。所以,我这里建议采取基本类型对应就好,不需要使用包装类型

    为什么一个方法有在页面中有很多测试方法出现

    **描述:**如果所示

    在这里插入图片描述
    **原因:**是由于在代码中没有设置该参数是需要哪一种处理方式,所以swagger就给每一种都设置了处理的形式(哈哈,是不是太友好了点呢!!!)。
    **解决方法:**设置一种接受方式
    如:设置为POST方式

    @RequestMapping(value = "person/getperson4", method = RequestMethod.POST)

      Swagger关键注解的使用情况

      备注:Swagger的话,主要就是那么几个注解,但是使用起来,不是很熟悉的话还是容易产生很多问题的,所以,我这里重点分析一下。

      @Api

      使用地点

      作用于类上(类型@controller注解),用于标识是一个Swagger的资源类

      参数

      value :描述说明

      tag:也是描述说明,类型value,个人习惯使用value

      @ApiOperation

      使用地点

      用于方法;表示一个http请求的操作

      参数

      value :对该方法的描述说明

      notes:用于提示内容
      tags:API分组(类似将一个班的同学分多少组)

      实例效果

      @ApiOperation(value = "测试根据id获取用户信息的方法(1)" ,notes="测试查询方法", tags = {"query"})

      • 1
      • 2

      在这里插入图片描述

      @ApiParam

      使用地点

      用于方法,参数,字段说明;表示对参数的添加元数据(说明或是否必填等)

      参数

      name:参数名(中文,英文都可以,用于显示)

      value:参数说明 (需要与接受参数一致)
      required:是否必填

      实例

      public Object queryPerson6( @ApiParam(name = "id",required = true,value = "用户ID")                                       @RequestParam Integer id ) 
      1
      2

      @ApiImplicitParam

      使用地点

      用于方法,主要对于接受参数的设置

      参数

      name:参数ming

      value:参数说明
      dataType:数据类型
      paramType:参数类型
      example:举例说明
      defaultValue:参数的默认值

      实例

      @ApiImplicitParam(paramType = "query", name = "id", value = "用户Id", required = true, dataType = "int")

      @ApiImplicitParams()

      使用地点

      用于方法,包含多个 @ApiImplicitParam

      参数

      无特别参数

      实例

      @ApiOperation(value = "测试多个参数(5)" ,notes="测试查询方法", tags = {"query"})    @ApiImplicitParams({            @ApiImplicitParam(paramType = "query", name = "id", value = "用户Id", required = true, dataType = "int"),            @ApiImplicitParam(paramType = "query", name = "userName", value = "用户名", required = true, dataType = "String"),    })    @RequestMapping(value = "person/getperson5", method = RequestMethod.GET)    @ResponseBody    public Object queryPerson5( @RequestParam String userName,                                @RequestParam Integer id ){        return "success";    }

      @ApiIgnore

      使用地方

      用于类或者方法上,可以不被swagger显示在页面上,不经常用

      参数

      value:描述值

      @ApiModel

      使用地方

      用于实体类javabean ;表示对类进行说明,用于参数用实体类接收(当接受的参数是实体的时候,则必须用这个修饰实体类)

      参数

      value:表示对象名

      description:描述
      其实参数一般都不写

      实例

      @ApiModel(value = "用户实体模型")public class Person {

      @ApiModelProperty

      使用地方

      用于方法,字段(实体类中); 表示对model属性的说明或者数据操作更改

      参数

      value:字段说明

      name:重写属性名字
      dataType:重写属性类型
      required:是否必填
      example:举例说明
      hidden:隐藏

      实例

      @ApiModelProperty(value = "用户id", required = true)    private Integer id;    @ApiModelProperty(value = "用户名", required = true)    private String name;

      在这里插入图片描述

      多种不同的接受参数的方式

      备注:我们在方法的接受参数和返回形式中,都会有很多的方式,那么根据不同的效果,我们也会采取不同的处理,所以,这里就主要讲解一下,多种不同的处理方法。

      返回单纯的String字符串

      /**     * 根据ID查询数据     * @param id     * @return 返回字符串     */    @ApiOperation(value = "测试根据id获取用户信息的方法(1)" ,notes="测试查询方法", tags = {"query"})    @ApiImplicitParam(paramType = "query", name = "id",                 value = "用户Id", required = true, dataType = "Integer")    @RequestMapping(value = "person/getperson1", method = RequestMethod.GET)    @ResponseBody    public String queryPerson1(@RequestParam Integer id ){        Person person = personService.getPersonById(id);        return "hello";    }

      返回实体Json

      /**     * 根据ID查询数据     * @param id     * @return 返回实体的json格式     */    @ApiOperation(value = "测试根据id获取用户信息的方法(2)" ,notes="测试查询方法", tags = {"query"})    @ApiImplicitParam(paramType = "query", name = "id", value = "用户Id", required = true, dataType = "int")    @RequestMapping(value = "person/getperson2", method = RequestMethod.GET)    @ResponseBody    public Object queryPerson2(@RequestParam Integer id , Model model){        Person person = personService.getPersonById(id);        model.addAttribute("person" , person);        return person;    }

      返回页面格式

      /**     * 根据id获取用户信息     * @param id     * @param model     * @return 返回页面     */    @ApiOperation(value = "测试根据id获取用户信息的方法(3)" ,notes="测试查询方法", tags = {"query"})    @ApiImplicitParam(paramType = "query", name = "id", value = "用户Id", required = true, dataType = "int")    @RequestMapping(value = "person/getperson3", method = RequestMethod.GET)    public Object queryPerson3(@RequestParam Integer id , Model model){        Person person = personService.getPersonById(id);        model.addAttribute("person" , person);        return "ok";    }

      接受参数是一个

      可以看返回是单纯的Stirng类型的示例

      接受参数是多个

      /**     *  多个参数的形式,利用     * @param userName     * @param id     * @return     */    @ApiOperation(value = "测试多个参数(5)" ,notes="测试查询方法", tags = {"query"})    @ApiImplicitParams({            @ApiImplicitParam(paramType = "query", name = "id", value = "用户Id", required = true, dataType = "int"),            @ApiImplicitParam(paramType = "query", name = "userName", value = "用户名", required = true, dataType = "String"),    })    @RequestMapping(value = "person/getperson5", method = RequestMethod.GET)    @ResponseBody    public Object queryPerson5( @RequestParam String userName,                                @RequestParam Integer id ){        return "success";    }

      接受参数是实体类

      步骤:

      (1)找到对应的实体类
      (2)在对应的字段和类上添加注解

      package com.scw.springboot.swagger.model;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;/** * @author scw * @create 2018-01-03 10:33 * @desc 对应数据库中的实体类 **/@ApiModel(value = "用户实体模型")public class Person {    @ApiModelProperty(value = "用户id", required = true)    private Integer id;    @ApiModelProperty(value = "用户名", required = true)    private String name;    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return "Person{" +                "id=" + id +                ", name='" + name + '\'' +                '}';    }}

        (3)在controller层的方法使用注解@RequestBody进行接受处理

        /**     *  接受的参数是person实体(这种情况用得最多,比如form表单提交)     * @param person     * @return     */    @ApiOperation(value = "测试接受参数为对象实体(4)" ,notes="2222", tags = {"query"})    @RequestMapping(value = "person/getperson4", method = RequestMethod.POST)    @ResponseBody    public String queryPerson4(@RequestBody Person person){        return "成功";    }

        总结

        Swagger还是非常实用的,便于前后端的分离各自的开发,并且集成也非常的容易和快速,并且可控性也比较强(比如,什么时候需要使用和时候地方需要使用)。不过,个人觉得的话,有一点就是一个最大的痛点,就是针对程序中的代码可能看起来比较冗余,因为这个在开发环境是需要的,但是以后正式环境,一般这个功能是很少有的(当然,像SQL监控这些功能还是有的,一般都是超级管理员可以看到,客户是压根不知道,只是为了分析整个系统的性能),所以,代码看起来可能会相对比较多。万事有好,必有坏,个人还是喜欢的,所以,根据大家各自的需求来进行得与舍就行了。。

        感谢大家的阅读

        你可能感兴趣的文章
        Servlet进阶和JSP基础
        查看>>
        servlet中的cookie和session
        查看>>
        过滤器及JSP九大隐式对象
        查看>>
        软件(项目)的分层
        查看>>
        菜单树
        查看>>
        Servlet的生命周期
        查看>>
        JAVA八大经典书籍,你看过几本?
        查看>>
        《读书笔记》—–书单推荐
        查看>>
        String s1 = new String("abc"); String s2 = ("abc");
        查看>>
        JAVA数据类型
        查看>>
        【Python】学习笔记——-6.2、使用第三方模块
        查看>>
        【Python】学习笔记——-7.0、面向对象编程
        查看>>
        【Python】学习笔记——-7.2、访问限制
        查看>>
        【Python】学习笔记——-7.3、继承和多态
        查看>>
        【Python】学习笔记——-7.5、实例属性和类属性
        查看>>
        git中文安装教程
        查看>>
        虚拟机 CentOS7/RedHat7/OracleLinux7 配置静态IP地址 Ping 物理机和互联网
        查看>>
        Jackson Tree Model Example
        查看>>
        常用js收集
        查看>>
        如何防止sql注入
        查看>>