亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

Spring Boot集成Swagger2項目實戰

2024-07-13 10:16:45
字體:
來源:轉載
供稿:網友

一、Swagger簡介

  上一篇文章中我們介紹了Spring Boot對Restful的支持,這篇文章我們繼續討論這個話題,不過,我們這里不再討論Restful API如何實現,而是討論Restful API文檔的維護問題。

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

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

THE WORLD'S MOST POPULAR API TOOLINGSwagger 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的目的是支撐整個API生命周期的開發,包括設計、文檔以及測試和部署。這篇文章中我們會用到Swagger的文檔管理和測試功能。

  對Swagger的作用有了基本的認識后,我們現在來看看怎么使用。

二、Swagger與Spring boot集成

  第一步:引入對應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@EnableSwagger2public 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系統Restful API")        .description("Blog系統Restful API")        .termsOfServiceUrl("http://127.0.0.1:8080/")        .contact("liuxiaopeng")        .version("1.0")        .build();  }}

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

  @Configuration是表示這是一個配置類,是JDK自帶的注解,前面的文章中也已做過說明。

  @EnableSwagger2的作用是啟用Swagger2相關功能。

  在這個配置類里面我么實例化了一個Docket對象,這個對象主要包括三個方面的信息:

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

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

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

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的話就直接忽略吧,前三種應該足夠大家在日常工作中使用了。

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

  啟動Spring boot,然后訪問:http://127.0.0.1:8080/swagger-ui.html即可看到如下結果:

spring,boot實戰,boot,Swagger2

   這個頁面上可以看到,除了最后一個接口/test/{id}外,其他接口都生成對應的文檔,最后一個接口因為不滿足我們配置的路徑——“/rest/.*”,所以沒有生成文檔。

  我們還可以點進去看一下每一個具體的接口,我們這里以“POST /rest/article”這個接口為例:

spring,boot實戰,boot,Swagger2

  可以看到,Swagger為每一個接口都生成了返回結果和請求參數的示例,并且能直接通過下面的"try it out"進行接口訪問,方面大家對接口進行測試。整體上感覺Swagger還是很強大的,配置也比較簡單。

@RestControllerpublic 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詳細配置

   不過大家看到這里肯定會有點疑問:

    第一個問題:這個返回結果和請求參數都沒有文字性的描述,這個可不可以配置?

    第二個問題:這個請求參應該是直接根據對象反射出來的結果,但是不是對象的每個屬性都是必傳的,另外參數的值也不一定滿足我們的需求,這個能否配置?

  答案肯定是可以的,現在我們就來解決這兩個問題,直接看配置的代碼:

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 = "文章標題", required = true, dataType = "String"),      @ApiImplicitParam(name = "summary", value = "文章摘要", required = true, dataType = "String"),      @ApiImplicitParam(name = "status", value = "發布狀態", 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 = "根據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 = "可以根據標題進行模糊查詢", tags = "Article",httpMethod = "GET")  @ApiImplicitParams({      @ApiImplicitParam(name = "title", value = "文章標題", required = false, dataType = "String"),      @ApiImplicitParam(name = "pageSize", value = "每頁文章數量", required = false, dataType = "Integer"),      @ApiImplicitParam(name = "pageNum", value = "分頁的頁碼", 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 = "更新文章內容", tags = "Article",httpMethod = "PUT")  @ApiImplicitParams({      @ApiImplicitParam(name = "id", value = "文章ID", required = true, dataType = "Long"),      @ApiImplicitParam(name = "title", value = "文章標題", required = false, dataType = "String"),      @ApiImplicitParam(name = "summary", value = "文章摘要", required = false, dataType = "String"),      @ApiImplicitParam(name = "status", value = "發布狀態", 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<>());  }}

  我們解釋一下代碼中幾個注解及相關屬性的具體作用:

  @ApiOperation,整個接口屬性配置:

    value:接口說明,展示在接口列表。

    notes:接口詳細說明,展示在接口的詳情頁。

    tags:接口的標簽,相同標簽的接口會在一個標簽頁下展示。

    httpMethod:支持的HTTP的方法。

  @ApiImplicitParams,@ApiImplicitParam的容器,可包含多個@ApiImplicitParam注解

  @ApiImplicitParam,請求參數屬性配置:

    name:參數名稱

    value:參數說明

    required:是否必須

    dataType:數據類型  

  @ApiResponses,@ApiResponse容器,可以包含多個@ApiResponse注解

  @ApiResponse,返回結果屬性配置:

    code:返回結果的編碼。

    message:返回結果的說明。

    response:返回結果對應的類?!   ?/p>

  完成以上配置后,我們再看下頁面效果:

列表頁:   

spring,boot實戰,boot,Swagger2         

   可以看到,現在接口都位于Article這個tag下,并且接口后面也有了我們配置好的說明。我們再看下”POST /rest/article“這個接口的詳情頁:

spring,boot實戰,boot,Swagger2

  圖片太大,只截取了title屬性的展示,其他幾個參數的類似。我們可以從頁面上看到請求參數的說明是有的,不過這不是我們預期的效果,如果我們的參數僅僅是簡單類型,這種方式應該沒問題,但現在的問題是我們的請求參數是一個對象,那如何配置呢?這就涉及到另外兩個注解:@ApiModel和@ApiModelProperty,我們還是先看代碼,然后再解釋,這樣更容易理解:

@ApiModel(value="article對象",description="新增&更新文章對象說明")public class Article {  @Id  @GeneratedValue  @ApiModelProperty(name = "id",value = "文章ID",required = false,example = "1")  private Long id;  @ApiModelProperty(name = "title",value = "文章標題",required = true,example = "測試文章標題")  private String title;  @ApiModelProperty(name = "summary",value = "文章摘要",required = true,example = "測試文章摘要")  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 = "文章發布狀態",required = true,example = "1")  private Integer status;  @ApiModelProperty(name = "type",value = "文章分類",required = true,example = "1")  private Integer type;}

  @ApiModel是對整個類的屬性的配置:

    value:類的說明

    description:詳細描述

  @ApiModelProperty是對具體每個字段的屬性配置:

    name:字段名稱

    value:字段的說明

    required:是否必須

    example:示例值

    hidden:是否顯示

  完成上面的配置后,我們再來看效果:

 

