后端 API 接口文档 Swagger 使用指南

2023-11-03

  • 前言
  • 一:swagger是什么?
  • 二:为什么要使用swaager?
    • 2.1:对于后端开发人员来说
    • 2.2:对于前端开发来说
    • 2.3:对于测试
  • 三:如何搭一个swagger
    • 3.1:引入swagger的依赖
    • 3.2:springBoot整合swagger
    • 3.3:swagger的注解
  • 四:在项目中集成swagger
    • 4.1:在controller中使用注解
    • 4.2:访问本地链接
  • 五:使用swagger需要注意的问题
  • 六:总结​​​​​​​ 

作为一个以前后端分离为模式开发小组,我们每隔一段时间都进行这样一个场景:前端人员和后端开发在一起热烈的讨论"哎,你这参数又变了啊","接口怎么又请求不通了啊","你再试试,我打个断点调试一下.."。可以看到在前后端沟通中出现了不少问题。

对于这样的问题,之前一直没有很好的解决方案,直到它的出现,没错...这就是我们今天要讨论的神器:swagger,一款致力于解决接口规范化、标准化、文档化的开源库,一款真正的开发神器。

一:swagger是什么?

Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。目标是使客户端和文件系统作为服务器以同样的速度来更新文件的方法,参数和模型紧密集成到服务器。

这个解释简单点来讲就是说,swagger是一款可以根据resutful风格生成的生成的接口开发文档,并且支持做测试的一款中间软件。

二:为什么要使用swaager?

2.1:对于后端开发人员来说

  • 不用再手写WiKi接口拼大量的参数,避免手写错误
  • 对代码侵入性低,采用全注解的方式,开发简单
  • 方法参数名修改、增加、减少参数都可以直接生效,不用手动维护
  • 缺点:增加了开发成本,写接口还得再写一套参数配置

2.2:对于前端开发来说

  • 后端只需要定义好接口,会自动生成文档,接口功能、参数一目了然
  • 联调方便,如果出问题,直接测试接口,实时检查参数和返回值,就可以快速定位是前端还是后端的问题

2.3:对于测试

  • 对于某些没有前端界面UI的功能,可以用它来测试接口
  • 操作简单,不用了解具体代码就可以操作
  • 操作简单,不用了解具体代码就可以操作

三:如何搭一个swagger

3.1:引入swagger的依赖

目前推荐使用2.7.0版本,因为2.6.0版本有bug,而其他版本又没有经过验证

一:引入Swagger依赖库
<!--引入swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

3.2:springBoot整合swagger

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket productApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))  //添加ApiOperiation注解的被扫描
                .paths(PathSelectors.any())
                .build();

    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title(”swagger和springBoot整合“).description(”swagger的API文档")
                .version("1.0").build();
    }

}

3.3:swagger的注解

swagger的核心在于注解,接下来就着重讲一下swagger的注解:

四:在项目中集成swagger

4.1:在controller中使用注解

package com.youjia.swagger.controller;

import com.youjia.swagger.constants.CommonConstants;
import com.youjia.swagger.model.Film;
import com.youjia.swagger.model.ResultModel;
import com.youjia.swagger.service.FilmService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Auther: wyq
 * @Date: 2018/12/29 14:50
 */
@RestController
@Api(value = "电影Controller", tags = { "电影访问接口" })
@RequestMapping("/film")
public class FilmController {

    @Autowired
    private FilmService filmService;

