做者:Yrion
前言:做为一个之前后端分离为模式开发小组,咱们每隔一段时间都进行这样一个场景:前端人员和后端开发在一块儿热烈的讨论"哎,你这参数又变了啊","接口怎么又请求不通了啊","你再试试,我打个断点调试一下.."。能够看到在先后端沟通中出现了很多问题。php
对于这样的问题,以前一直没有很好的解决方案,直到它的出现,没错...这就是咱们今天要讨论的神器:swagger,一款致力于解决接口规范化、标准化、文档化的开源库,一款真正的开发神器。html
swagger是什么?前端
为何要使用swaager?java
如何搭一个swagger?web
如何在项目中集成swaggerspring
使用swagger须要注意的问题编程
总结后端
Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。目标是使客户端和文件系统做为服务器以一样的速度来更新文件的方法,参数和模型紧密集成到服务器。api
这个解释简单点来说就是说,swagger是一款能够根据resutful风格生成的生成的接口开发文档,而且支持作测试的一款中间软件。服务器
不用再手写WiKi接口拼大量的参数,避免手写错误
对代码侵入性低,采用全注解的方式,开发简单
方法参数名修改、增长、减小参数均可以直接生效,不用手动维护
缺点:增长了开发成本,写接口还得再写一套参数配置
后端只须要定义好接口,会自动生成文档,接口功能、参数一目了然
联调方便,若是出问题,直接测试接口,实时检查参数和返回值,就能够快速定位是前端仍是后端的问题
对于某些没有前端界面UI的功能,能够用它来测试接口
操做简单,不用了解具体代码就能够操做
操做简单,不用了解具体代码就能够操做
目前推荐使用2.7.0版本,由于2.6.0版本有bug,而其余版本又没有通过验证
<!--引入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>
@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();
}
}
swagger的核心在于注解,接下来就着重讲一下swagger的注解:
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.getSucce***esultModel();
}
/**
* 根据电影名删除电影
*
* @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.getSucce***esultModel();
}
/**
* 根据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.getSucce***esultModel();
}
return CommonConstants.getErrorResultModel();
}
}
http://localhost:8080/swagger-ui.html#/
能够看出访问的url都很清晰的展现在它最终的页面上,咱们打开一个方法:能够看出方法的请求参数清晰的的罗列出来,包括方法的返回值。而且有一个很重要的功能,只须要点下方的try it out就能够进行接口测试,
对于只有一个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的做用。实在是开发编程必备良品啊。