亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring Boot集成Swagger2項(xiàng)目實(shí)戰(zhàn)

 更新時(shí)間:2018年01月16日 08:42:42   作者:liuxiaopeng  
在日常的工作中,我們往往需要給前端(WEB端、IOS、Android)或者第三方提供接口,這個(gè)時(shí)候我們就需要給他們提供一份詳細(xì)的API說(shuō)明文檔。這篇文章我們就來(lái)分享一種API文檔維護(hù)的方式,即通過(guò)Swagger來(lái)自動(dòng)生成Restuful API文檔

一、Swagger簡(jiǎn)介

  上一篇文章中我們介紹了Spring Boot對(duì)Restful的支持,這篇文章我們繼續(xù)討論這個(gè)話題,不過(guò),我們這里不再討論Restful API如何實(shí)現(xiàn),而是討論Restful API文檔的維護(hù)問(wèn)題。

  在日常的工作中,我們往往需要給前端(WEB端、IOS、Android)或者第三方提供接口,這個(gè)時(shí)候我們就需要給他們提供一份詳細(xì)的API說(shuō)明文檔。但維護(hù)一份詳細(xì)的文檔可不是一件簡(jiǎn)單的事情。首先,編寫(xiě)一份詳細(xì)的文檔本身就是一件很費(fèi)時(shí)費(fèi)力的事情,另一方面,由于代碼和文檔是分離的,所以很容易導(dǎo)致文檔和代碼的不一致。這篇文章我們就來(lái)分享一種API文檔維護(hù)的方式,即通過(guò)Swagger來(lái)自動(dòng)生成Restuful API文檔。

  那什么是Swagger?我們可以直接看下官方的描述:

THE WORLD'S MOST POPULAR API TOOLING
Swagger is the world's largest framework of API developer tools for the OpenAPI Specification(OAS),
enabling development across the entire API lifecycle, from design and documentation, to test and deployment.

  這段話首先告訴大家Swagger是世界上最流行的API工具,并且Swagger的目的是支撐整個(gè)API生命周期的開(kāi)發(fā),包括設(shè)計(jì)、文檔以及測(cè)試和部署。這篇文章中我們會(huì)用到Swagger的文檔管理和測(cè)試功能。

  對(duì)Swagger的作用有了基本的認(rèn)識(shí)后,我們現(xiàn)在來(lái)看看怎么使用。

二、Swagger與Spring boot集成

  第一步:引入對(duì)應(yīng)jar包:

<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.6.0</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.6.0</version>
</dependency>

  第二步,基本信息配置:

@Configuration
@EnableSwagger2
public class Swagger2Config {
  @Bean
  public Docket createRestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
        .apiInfo(apiInfo())
        .select()
        .apis(RequestHandlerSelectors.basePackage("com.pandy.blog.rest"))
        .paths(PathSelectors.regex("/rest/.*"))
        .build();
  }
 
  private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
        .title("Blog系統(tǒng)Restful API")
        .description("Blog系統(tǒng)Restful API")
        .termsOfServiceUrl("http://127.0.0.1:8080/")
        .contact("liuxiaopeng")
        .version("1.0")
        .build();
  }
}

  基礎(chǔ)的配置是對(duì)整個(gè)API文檔的描述以及一些全局性的配置,對(duì)所有接口起作用。這里涉及到兩個(gè)注解:

  @Configuration是表示這是一個(gè)配置類,是JDK自帶的注解,前面的文章中也已做過(guò)說(shuō)明。

  @EnableSwagger2的作用是啟用Swagger2相關(guān)功能。

  在這個(gè)配置類里面我么實(shí)例化了一個(gè)Docket對(duì)象,這個(gè)對(duì)象主要包括三個(gè)方面的信息:

   ?。?)整個(gè)API的描述信息,即ApiInfo對(duì)象包括的信息,這部分信息會(huì)在頁(yè)面上展示。

    (2)指定生成API文檔的包名。

    (3)指定生成API的路徑。按路徑生成API可支持四種模式,這個(gè)可以參考其源碼:

public class PathSelectors {
  private PathSelectors() {
    throw new UnsupportedOperationException();
  }
 
  public static Predicate<String> any() {
    return Predicates.alwaysTrue();
  }
 
  public static Predicate<String> none() {
    return Predicates.alwaysFalse();
  }
 
  public static Predicate<String> regex(final String pathRegex) {
    return new Predicate<String>() {
      public boolean apply(String input) {
        return input.matches(pathRegex);
      }
    };
  }
 