    /**
     * 添加一个电影数据
     *
     * @param
     * @return
     */
    @ApiOperation(value = "添加一部电影")
    @PostMapping("/addFilm")
    @ApiResponses(value = { @ApiResponse(code = 1000, message = "成功"), @ApiResponse(code = 1001, message = "失败"),
            @ApiResponse(code = 1002, response = Film.class,message = "缺少参数") })
    public ResultModel addFilm(@ApiParam("电影名称") @RequestParam("filmName") String filmName,
                               @ApiParam(value = "分数", allowEmptyValue = true) @RequestParam("score") Short score,
                               @ApiParam("发布时间") @RequestParam(value = "publishTime",required = false) String publishTime,
                               @ApiParam("创建者id") @RequestParam("creatorId") Long creatorId) {

        if (Objects.isNull(filmName) || Objects.isNull(score) || Objects.isNull(publishTime) || StringUtils
                .isEmpty(creatorId)) {
            return new ResultModel(ResultModel.failed, "参数错误");
        }
        Film filmPOM = new Film();
        filmPOM.setFilmName(filmName);
        filmPOM.setScore(score);
        DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date publishTimeDate = null;
        try {
            publishTimeDate = simpleDateFormat.parse(publishTime);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        filmPOM.setPublishTime(publishTimeDate);
        filmPOM.setCreatorId(creatorId);
        Boolean result = filmService.addFilm(filmPOM);
        if (result) {
            return new ResultModel(CommonConstants.SUCCESSMSG);
        }
        return new ResultModel(CommonConstants.FAILD_MSG);
    }

    /**
     * 根据电影名字获取电影
     *
     * @param fileName
     * @return
     */
    @GetMapping("/getFilms")
    @ApiOperation(value = "根据名字获取电影")
    @ApiResponses(value = { @ApiResponse(code = 1000, message = "成功"), @ApiResponse(code = 1001, message = "失败"),
            @ApiResponse(code = 1002, message = "缺少参数") })
    public ResultModel getFilmsByName(@ApiParam("电影名称") @RequestParam("fileName") String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            return CommonConstants.getErrorResultModel();
        }

        List<Film> films = filmService.getFilmByName(fileName);
        if (!CollectionUtils.isEmpty(films)) {
            return new ResultModel(films);
        }
        return CommonConstants.getErrorResultModel();

    }

    /**
     * 根据电影名更新
     *
     * @return
     */
    @PostMapping("/updateScore")
    @ApiOperation(value = "根据电影名修改分数")
    @ApiResponses(value = { @ApiResponse(code = 1000, message = "成功"), @ApiResponse(code = 1001, message = "失败"),
            @ApiResponse(code = 1002, message = "缺少参数") })
    public ResultModel updateFilmScore(@ApiParam("电影名称") @RequestParam("fileName") String fileName,
                                       @ApiParam("分数") @RequestParam("score") Short score) {
        if (StringUtils.isEmpty(fileName) || Objects.isNull(score)) {
            return CommonConstants.getErrorResultModel();
        }

        filmService.updateScoreByName(fileName, score);
        return CommonConstants.getSuccessResultModel();
    }

    /**
     * 根据电影名删除电影
     *
     * @param request
     * @return
     */
    @PostMapping("/delFilm")
    @ApiOperation(value = "根据电影名删除电影")
    @ApiImplicitParams({ @ApiImplicitParam(name = "filmName",
            value = "电影名",
            dataType = "String",
            paramType = "query",
            required = true), @ApiImplicitParam(name = "id", value = "电影id", dataType = "int", paramType = "query") })
    public ResultModel deleteFilmByNameOrId(HttpServletRequest request) {
        //电影名
        String filmName = request.getParameter("filmName");
        //电影id
        Long filmId = Long.parseLong(request.getParameter("id"));

        filmService.deleteFilmOrId(filmName,filmId);


        return CommonConstants.getSuccessResultModel();
    }

    /**
     * 根据id获取电影
     *
     * @param id
     * @return
     */
    @PostMapping("/{id}")
    @ApiOperation("根据id获取电影")
    @ApiImplicitParam(name = "id", value = "电影id", dataType = "long", paramType = "path", required = true)
    public ResultModel getFilmById(@PathVariable Long id) {

        if (Objects.isNull(id)) {
            return CommonConstants.getLessParamResultModel();
        }
        Film film = filmService.getFilmById(id);
        if (Objects.nonNull(film)) {
            return new ResultModel(film);
        }
        return CommonConstants.getErrorResultModel();
    }

