手把手教你如何玩转Swagger

情景引入

  • 小白:起床,起床,,赶快起床!!!!
  • 我:你又怎么了呢~~好不容易有个假期,都不能消停消停的吗?
  • 小白:我也想你多休息,但是我又遇到问题了,需要你的帮助~
  • 我:说说,你又遇到什么问题了呢?这么火急火燎的 ~ 真烦人
  • 小白:你是知道的,我们平常开发都是有接口开发文档的,但是,前后端处理挺麻烦的,而且更新又不及时,有时候字段改了,又不及时通知,然后调试的时候就出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
具体的集成步骤都在我的博文有详细的介绍
https://blog.csdn.net/Cs_hnu_scw/article/details/78961232

开发步骤(小试牛刀)

  1. 搭建基本的SpringBoot+Mybatis+Mysql的环境(这个在开发环境中已经说明)
  2. 引入Swagger的pom依赖
<!--swagger-->
		<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>

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

  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. 访问项目地址
    http://localhost:8080/swagger-ui.html#/
  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"})

在这里插入图片描述

@ApiParam

使用地点

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

参数

name:参数名(中文,英文都可以,用于显示)
value:参数说明 (需要与接受参数一致)
required:是否必填

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

@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监控这些功能还是有的,一般都是超级管理员可以看到,客户是压根不知道,只是为了分析整个系统的性能),所以,代码看起来可能会相对比较多。万事有好,必有坏,个人还是喜欢的,所以,根据大家各自的需求来进行得与舍就行了。。

源代码

github地址:https://github.com/qq496616246/SpringBootAndSwagger
或者直接clone git@github.com:qq496616246/SpringBootAndSwagger.git
百度云地址:https://pan.baidu.com/s/1VJ9aRsKzcjaRadPGeSxBaA
密码:abou

感谢大家的阅读

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值