  public static Predicate<String> ant(final String antPattern) {
    return new Predicate<String>() {
      public boolean apply(String input) {
        AntPathMatcher matcher = new AntPathMatcher();
        return matcher.match(antPattern, input);
      }
    };
  }
}

  從源碼可以看出,Swagger總共支持任何路徑都生成、任何路徑都不生成以及正則匹配和ant 模式匹配四種方式。大家可能比較熟悉的是前三種,最后一種ant匹配,如果不熟悉ant的話就直接忽略吧,前三種應(yīng)該足夠大家在日常工作中使用了。

  有了上面的配置我們就可以看到效果了,我在com.pandy.blog.rest這個(gè)包下面有一個(gè)ArticleRestController這個(gè)類,源碼如下:

  啟動(dòng)Spring boot,然后訪問(wèn):http://127.0.0.1:8080/swagger-ui.html即可看到如下結(jié)果:

   這個(gè)頁(yè)面上可以看到,除了最后一個(gè)接口/test/{id}外,其他接口都生成對(duì)應(yīng)的文檔,最后一個(gè)接口因?yàn)椴粷M足我們配置的路徑——“/rest/.*”,所以沒(méi)有生成文檔。

  我們還可以點(diǎn)進(jìn)去看一下每一個(gè)具體的接口,我們這里以“POST /rest/article”這個(gè)接口為例:

  可以看到,Swagger為每一個(gè)接口都生成了返回結(jié)果和請(qǐng)求參數(shù)的示例,并且能直接通過(guò)下面的"try it out"進(jìn)行接口訪問(wèn),方面大家對(duì)接口進(jìn)行測(cè)試。整體上感覺(jué)Swagger還是很強(qiáng)大的,配置也比較簡(jiǎn)單。

@RestController
public class ArticleRestController {
  @Autowired
  private ArticleService articleService;
  @RequestMapping(value = "/rest/article", method = POST, produces = "application/json")
  public WebResponse<Map<String, Object>> saveArticle(@RequestBody Article article) {
    article.setUserId(1L);
    articleService.saveArticle(article);
    Map<String, Object> ret = new HashMap<>();
    ret.put("id", article.getId());
    WebResponse<Map<String, Object>> response = WebResponse.getSuccessResponse(ret);
    return response;
  }
  @RequestMapping(value = "/rest/article/{id}", method = DELETE, produces = "application/json")
  public WebResponse<?> deleteArticle(@PathVariable Long id) {
    Article article = articleService.getById(id);
    article.setStatus(-1);
    articleService.updateArticle(article);
    WebResponse<Object> response = WebResponse.getSuccessResponse(null);
    return response;
  }
  @RequestMapping(value = "/rest/article/{id}", method = PUT, produces = "application/json")
  public WebResponse<Object> updateArticle(@PathVariable Long id, @RequestBody Article article) {
    article.setId(id);
    articleService.updateArticle(article);
    WebResponse<Object> response = WebResponse.getSuccessResponse(null);
    return response;
  }
  @RequestMapping(value = "/rest/article/{id}", method = GET, produces = "application/json")
  public WebResponse<Article> getArticle(@PathVariable Long id) {
    Article article = articleService.getById(id);
    WebResponse<Article> response = WebResponse.getSuccessResponse(article);
    return response;
  }
  @RequestMapping(value = "/test/{id}", method = GET, produces = "application/json")
  public WebResponse<?> getNoApi(){
    WebResponse<?> response = WebResponse.getSuccessResponse(null);
    return response;
  }
}

三、Swagger API詳細(xì)配置

   不過(guò)大家看到這里肯定會(huì)有點(diǎn)疑問(wèn):

    第一個(gè)問(wèn)題:這個(gè)返回結(jié)果和請(qǐng)求參數(shù)都沒(méi)有文字性的描述,這個(gè)可不可以配置?

    第二個(gè)問(wèn)題:這個(gè)請(qǐng)求參應(yīng)該是直接根據(jù)對(duì)象反射出來(lái)的結(jié)果,但是不是對(duì)象的每個(gè)屬性都是必傳的,另外參數(shù)的值也不一定滿足我們的需求,這個(gè)能否配置?

  答案肯定是可以的,現(xiàn)在我們就來(lái)解決這兩個(gè)問(wèn)題,直接看配置的代碼:

package com.pandy.blog.rest;
import com.pandy.blog.dto.WebResponse;
import com.pandy.blog.po.Article;
import com.pandy.blog.service.ArticleService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
@RestController
@RequestMapping("/rest")
public class ArticleRestController {
  @Autowired
  private ArticleService articleService;
  @RequestMapping(value = "/article", method = POST, produces = "application/json")
  @ApiOperation(value = "添加文章", notes = "添加新的文章", tags = "Article",httpMethod = "POST")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "title", value = "文章標(biāo)題", required = true, dataType = "String"),
      @ApiImplicitParam(name = "summary", value = "文章摘要", required = true, dataType = "String"),
      @ApiImplicitParam(name = "status", value = "發(fā)布狀態(tài)", required = true, dataType = "Integer")
  })
  @ApiResponses({
      @ApiResponse(code=200,message="成功",response=WebResponse.class),
  })
  public WebResponse<Map<String,Object>> saveArticle(@RequestBody Article article){
    articleService.saveArticle(article);
    Map<String,Object> ret = new HashMap<>();
    ret.put("id",article.getId());
    WebResponse<Map<String,Object>> response = WebResponse.getSuccessResponse(ret);
    return response;
  }
  @ApiOperation(value = "刪除文章", notes = "根據(jù)ID刪除文章", tags = "Article",httpMethod = "DELETE")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "id", value = "文章ID", required = true, dataType = "Long")
  })
  @RequestMapping(value = "/{id}",method = DELETE,produces = "application/json")
  public WebResponse<?> deleteArticle(@PathVariable Long id){
    Article article = articleService.getById(id);
    article.setStatus(-1);
    articleService.saveArticle(article);
    return WebResponse.getSuccessResponse(new HashMap<>());
  }
  @ApiOperation(value = "獲取文章列表", notes = "可以根據(jù)標(biāo)題進(jìn)行模糊查詢", tags = "Article",httpMethod = "GET")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "title", value = "文章標(biāo)題", required = false, dataType = "String"),
      @ApiImplicitParam(name = "pageSize", value = "每頁(yè)文章數(shù)量", required = false, dataType = "Integer"),
      @ApiImplicitParam(name = "pageNum", value = "分頁(yè)的頁(yè)碼", required = false, dataType = "Integer")
  })
  @RequestMapping(value = "/article/list", method = GET, produces = "application/json")
  public WebResponse<?> listArticles(String title, Integer pageSize, Integer pageNum) {
    if (pageSize == null) {
      pageSize = 10;
    }
    if (pageNum == null) {
      pageNum = 1;
    }
    int offset = (pageNum - 1) * pageSize;
    List<Article> articles = articleService.getArticles(title, 1L, offset, pageSize);
    return WebResponse.getSuccessResponse(articles);
  }
  @ApiOperation(value = "更新文章", notes = "更新文章內(nèi)容", tags = "Article",httpMethod = "PUT")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "id", value = "文章ID", required = true, dataType = "Long"),
      @ApiImplicitParam(name = "title", value = "文章標(biāo)題", required = false, dataType = "String"),
      @ApiImplicitParam(name = "summary", value = "文章摘要", required = false, dataType = "String"),
      @ApiImplicitParam(name = "status", value = "發(fā)布狀態(tài)", required = false, dataType = "Integer")
  })
  @RequestMapping(value = "/article/{id}", method = PUT, produces = "application/json")
  public WebResponse<?> updateArticle(@PathVariable Long id,@RequestBody Article article){
    article.setId(id);
    articleService.updateArticle(article);
    return WebResponse.getSuccessResponse(new HashMap<>());
  }
}

  我們解釋一下代碼中幾個(gè)注解及相關(guān)屬性的具體作用:

  @ApiOperation,整個(gè)接口屬性配置:

    value:接口說(shuō)明,展示在接口列表。

    notes:接口詳細(xì)說(shuō)明,展示在接口的詳情頁(yè)。

    tags:接口的標(biāo)簽,相同標(biāo)簽的接口會(huì)在一個(gè)標(biāo)簽頁(yè)下展示。

    httpMethod:支持的HTTP的方法。

  @ApiImplicitParams,@ApiImplicitParam的容器,可包含多個(gè)@ApiImplicitParam注解

  @ApiImplicitParam,請(qǐng)求參數(shù)屬性配置:

    name:參數(shù)名稱

    value:參數(shù)說(shuō)明

    required:是否必須

    dataType:數(shù)據(jù)類型  

  @ApiResponses,@ApiResponse容器,可以包含多個(gè)@ApiResponse注解

  @ApiResponse,返回結(jié)果屬性配置:

    code:返回結(jié)果的編碼。

    message:返回結(jié)果的說(shuō)明。

    response:返回結(jié)果對(duì)應(yīng)的類?!   ?/p>

  完成以上配置后,我們?cè)倏聪马?yè)面效果:

列表頁(yè):   

         

   可以看到,現(xiàn)在接口都位于Article這個(gè)tag下,并且接口后面也有了我們配置好的說(shuō)明。我們?cè)倏聪隆盤(pán)OST /rest/article“這個(gè)接口的詳情頁(yè):

  圖片太大,只截取了title屬性的展示,其他幾個(gè)參數(shù)的類似。我們可以從頁(yè)面上看到請(qǐng)求參數(shù)的說(shuō)明是有的,不過(guò)這不是我們預(yù)期的效果,如果我們的參數(shù)僅僅是簡(jiǎn)單類型,這種方式應(yīng)該沒(méi)問(wèn)題,但現(xiàn)在的問(wèn)題是我們的請(qǐng)求參數(shù)是一個(gè)對(duì)象,那如何配置呢?這就涉及到另外兩個(gè)注解:@ApiModel和@ApiModelProperty,我們還是先看代碼,然后再解釋,這樣更容易理解:

@ApiModel(value="article對(duì)象",description="新增&更新文章對(duì)象說(shuō)明")
public class Article {
  @Id
  @GeneratedValue
  @ApiModelProperty(name = "id",value = "文章ID",required = false,example = "1")
  private Long id;
  @ApiModelProperty(name = "title",value = "文章標(biāo)題",required = true,example = "測(cè)試文章標(biāo)題")
  private String title;
  @ApiModelProperty(name = "summary",value = "文章摘要",required = true,example = "測(cè)試文章摘要")
  private String summary;
  @ApiModelProperty(hidden = true)
  private Date createTime;
  @ApiModelProperty(hidden = true)
  private Date publicTime;
  @ApiModelProperty(hidden = true)
  private Date updateTime;
  @ApiModelProperty(hidden = true)
  private Long userId;
  @ApiModelProperty(name = "status",value = "文章發(fā)布狀態(tài)",required = true,example = "1")
  private Integer status;
  @ApiModelProperty(name = "type",value = "文章分類",required = true,example = "1")
  private Integer type;
}

  @ApiModel是對(duì)整個(gè)類的屬性的配置:

    value:類的說(shuō)明

    description:詳細(xì)描述

  @ApiModelProperty是對(duì)具體每個(gè)字段的屬性配置:

    name:字段名稱

    value:字段的說(shuō)明

    required:是否必須

    example:示例值

    hidden:是否顯示

  完成上面的配置后,我們?cè)賮?lái)看效果:

 

  現(xiàn)在我們可以看到,字段的說(shuō)明都已經(jīng)展示出來(lái),并且,示例中字段的值也變成了我們配置的example屬性對(duì)應(yīng)的值了。這樣,一份完整的API文檔就生成了,并且該文檔與代碼緊密的聯(lián)系在一起,而不是隔離的兩個(gè)部分。除此之外,我們還可以直接通過(guò)該文檔很方便的進(jìn)行測(cè)試,我們只需要點(diǎn)擊Example Value下黃色的框,里面的內(nèi)容就會(huì)自動(dòng)復(fù)制到article對(duì)應(yīng)的value框中,然后在點(diǎn)擊“Try it out”就可以發(fā)起http請(qǐng)求了。

 

  點(diǎn)擊Try it out后,我們就可以看到返回的結(jié)果:

  操作還是很方便的,相比Junit和postman,通過(guò)Swagger來(lái)測(cè)試會(huì)更加便捷,當(dāng)然,Swagger的測(cè)試并不能代替單元測(cè)試,不過(guò),在聯(lián)調(diào)的時(shí)候還是有非常大的作用的。