    /**
     * 修改整个电影
     *
     * @param film
     * @return
     */
    @PostMapping("/insertFilm")
    @ApiOperation("插入一部电影")
    public ResultModel insertFilm(@ApiParam("电影实体对象") @RequestBody Film film) {
        if (Objects.isNull(film)) {
            return CommonConstants.getLessParamResultModel();
        }
        Boolean isSuccess = filmService.insertFilm(film);
        if (isSuccess) {
            return CommonConstants.getSuccessResultModel();
        }
        return CommonConstants.getErrorResultModel();
    }
}

4.2:访问本地链接

http://localhost:8080/swagger-ui.html#/

可以看出访问的url都很清晰的展示在它最终的页面上,我们打开一个方法:可以看出方法的请求参数清晰的的罗列出来,包括方法的返回值。并且有一个很重要的功能,只需要点下方的try it out就可以进行接口测试,

五:使用swagger需要注意的问题

  • 对于只有一个HttpServletRequest参数的方法,如果参数小于5个,推荐使用 @ApiImplicitParams的方式单独封装每一个参数;如果参数大于5个,采用定义一个对象去封装所有参数的属性,然后使用@APiParam的方式
  • 默认的访问地址:ip:port/swagger-ui.html#/,但是在shiro中,会拦截所有的请求,必须加上默认访问路径(比如项目中,就是ip:port/context/swagger-ui.html#/),然后登陆后才可以看到
  • 在GET请求中,参数在Body体里面,不能使用@RequestBody。在POST请求,可以使用@RequestBody和@RequestParam,如果使用@RequestBody,对于参数转化的配置必须统一
  • controller必须指定请求类型,否则swagger会把所有的类型(6种)都生成出来
  • swagger在生产环境不能对外暴露,可以使用@Profile({“dev”, “prod”,“pre”})指定可以使用的环境

六:总结

swagger作为一款辅助性的工具,能大大提升我们的和前端的沟通效率,接口是一个非常重要的传递数据的媒介,每个接口的签名、方法参数都非常重要。一个良好的文档非常重要,如果采用手写的方式非常容易拼写错误,而swagger可以自动化生成参数文档,这一切都加快了我们的沟通效率。并且可以替代postman的作用。实在是开发编程必备良品啊。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

后端 API 接口文档 Swagger 使用指南 的相关文章

