IDEA 中SpringBoot集成Swagger 2步驟、注意事項、常見問題

最近開始看後端的東西,記錄下學習筆記吧。

一、Swagger定義:http://swagger.io(官網)

Swagger是一個簡單但功能強大的API表達工具。它具有地球上最大的API工具生態系統,數以千計的開發人員,使用幾乎所有的現代編程語言,都在支持和使用Swagger。使用Swagger生成API,我們可以得到交互式文檔,自動生成代碼的SDK以及API的發現特性等。

現在,Swagger已經幫助包括Apigee, Getty圖像, Intuit, LivingSocial, McKesson, 微軟, Morningstar和PayPal等世界知名企業建立起了一套基於RESTful API的完美服務系統。

2.0版本已經發布,Swagger變得更加強大。值得感激的是,Swagger的源碼100%開源在github

Swagger是一組開源項目,其中主要要項目如下:

1.   Swagger-tools:提供各種與Swagger進行集成和交互的工具。例如模式檢驗、Swagger 1.2文檔轉換成Swagger 2.0文檔等功能。

2.   Swagger-core: 用於Java/Scala的的Swagger實現。與JAX-RS(Jersey、Resteasy、CXF...)、Servlets和Play框架進行集成。

3.   Swagger-js: 用於JavaScript的Swagger實現。

4.   Swagger-node-express: Swagger模塊,用於node.js的Express web應用框架。

5.   Swagger-ui:一個無依賴的HTML、JS和CSS集合,可以爲Swagger兼容API動態生成優雅文檔。

6.   Swagger-codegen:一個模板驅動引擎,通過分析用戶Swagger資源聲明以各種語言生成客戶端代碼。

二、作用

1、接口文檔的在線自動生成

2、功能測試

三、集成

1、maven方式 在pom.xml中增加dependency

<dependency>

    <groupId>io.springfox</groupId>

    <artifactId>springfox-swagger2</artifactId>

    <version>2.6.1</version>

</dependency>

<dependency>

    <groupId>io.springfox</groupId>

    <artifactId>springfox-swagger-ui</artifactId>

    <version>2.6.1</version>

</dependency>

2、創建Swagger2配置類(看其他的貼子中寫要和Application同級目錄,但是我沒有放在同一級別也可以,不知原因,知道原因的可以給我留言,互相學習。)

package com.betty.miaosha.config;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.Contact;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/*
 * Create by BettyLi on 2019/12/1 14:40
 *
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
    @Bean
    public Docket petApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .apis(RequestHandlerSelectors.basePackage("com.betty.miaosha.controller")) //指定提供接口所在的基包
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 該套 API 說明,包含作者、簡介、版本、host、服務URL
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Betty Swagger學習")
                .version("1.0")
                //.termsOfServiceUrl("localhost:8090/betty")
                .description("betty demo")
                .build();
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(
                "classpath:/static/");
        // 解決 SWAGGER 404報錯
        registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }


}

不加addResourceHandlers的話,我這邊是報錯no mapper錯誤,也有的說是404,我直接就加上了。

做好這些就可以在Controller中添加文檔內容了。

3、在完成了上述配置後,其實已經可以生產文檔內容,但是這樣的文檔主要針對請求本身,描述的主要來源是函數的命名,對用戶並不友好,我們通常需要自己增加一些說明來豐富文檔內容。

Swagger使用的註解及其說明:

@Api:用在類上,說明該類的作用。

@ApiOperation:註解來給API增加方法說明。

@ApiImplicitParams : 用在方法上包含一組參數說明。

@ApiImplicitParam:用來註解來給方法入參增加說明。

@ApiResponses:用於表示一組響應

@ApiResponse:用在@ApiResponses中,一般用於表達一個錯誤的響應信息

    l   code:數字,例如400

    l   message:信息,例如"請求參數沒填好"

    l   response:拋出異常的類   

@ApiModel:描述一個Model的信息(一般用在請求參數無法使用@ApiImplicitParam註解進行描述的時候)

    l   @ApiModelProperty:描述一個model的屬性

 

注意:@ApiImplicitParam的參數說明:

paramType:指定參數放在哪個地方

header:請求參數放置於Request Header,使用@RequestHeader獲取

query:請求參數放置於請求地址,使用@RequestParam獲取

path:(用於restful接口)-->請求參數的獲取:@PathVariable

body:(不常用)

form(不常用)

name:參數名

 

dataType:參數類型

 

required:參數是否必須傳

true | false

value:說明參數的意思

 

defaultValue:參數的默認值

 

例:

package com.betty.miaosha.controller;

import com.alibaba.druid.util.StringUtils;
import com.betty.miaosha.controller.viewobject.UserVO;
import com.betty.miaosha.error.BusinessException;
import com.betty.miaosha.error.EmBusinessError;
import com.betty.miaosha.response.CommonReturnType;
import com.betty.miaosha.service.UserService;
import com.betty.miaosha.service.model.UserModel;
import io.swagger.annotations.*;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Encoder;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

/*
 * Create by BettyLi on 2019/11/21 15:46
 *
 */

