前言

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

对于这样的问题,之前一直没有很好的解决方案,直到它的出现,没错...这就是我们今天要讨论的神器: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依赖库io.springfox    springfox-swagger2    2.7.0io.springfox    springfox-swagger-ui    2.7.0

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的注解:

四:在项目中集成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 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的作用。实在是开发编程必备良品啊。

作为参数给后端为空_后端 API 接口文档 Swagger 使用指南相关推荐

  1. java扫描接口_一种扫描接口并生成可调用API接口文档的方法与流程

    本发明属于JavaWeb开发技术领域,涉及一种API接口文档的生成方法,尤其是一种扫描接口并生成可调用API接口文档的方法. 背景技术: API(Application Programming Int ...

  2. vue后端必须接口吗_前后端分离模式,后端说开发完才能给接口文档,合理吗

    背景: 汇总了下老王在其他平台的原创回复,欢迎关注老王原创公众号[软件老王],关注不迷路. 一.后端开发完接口才给出接口文档,合理吗? 本人所在的项目组做项目过程中,后端不会先给出接口文档,而是要等他 ...

  3. echarts4离线使用文档_适合写API接口文档的管理工具有哪些?

    现在越来越流行前后端分离开发,使用ajax交互.所以api接口文档就变的十分有意义了,目前市场有哪些比较优秀的接口文档管理工具呢? 1.MinDoc 网址:https://www.iminho.me/ ...

  4. app后端开发一:swagger-ui教程-构建api接口文档工具

    声明 之前写过关于app后端开发的一系列文章,那是我第一次做app后端开发,存在很多不足,本想好好修改一下,想想还是重新写吧,这样子也能让我博客文章看起来多一点嘛,万一以后找工作,别人一看我博客这么多 ...

  5. java 门禁接口_门禁API接口文档.md

    # "闪开"API接口说明 [toc] #### 1:小区注册 使用之前必须先注册小区信息,获得小区的ID * #####接口调用请求说明 http请求方式: POST(请使用ht ...

  6. 高德地图api接口文档_在 R 语言里面调用高德地图接口:地理编码与路径规划

    你知道从广州南站去珠江新城怎么走么?今天就让我们一起使用 R 语言调用高德地图的地理编码(地址转经纬度)接口和路径规划接口来回答这个问题. 准备工作 注册高德地图,创建应用添加 Key(注意申请 Ke ...

  7. java农行接口通讯代码_农行TrustPayClient-Java接口文档(参考)

    [实例简介] 农行TrustPayClient-Java接口文档,V3.1.3,包括接口使用说明.自动化配置模式.接口demo都有 [实例截图] [核心代码] 农行TrustPayClient-Jav ...

  8. 开发接口文档_更优更稳更好,看文档驱动开发模式在AIMS中的优势

    ​[摘要]程序员常会说:我最讨厌别人写的代码没有文档,我也最讨厌自己需要写文档. 有一个很老的梗: 我最讨厌别人写的代码没有文档,我也最讨厌自己需要写文档. 有这种想法的程序员应该算是一个老鸟了,对于 ...

  9. 开发接口文档_产品经理必懂的接口文档撰写方式

    做产品经理的难免会调研各式各样的第三方需求能力.以满足产品提供用户的市场价值,比如第三方登录.图像识别.风控算法,都有专注的服务厂商. 企业无需自己花时间和精力投入在具有较高技术壁垒或时间成本的需求上 ...

最新文章

  1. 如何写出一份优秀的软件设计文档
  2. 记录ALiYun EMR常用服务的手动启动和停止命令(hdfs/yarn/mr-jobhistory/zk/spark-history)
  3. 分享 | 光纤光缆布线基础知识及系统设计
  4. 中文版开源!最最最经典的Python编程教材强势来袭~
  5. 移动端rem适配-JS
  6. Share Point 开发系列之一:开发方式的选择
  7. css中设置br标签之后的样式_CSS学习
  8. spring boot系列教程2--从helloworld开始
  9. python爬取所有数据_入门用Python进行Web爬取数据:为数据科学项目提取数据的有效方法...
  10. vrrp 理论和配置
  11. fossid安装教程_keepalived 邮件通知
  12. memcpy和strcpy的区别
  13. WKWebview的内存问题
  14. 手把手教你VMware14虚拟机安装教程「图文附软件」
  15. Overleaf 指南:30 分钟 LaTeX 入门
  16. Python常用模块 之 hashlib模块
  17. java 水晶报表_水晶报表-crystal report
  18. 信息搜集快捷导航工具bug修复-光速启动
  19. 为什么今年的苹果手机不支持5G?原因有四点,网友:错怪库克了
  20. html如何引入iconfont官网图标

热门文章

  1. 【转】Android中Dalvik(DVM)的详解
  2. global.css
  3. [asp.net] 验证控件的属性及用法
  4. 中小企业电子商务如何发展?
  5. 微信亿级用户异常检测框架的设计与实践
  6. Spring MVC 使用问题与解决--HTTP Status 500 - Servlet.init() for servlet springmvc threw exception
  7. uni-app插入本地背景图片不能超过40kb解决方法
  8. [211渣硕] 腾讯/阿里/携程 详细NLP算法实习 面经
  9. 站在BERT肩膀上的NLP新秀们(PART I)
  10. gpu服务器性能测试用例,多目标测试用例预优化方法及其在GPU上的应用研究