随机推荐

  • Latex输入特殊字符#$%&{}_^-<>

    本博文源于latex基础学习 今天学习特殊字符的输入 H e l l o W o r
  • hdu 1698 Just a Hook(线段树区间修改)

    include
  • 支付宝大力补贴刷脸支付新赛道新机会

    此次微信和支付宝面向市场推出的刷脸支付的产品 在安全上做了极大的努力 通过数据层层加密 保障了商户的资金安全 同时也为消费者带来了全新的消费体验 减少了商户在高峰期人流量分流的问题 与传统的聚合二维码收银台形成了优势互补的作用 通过微信和支
  • Semantic-Kitti数据解析

    1 bin文件 文件中保存的是二进制格式的四维雷达数据 包括x y z intensity 打开文件 def load data points points path cloud np fromfile points path dtype
  • 初等数论之算术基本定理

    定理 每个大于1的正整数n都可以被唯一地表示成素数的乘积 n的分解式n p1 a1 p2 a2 p3 a3 pk ak 其中p1 p2 pk是素数 p1 lt p2 lt p3 pk 性质如下 1 d n a1 1 a2 1 a3 1 ak
  • Scala基础

    需要运行 使用object类 跟Java不太一样 Scala中class文件只是新建一个类 不能直接运行 Scala中 object 是单例对象 即 其中所有内容都是静态对象 不需要实例化 可以直接调用 main方法也是程序入口 跟Java
  • Visual Studio Code关联MATLAB的.m文件并进行编辑提示

    如何在Visual Studio Code软件中关联MATLAB的 m文件并进行编辑提示 1 设置 1 在VSCode中下载MATLAB扩展并安装 2 在文件 首选项 用户设置中 增加下列代码 将设置放入此文件中以覆盖默认设置 editor
  • 败者树(多路归并)

    已知顺串 R1 10 15 16 R2 9 20 38 R3 20 20 30 R4 6 15 25 R5 8 15 20 R6 9 11 16 R7 90 100 110 R8 17 18 20 建立败者树 编程工具 Dev C 读入文件
  • Qt部件基类QDialog

    部件基类QDialog QDialog是各种对话框的基类 其继承自QWidget 对话框有两种表现形式 模态对话框 非模态对话框 模态对话框就是阻塞同一应用程序中其它可视窗口的输入的对话框 用户必须完成当前对话框中的交互操作并且关闭窗口后才
  • ICCV图像处理相关论文总结(103篇)(粗)

    ICCV图像处理相关论文总结 103篇 1 Person ReID 行人再识别 15 1 Neural Person Search Machines Hao Liu Jiashi Feng Zequn Jie Karlekar Jayash
  • js addEventListener绑定事件方法(详细介绍)

    addEventListener是一种给元素绑定事件的方法 例如绑定点击事件 这样元素在被点击之后就会执行一些操作 let element document getElementById element element addEventLi
  • ping命令

    打开运行窗口 首先 我们需要打开运行窗口 可以通过按下Win R组合键打开 然后 在窗口中输入cmd 进入dos命令 在命令行中输入ping命令 在dos命令行中 我们可以通过输入ping命令来检测网络连接 例如 我们可以输入ping 19
  • latex使用——调整大小系列

    写在最前面 如果是双栏的论文 想让表格或者图片或者公式占满两栏 直接在 begin table 和 end table 里加 像这样 begin table 和 end table 其他的也是一样的操作 公式调整大小 字体大小 七号 5 2
  • git commit时加上Signed-off-by信息

    git commit s m descriptions about the code 只要加入 s参数即可自动加上Signed off by信息 转载于 https www cnblogs com dakewei p 9856990 htm
  • Unity之FBX文件操作学习笔记(一)

    FBX作为隶属于Autodesk的一种三维模型场景动画打包格式文件 在图形学工程化领域应用十分广泛 然而 FBX文件格式不是公开的 所以对FBX文件进行读取与存储需要专门的工具 除了游戏引擎以及三维软件自带的FBX文件操作工具外 Autod
  • 紫鸟和Maskfog浏览器全方位测评对比

    随着跨境电商行业的发展 指纹浏览器被越来越多的人广泛使用 对于跨境电商来说 指纹浏览器能为多账号安全管理提供解决方案 现在市面上的指纹浏览器也层出不穷 今天给大家测评一下我认为做得比较好的两款防关联浏览器 Maskfog浏览器跟紫鸟浏览器
  • 安卓java修改按钮大小_修改android Toolbar的标题大小和按钮图标颜色

    使用android toolbar的时候 toolbar中的标题 二级标题以及按钮的图标的颜色都会使用默认的值 但是 有时候我们必须要自定义它们的大小以及颜色 该如何自定义呢 解决方法 1 修改标题 二级标题的字体大小和颜色 可以通过sty
  • Http响应码分类汇总

    1 响应码分类 1xx 响应码规范 RFC6585 2012 4 RFC7231 2014 6 1xx 类状态码属于提示信息 是协议处理中的一种中间状态 请求已接收到 需要进一步处理才能完成 实际用到的比较少 HTTP1 0 不支持 hea
  • #pragma once 与 #ifndef #define #endif各自的优缺点

    为了避免同一个文件被include多次 C C 中有两种方式 一种是 ifndef方式 一种是 pragma once方式 方式一 代码形式 注意标识名是自己起的 但这两个必须相同 一般用头文件名的大写 ifndef A H 如果未定义 A
  • 后端 API 接口文档 Swagger 使用指南

    前言 一 swagger是什么 二 为什么要使用swaager 2 1 对于后端开发人员来说 2 2 对于前端开发来说 2 3 对于测试 三 如何搭一个swagger 3 1 引入swagger的依赖 3 2 springBoot整合swa