您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

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

时间:2019-12-25 11:22:16  来源:  作者:

前言

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

对于这样的问题,之前一直没有很好的解决方案,直到它的出现,没错...这就是我们今天要讨论的神器: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@EnableSwagger2public 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的注解:

后端 API 接口文档 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#/

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

 

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

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

 

五:使用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的作用。实在是开发编程必备良品啊。



Tags:Swagger   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
为了不重复 CV 操作,抱着一丝希望开始在GitHub里找,看看有没有什么工具可以用,结果就真的发现了宝藏,screw(螺丝钉),居然可以生成数据库文档,优秀啊~。 数据库支持 MySQL MariaDB TI...【详细内容】
2021-06-01  Tags: Swagger  点击:(123)  评论:(0)  加入收藏
Swagger Butler是一个基于Swagger与Zuul构建的API文档汇集工具。通过构建一个简单的Spring Boot应用,增加一些配置就能将现有整合了Swagger的Web应用的API文档都汇总到一起,方...【详细内容】
2021-04-12  Tags: Swagger  点击:(246)  评论:(0)  加入收藏
推荐使用全局的方式1. 每个接口单独传import com.google.common.collect.Lists;import org.springframework.beans.factory.annotation.Value;import org.springframework....【详细内容】
2020-07-16  Tags: Swagger  点击:(364)  评论:(0)  加入收藏
前言作为一个以前后端分离为模式开发小组,我们每隔一段时间都进行这样一个场景:前端人员和后端开发在一起热烈的讨论"哎,你这参数又变了啊","接口怎么又请求不通了啊","你再试...【详细内容】
2019-12-25  Tags: Swagger  点击:(129)  评论:(0)  加入收藏
Swagger 使用 Swagger 有什么用?Swagger 是一个流行的API开发框架,这个框架以“开放API声明” (OpenAPI Specification,OAS) 为基础,对整个 API 的开发周期都提供了相应的解决方案...【详细内容】
2019-09-29  Tags: Swagger  点击:(141)  评论:(0)  加入收藏
Swagger Butler是一个基于Swagger与Zuul构建的API文档汇集工具。通过构建一个简单的Spring Boot应用,增加一些配置就能将现有整合了Swagger的Web应用的API文档都汇总到一起,方...【详细内容】
2019-09-10  Tags: Swagger  点击:(143)  评论:(0)  加入收藏
▌简易百科推荐
本文分为三个等级自顶向下地分析了glibc中内存分配与回收的过程。本文不过度关注细节,因此只是分别从arena层次、bin层次、chunk层次进行图解,而不涉及有关指针的具体操作。前...【详细内容】
2021-12-28  linux技术栈    Tags:glibc   点击:(3)  评论:(0)  加入收藏
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(2)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(10)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(20)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(25)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(25)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条