@RestController
@MapperScan("com.betty.miaosha.dao")
@RequestMapping("/user")
@Api(value = "UserControllerBetty測試", tags = { "ueser interface" })
//DEFAULT_ALLOWED_HEADERS 允許跨域傳輸所有的headers參數,將用於使用token放入header域做session共享的跨域請求
@CrossOrigin(allowCredentials = "true",allowedHeaders = "*")
public class UserController extends BaseController{

    @Autowired
    private UserService userService;
    @Autowired
    private HttpServletRequest httpServletRequest;

    @PostMapping("/login")
    @ApiOperation(value = "登錄接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name="telphone",value="手機號",required=true,paramType="query"),
            @ApiImplicitParam(name="password",value="密碼",required=false,paramType="query"),
    })
    @ApiResponses({
            @ApiResponse(code=400,message="請求參數沒填好"),
            @ApiResponse(code=404,message="請求路徑沒有或頁面跳轉路徑不對")
    })
    public CommonReturnType login( @RequestParam("telphone") String telphone,
                                   @RequestParam("password") String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //入參校驗
        if(org.apache.commons.lang3.StringUtils.isEmpty(telphone)||
                org.apache.commons.lang3.StringUtils.isEmpty(password)){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        //用戶登錄服務用來校驗登錄是否合法
        UserModel userModel = userService.validateLogin(telphone,this.EncodeByMD5(password));
        //將登錄憑證加入到用戶登錄成功的session內
        this.httpServletRequest.getSession().setAttribute("IS_LOGIN",true);
        this.httpServletRequest.getSession().setAttribute("LOGIN_USER",userModel);
        return CommonReturnType.create(null);
    }

    @PostMapping("/register")
    @ApiOperation(value = "註冊接口")
    public CommonReturnType register(@RequestParam("name") String name,
                                     @RequestParam("telphone") String telphone,
                                     @RequestParam("password") String password,
                                     @RequestParam("registerMode") String registerMode,
                                     @RequestParam("gender") Integer gender,
                                     @RequestParam("age") Integer age,
                                     @RequestParam("optCode") String optCode) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //驗證手機號和對應的optcode相符合
        String intSessionOtpCode = (String)this.httpServletRequest.getSession().getAttribute(telphone);
        if(!StringUtils.equals(optCode,intSessionOtpCode)){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"短信驗證碼不正確");
        }
        //用戶的註冊流程
        UserModel userModel = new UserModel();
        userModel.setTelphone(telphone);
        userModel.setName(name);
        userModel.setPassword(this.EncodeByMD5(password));
        userModel.setAge(age);
        userModel.setGender(new Byte(String.valueOf(gender.intValue())));
        userModel.setRegisterMode(registerMode);
        userService.register(userModel);
        return CommonReturnType.create(null);

    }

    public String EncodeByMD5(String str) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        //確定計算方法
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        BASE64Encoder base64Encoder = new BASE64Encoder();
        //加密字符串
        String newStr = base64Encoder.encode(md5.digest(str.getBytes("utf-8")));
        return newStr;
    }

    @GetMapping("/get/{id}")
    @ApiOperation(value = "根據id獲取用戶信息")
    public CommonReturnType getUser(@PathVariable("id")int id) throws BusinessException {
        //調用service服務獲取對應id的用戶對象並返回給前端
        UserVO userVO = new UserVO();
        UserModel userModel = userService.getUserById(id);
        if(userModel==null){
            throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
            //return CommonReturnType.create(userModel,"fail");
        }else{
            //將核心領域模型用戶對象轉化爲可供UI使用的viewobject
            BeanUtils.copyProperties(userModel,userVO);
        }
        return CommonReturnType.create(userVO);
    }

    @PostMapping(value = "/getotp",consumes = {"application/x-www-form-urlencoded"})
    @ApiOperation(value = "獲取驗證碼")
    private CommonReturnType getOtp(@RequestParam("telphone")String telphone){
        //需要按照一定的規則生成OTP驗證碼
        Random random = new Random();
        int randonInt = random.nextInt(99999);
        randonInt = randonInt+10000;
        String otpCode = String .valueOf(randonInt);
        //將OTP驗證碼同對應用戶的手機關聯 使用httpsession的方式綁定他的手機號與OTPCODE
        httpServletRequest.getSession().setAttribute(telphone,otpCode);

        //將OTP驗證碼通過短信通道發送給用戶,省略
        System.out.println("telphone="+telphone+"&otpCode="+otpCode);

        return CommonReturnType.create(null);
    }
}

完成上述代碼添加上,啓動Spring Boot程序,訪問:http://localhost:server.port/server.servlet.context-path/swagger-ui.html

注:設置server.port 和 server.servlet.context-path要加上。我就是因爲忘記了path坑了很久。

到此基本完成。

遇到的問題也在上面寫了,還有一個是 點擊行不能展開,只能點擊右上角的 List Operations 和 Expand Operations 進行所有方法的 展開和關閉, 使用起來特別麻煩.,最後發現在API註解上的屬性中有 value 和 tags 兩個屬性, Value的值不會展示在 UI界面上, tags會展示在界面上, 如果tags 中的值設置爲中文, 那麼 下面的方法名點擊將不能被展開,改成英文之後正常.value 值是否爲中文不影響.

 

 

發佈了27 篇原創文章 · 獲贊 19 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章