前言:做爲一個以先後端分離爲模式開發小組,咱們每隔一段時間都進行這樣一個場景:前端人員和後端開發在一塊兒熱烈的討論"哎,你這參數又變了啊","接口怎麼又請求不通了啊","你再試試,我打個斷點調試一下.."。能夠看到在先後端溝通中出現了很多問題。對於這樣的問題,以前一直沒有很好的解決方案,直到它的出現,沒錯...這就是咱們今天要討論的神器:swagger,一款致力於解決接口規範化、標準化、文檔化的開源庫,一款真正的開發神器。html
目錄前端
一:swagger是什麼?java
二:爲何要使用swaager?web
三:如何搭一個swagger?spring
四:如何在項目中集成swagger編程
五:使用swagger須要注意的問題後端
六:總結api
一:swagger是什麼?springboot
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,而其餘版本又沒有通過驗證,因此在比較保守的狀況下,我比較推薦的版本是2.7.0,而且它是通過我驗證的。
一:引入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
springboot整合swagger,只須要添加一個swagger的配置類,添加上@bean註解,就能夠實現Bean的注入,而後添加一個ApiInfo的配置,添加註解掃描,其實對於掃描這裏,配置分類兩類,一個是包的路徑掃描,一個是按照註解的掃描,我比價推薦的方式是按照註解,由於在swageer的實際使用中,你得在每一個api中添加@APi的註解,可是若是配置成包的話,有可能會有遺漏,或者新增長包路徑可能忘了配置,就致使配置無效。
@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的經常使用註解,表格說的很清晰了,我就不一一贅述了,下面會給出具體的應用實際例子:
四:在項目中集成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的做用。實在是開發編程必備良品啊。
原文出處:https://www.cnblogs.com/wyq178/p/10291447.html