spring,boot實戰,boot,Swagger2

spring,boot實戰,boot,Swagger2

  現在我們可以看到,字段的說明都已經展示出來,并且,示例中字段的值也變成了我們配置的example屬性對應的值了。這樣,一份完整的API文檔就生成了,并且該文檔與代碼緊密的聯系在一起,而不是隔離的兩個部分。除此之外,我們還可以直接通過該文檔很方便的進行測試,我們只需要點擊Example Value下黃色的框,里面的內容就會自動復制到article對應的value框中,然后在點擊“Try it out”就可以發起http請求了。

 spring,boot實戰,boot,Swagger2

  點擊Try it out后,我們就可以看到返回的結果:

spring,boot實戰,boot,Swagger2

  操作還是很方便的,相比Junit和postman,通過Swagger來測試會更加便捷,當然,Swagger的測試并不能代替單元測試,不過,在聯調的時候還是有非常大的作用的。

四、總結

  總體上來說,Swagger的配置還是比較簡單的,并且Swagger能夠自動幫我們生成文檔確實為我們節省了不少工作,對后續的維護也提供了很大的幫助。除此之外,Swagger還能根據配置自動為我們生成測試的數據,并且提供對應的HTTP方法,這對我們的自測和聯調工作也有不少的幫助,所以我還是推薦大家在日常的開發中去使用Swagger,應該可以幫助大家在一定程度上提高工作效率的。最后,留一個問題給大家思考吧,就是該文檔是可以直接通過頁面來訪問的,那我們總不能把接口直接暴露在生產環境吧,尤其是要對外提供服務的系統,那我們怎么才能在生產環節中關閉這個功能呢?方法有很多,大家可以自己嘗試一下。