四、總結(jié)

  總體上來(lái)說(shuō),Swagger的配置還是比較簡(jiǎn)單的,并且Swagger能夠自動(dòng)幫我們生成文檔確實(shí)為我們節(jié)省了不少工作,對(duì)后續(xù)的維護(hù)也提供了很大的幫助。除此之外,Swagger還能根據(jù)配置自動(dòng)為我們生成測(cè)試的數(shù)據(jù),并且提供對(duì)應(yīng)的HTTP方法,這對(duì)我們的自測(cè)和聯(lián)調(diào)工作也有不少的幫助,所以我還是推薦大家在日常的開(kāi)發(fā)中去使用Swagger,應(yīng)該可以幫助大家在一定程度上提高工作效率的。最后,留一個(gè)問(wèn)題給大家思考吧,就是該文檔是可以直接通過(guò)頁(yè)面來(lái)訪問(wèn)的,那我們總不能把接口直接暴露在生產(chǎn)環(huán)境吧,尤其是要對(duì)外提供服務(wù)的系統(tǒng),那我們?cè)趺床拍茉谏a(chǎn)環(huán)節(jié)中關(guān)閉這個(gè)功能呢?方法有很多,大家可以自己嘗試一下。

以上所述是小編給大家介紹的Spring Boot集成Swagger2項(xiàng)目實(shí)戰(zhàn),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Spring實(shí)戰(zhàn)之注入嵌套Bean操作示例

    Spring實(shí)戰(zhàn)之注入嵌套Bean操作示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之注入嵌套Bean操作,結(jié)合實(shí)例形式分析了嵌套Bean相關(guān)配置與使用操作技巧,需要的朋友可以參考下
    2019-11-11
  • Java設(shè)計(jì)模式中觀察者模式詳解

    Java設(shè)計(jì)模式中觀察者模式詳解

    觀察者模式是極其重要的一個(gè)設(shè)計(jì)模式,也是我?guī)啄觊_(kāi)發(fā)過(guò)程中使用最多的設(shè)計(jì)模式,本文首先概述觀察者模式的基本概念和Demo實(shí)現(xiàn),接著是觀察者模式在Java和Spring中的應(yīng)用,最后是對(duì)觀察者模式的應(yīng)用場(chǎng)景和優(yōu)缺點(diǎn)進(jìn)行總結(jié)
    2022-11-11
  • Java加密 消息摘要算法SHA實(shí)現(xiàn)詳解

    Java加密 消息摘要算法SHA實(shí)現(xiàn)詳解

    這篇文章主要介紹了Java加密 消息摘要算法SHA實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • SpringBoot Security密碼加鹽實(shí)例

    SpringBoot Security密碼加鹽實(shí)例

    這篇文章主要為打擊介紹了SpringBoot Security密碼加鹽實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Java正則表達(dá)式判斷是否包含數(shù)字、字母、特殊字符及中文的多種方法

    Java正則表達(dá)式判斷是否包含數(shù)字、字母、特殊字符及中文的多種方法

    這篇文章主要給大家介紹了關(guān)于Java正則表達(dá)式判斷是否包含數(shù)字、字母、特殊字符及中文的多種方法,Java正則表達(dá)式在字符串處理和模式匹配中扮演著重要角色,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • Eclipse中@SpringBootTest注解報(bào)紅的解決方案

    Eclipse中@SpringBootTest注解報(bào)紅的解決方案

    這篇文章主要介紹了Eclipse中@SpringBootTest注解報(bào)紅的解決方案,文中給出了原因分析和解決方案,并通過(guò)圖文結(jié)合的方式介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • 聊聊Spring循環(huán)依賴三級(jí)緩存是否可以減少為二級(jí)緩存的情況

    聊聊Spring循環(huán)依賴三級(jí)緩存是否可以減少為二級(jí)緩存的情況

    這篇文章主要介紹了聊聊Spring循環(huán)依賴三級(jí)緩存是否可以減少為二級(jí)緩存的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • MyBatis逆向工程生成dao層增刪改查的操作

    MyBatis逆向工程生成dao層增刪改查的操作

    這篇文章主要介紹了MyBatis逆向工程生成dao層增刪改查的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java基礎(chǔ)教程之組合(composition)

    Java基礎(chǔ)教程之組合(composition)

    這篇文章主要介紹了Java基礎(chǔ)教程之組合(composition),組合是在Java中實(shí)現(xiàn)程序復(fù)用(reusibility)的基本手段之一,需要的朋友可以參考下
    2014-08-08
  • java sqlserver text 類型字段讀取方法

    java sqlserver text 類型字段讀取方法

    有這樣一個(gè)需求,需要將原本存儲(chǔ)在數(shù)據(jù)庫(kù)中的文檔轉(zhuǎn)存至文件系統(tǒng)中,于是寫(xiě)了一個(gè)簡(jiǎn)單的程序完成此功能
    2012-11-11

最新評(píng)論