Swagger 使用

Swagger 使用指南

前言:作爲一個以前後端分離爲模式開發小組,我們每隔一段時間都進行這樣一個場景:前端人員和後端開發在一起熱烈的討論"哎,你這參數又變了啊",“接口怎麼又請求不通了啊”,“你再試試,我打個斷點調試一下…”。可以看到在前後端溝通中出現了不少問題。對於這樣的問題,之前一直沒有很好的解決方案,直到它的出現,沒錯…這就是我們今天要討論的神器:swagger,一款致力於解決接口規範化、標準化、文檔化的開源庫,一款真正的開發神器。

一:swagger是什麼?

Swagger是一款RESTFUL接口的文檔在線自動生成+功能測試功能軟件。Swagger是一個規範和完整的框
架,用於生成、描述、調用和可視化RESTful風格的Web服務。目標是使客戶端和文件系統作爲服務器以同
樣的速度來更新文件的方法,參數和模型緊密集成到服務器。這個解釋簡單點來講就是說,swagger是一款
可以根據resutful風格生成的生成的接口開發文檔,並且支持做測試的一款中間軟件。

swagger官網

二:爲什麼要使用swaager?

2.1:對於後端開發人員來說

  1. 不用再手寫WiKi接口拼大量的參數,避免手寫錯誤
  2. 對代碼侵入性低,採用全註解的方式,開發簡單
  3. 方法參數名修改、增加、減少參數都可以直接生效,不用手動維護
  4. 缺點:增加了開發成本,寫接口還得再寫一套參數配置

2.2:對於前端開發來說

  1. 後端只需要定義好接口,會自動生成文檔,接口功能、參數一目瞭然
  2. 聯調方便,如果出問題,直接測試接口,實時檢查參數和返回值,就可以快速定位是前端還是後端的問題

2.3:對於測試

  1. 對於某些沒有前端界面UI的功能,可以用它來測試接口
  2. 操作簡單,不用瞭解具體代碼就可以操作

三:如何搭一個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

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需要注意的問題

  1. 對於只有一個HttpServletRequest參數的方法,如果參數小於5個,推薦使用 @ApiImplicitParams的方式單獨封裝每一個參數;如果參數大於5個,採用定義一個對象去封裝所有參數的屬性,然後使用@APiParam的方式
  2. 默認的訪問地址:ip:port/swagger-ui.html#/,但是在shiro中,會攔截所有的請求,必須加上默認訪問路徑(比如項目中,就是ip:port/context/swagger-ui.html#/),然後登陸後纔可以看到
  3. 在GET請求中,參數在Body體裏面,不能使用@RequestBody。在POST請求,可以使用@RequestBody和@RequestParam,如果使用@RequestBody,對於參數轉化的配置必須統一
  4. controller必須指定請求類型,否則swagger會把所有的類型(6種)都生成出來
  5. swagger在生產環境不能對外暴露,可以使用@Profile({“dev”, “prod”,“pre”})指定可以使用的環境

六:總結

swagger作爲一款輔助性的工具,能大大提升我們的和前端的溝通效率,接口是一個非常重要的傳遞數據的媒介,每個接口的簽名、方法參數都非常重要。一個良好的文檔非常重要,如果採用手寫的方式非常容易拼寫錯誤,而swagger可以自動化生成參數文檔,這一切都加快了我們的溝通效率。並且可以替代postman的作用。實在是開發編程必備良品啊。

轉載自:https://www.cnblogs.com/wyq178/p/10291447.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章