以上所述是小編給大家介紹的Spring Boot集成Swagger2項目實戰,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲午夜精品久久久久久性色| 久久久精品免费视频| 色先锋久久影院av| 亚洲人成电影在线| 一区二区三区高清国产| 欧美激情精品久久久| 丁香五六月婷婷久久激情| 成年人精品视频| 欧美激情按摩在线| 国产91精品久久久久久久| 亚洲人成亚洲人成在线观看| 欧美精品videossex性护士| 久久综合免费视频影院| 琪琪第一精品导航| 亚洲情综合五月天| 日韩电影网在线| 久久久久久国产精品久久| 97免费视频在线播放| 亚洲精品少妇网址| 日韩av色综合| 久久天天躁狠狠躁老女人| 992tv成人免费影院| 国产亚洲欧洲高清| 91色视频在线观看| 成人综合网网址| 国产精品一区二区久久精品| 国产色综合天天综合网| 日本免费久久高清视频| 精品国产户外野外| 色偷偷888欧美精品久久久| 国产精品久久久久99| 日韩hd视频在线观看| 日本一区二区在线免费播放| 国产亚洲精品久久久| 国产精品一区av| 日韩av在线最新| 亚洲人午夜色婷婷| 日韩精品在线观看网站| 日本精品免费观看| 欧美国产中文字幕| 色悠悠久久久久| 久久视频在线直播| 中文字幕亚洲欧美日韩在线不卡| 国产成人综合久久| 久久免费精品视频| 中文字幕日韩高清| 91色中文字幕| 97热精品视频官网| 久久香蕉国产线看观看网| 搡老女人一区二区三区视频tv| 色偷偷av亚洲男人的天堂| 中文字幕av一区二区| 欧美激情综合色| 国产欧美日韩视频| 91精品在线国产| 国产精品91在线| 国产精品直播网红| 最好看的2019年中文视频| 日韩激情av在线播放| …久久精品99久久香蕉国产| 日韩成人激情视频| 欧美日韩中文在线观看| 亚洲男女性事视频| 久久成人综合视频| 亚洲黄页网在线观看| 91精品视频免费看| 亚洲男人天堂九九视频| 国产精品视频xxx| 2019中文在线观看| 中文字幕亚洲欧美一区二区三区| 国产精品一二三在线| 欧美成人精品一区二区三区| 欧美激情视频网址| 97国产精品久久| 伊人亚洲福利一区二区三区| 成人福利网站在线观看| 亚洲精品av在线播放| 欧美专区国产专区| 啪一啪鲁一鲁2019在线视频| 国产精品91久久久久久| 91久久精品久久国产性色也91| 欧美一区二区三区图| 亚洲欧美国产另类| 日韩久久免费视频| 久久在线免费观看视频| 欧美中在线观看| 欧美孕妇性xx| 大桥未久av一区二区三区| 在线播放国产一区中文字幕剧情欧美| 欧美日韩亚洲精品一区二区三区| 国产综合在线视频| 久久久91精品国产| 成人av在线网址| 国产精品尤物福利片在线观看| 欧美精品videos另类日本| 国产精品久久久久免费a∨大胸| 色综合久久天天综线观看| 蜜月aⅴ免费一区二区三区| 欧美性猛交99久久久久99按摩| 亚洲一区二区三区sesese| 日韩欧美在线视频日韩欧美在线视频| 日韩欧美国产免费播放| 久久91精品国产91久久久| 亚洲性69xxxbbb| 国产欧美日韩丝袜精品一区| 亚洲精品免费一区二区三区| 亚洲色图av在线| 亚洲欧美中文日韩在线| 亚洲精品视频在线观看视频| 国产精品免费福利| 国产亚洲精品美女久久久| 日本久久久久久久久| 精品国产一区二区三区久久| 欧美国产亚洲精品久久久8v| 欧美中文在线字幕| 成人情趣片在线观看免费| 欧美精品电影免费在线观看| 伊人久久综合97精品| 久久久国产成人精品| 欧美丰满少妇xxxxx做受| 大量国产精品视频| 亚洲黄色成人网| 啪一啪鲁一鲁2019在线视频| 性欧美亚洲xxxx乳在线观看| 日韩av色综合| 国产精品户外野外| 亚洲男人天堂古典| 国产精品jvid在线观看蜜臀| 久久久久久有精品国产| 欧美激情一区二区三区高清视频| 亚洲精品中文字幕女同| 亚洲免费中文字幕| 国产成人精品日本亚洲| 亚洲欧美在线免费| 久久成人这里只有精品| 97热精品视频官网| 国产亚洲欧美日韩一区二区| 欧美日韩国产一区二区| 国产成人综合精品在线| 成人欧美一区二区三区在线| 国产精品欧美久久久| 久久精品中文字幕| 精品国产区一区二区三区在线观看| 日韩在线视频中文字幕| 久久精彩免费视频| 日韩欧美国产成人| 精品久久久一区| 亚洲视频在线看| 最近2019年日本中文免费字幕| 国产亚洲欧美日韩精品| 欧美日本在线视频中文字字幕| 国产精品福利在线观看网址| 91国产视频在线| 成人中心免费视频| 亚洲天堂开心观看| 亚洲最新视频在线| 久久久久久久色| 国产精品福利在线观看| 亚洲日本中文字幕免费在线不卡| 国产精品成av人在线视午夜片| 97人人模人人爽人人喊中文字| 欧美国产日韩一区| 成人黄色av播放免费| 日韩视频免费观看|