溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Boot從零入門6_Swagger2生成生產環

發布時間:2020-08-03 23:57:54 來源:網絡 閱讀:449 作者:艾弗森哇 欄目:開發技術

1 前言

在如今前后端分離開發的模式下,前端調用后端提供的API去實現數據的展示或者相關的數據操作,保證及時更新和完整的REST API文檔將會大大地提高兩邊的工作效率,減少不必要的溝通成本。本文采用的Swagger2就是一個當前流行的通過少量的注解就可以生成漂亮的API文檔工具,且在生成的在線文檔中提供類似POSTMAN直接調試能力,不僅僅是靜態的文檔。接下來將會利用這個工具與Spring Boot項目結合,最終生成我們上一篇文章中所涉及到的REST API文檔。

這一篇文章基本將Swagger2在生產環境中可能會用到的配置都有涉及,慢慢看吧,看了這一篇因該是夠了。

2 Swagger2簡介

Swagger是與用于實現 OpenAPI 文檔廣泛使用的工具,Swagger工具集包括開源工具,免費工具和商業工具的組合,可在API生命周期的不同階段使用。

  • Swagger Editor(開源):使用Swagger編輯器,可以在瀏覽器內的YAML文檔中編輯OpenAPI規范并支持實時預覽文檔,可以參考官方的Demo?https://editor.swagger.io/

  • Swagger UI(開源):讓Swagger產生的文檔更漂亮,而且支持API交互操作,在生成文檔后,直接在瀏覽器中瀏覽,并可以實現類似curl命令或者postman訪問我們的API,并返回相關數據。

  • Swagger Codegen(開源): 是一個代碼生成器,可以通過Swagger API定義生成不同語言版本的服務端和客戶端工程代碼。

  • Swagger Core(開源):用于生成Swagger API規范的示例和服務器集成,可輕松訪問REST API,結合Swagger UI,讓生成的文檔更漂亮。

  • Swagger Parser(開源): Java開發,解析OpenAPI定義的獨立庫

  • Swagger Inspector(免費):API在線測試工具,驗證API并從現有API生成OpenAPI定義功能?https://goo.gl/fZYHWz

  • SwaggerHub(免費和商用版):API設計和文檔化,為使用OpenAPI的團隊打造。

3 開始使用

3.1 構建Restful WEB服務

參考《Spring Boot從零入門5_五臟俱全的RESTful Web Service構建》。構建好后有如下REST API:

#?獲取所有用戶信息GET?http://localhost:8080/api/v1/users#?新增一個用戶,參數通過body傳遞POST?http://localhost:8080/api/v1/users#?更新一個用戶信息PUT?http://localhost:8080/api/v1/users/{id}#?刪除指定用戶DELETE?http://localhost:8080/api/v1/users/{id}

3.2 集成Swagger2

構建好RESTful WEB服務后,接下來我們集成Swagger,然后對上節中的REST API自動生成接口文檔。

3.2.1 pom.xml添加依賴

集成Swagger2,需要在pom.xml中添加依賴源:

<dependencies>
	<dependency>
	????<groupid>io.springfox</groupid>
	????<artifactid>springfox-swagger2</artifactid>
	????<!--?截至2019年11月7日為止,最新版本為2.9.2?-->
	????<!--?https://mvnrepository.com/artifact/io.springfox/springfox-swagger2?-->
	????<version>2.9.2</version>
	</dependency></dependencies>
3.2.2 Swagger 配置及初始化

springfox有一個專用對象Docket,可以靈活的配置Swagger的各種屬性,首先我們簡單的創建一個Swagger配置類Swagger2Config.java

@Configuration@EnableSwagger2
public?class?Swagger2Config?{
????@Bean("UsersApis")
????public?Docket?usersApis()?{????????return?new?Docket(DocumentationType.SWAGGER_2)????????????????.select()????????????????.apis(RequestHandlerSelectors.any())????????????????.paths(PathSelectors.any())????????????????.build();
????}
}

這里的@Configuration注解用于定義配置類,被注解的類內部包含有一個或多個被@Bean注解的方法,這些方法將會被AnnotationConfigApplicationContext類進行掃描,并用于構建Bean定義,初始化對象。@ComponentScan會自動獲取所有的Spring Components,包括@Configuration類。另外這里的“用戶管理模塊”API生成配置很簡單,對所有路徑上API都去生成文檔。

3.2.3 啟動服務并驗證

當完成Swagger2的配置類時,啟動WEB服務,通過http://localhost:8080/v2/api-docs就可以訪問生成文檔內容,但是瀏覽器返回的是JSON內容,基本上很難給需要用到相關API的開發人員進行參考。這個時候就需要用到Swagger2 UI了。

3.3 集成Swagger2 UI

pom.xml添加依賴,然后重啟WEB服務就可以了,再次訪問http://localhost:8080/swagger-ui.html,這時候看到的就是WEB文檔了。

<dependency>
????<groupid>io.springfox</groupid>
????<artifactid>springfox-swagger-ui</artifactid>
????<version>2.9.2</version></dependency>

Spring Boot從零入門6_Swagger2生成生產環

從swagger-ui頁面看到的內容有一部無關的內容,或者是如何明顯表現跟項目相關的內容呢?下面章節詳細講解Swagger的各種配置,能夠應用到實際生產環境中去。

4 Swagger2 深度配置

4.1 深度配置目標

首先,如果要將我們最后生成的API文檔給生產環境的開發人員查閱,那么友好的展示信息和歸類是很有必要的,我們接下來實現如下目標:

  • 文檔的各種信息說明

    • 文檔標題

    • 文檔描述

    • 文檔版本號

    • Logo

    • 文檔責任人

    • 文檔許可證信息

    • 文檔服務條款

  • API分組

    • 組描述

    • 各API描述

  • 附加部分(非API)

  • 定制化文檔頁面風格

為了更好地展示API分組功能,這里另外加了一組REST API (代碼層面上只需要將User相關的代碼全部復制一份,將User關鍵字全部改為Product就可以了,包括大小寫):

#?獲取所有產品信息GET?http://localhost:8080/api/v1/products#?新增一個產品,參數通過body傳遞POST?http://localhost:8080/api/v1/products#?更新一個產品信息PUT?http://localhost:8080/api/v1/products/{id}#?刪除指定產品DELETE?http://localhost:8080/api/v1/products/{id}

4.2 文檔信息配置

@Configuration@EnableSwagger2public?class?Swagger2Config?{????@Bean("UsersApis")????public?Docket?usersApis()?{????????return?new?Docket(DocumentationType.SWAGGER_2)????????		//?select()返回的是ApiSelectorBuilder對象,而非Docket對象
????????????????.select()
????????????????.apis(RequestHandlerSelectors.any())
????????????????.paths(PathSelectors.any())?????????????????
????????????????//?build()返回的是Docket對象
????????????????.build()????????????????//?測試API時的主機URL
????????????????.host("https://xiaobaiai.net")????
????????????????//?API前綴
????????????????.pathProvider(new?RelativePathProvider(null)?{????????????????????@Override
????????????????????public?String?getApplicationBasePath()?{????????????????????????return?"/prefix";
????????????????????}
????????????????})
????????????????.apiInfo(apiInfo());
????}????
????public?ApiInfo?apiInfo()?{????	//?API負責人的聯系信息
????	final?Contact?contact?=?new?Contact(????			"Ethan",?"https://xiaobaiai.net",?"ycm_hy@163.com");????????return?new?ApiInfoBuilder()????????	//?API文檔標題
????????????.title("X系統平臺接口文檔")????????????//?API文檔描述
????????????.description("用戶/產品相關API,?更多請關注公眾號:?小白AI?或微信小程序:小白AI博客")????????????//?服務條款URL
????????????.termsOfServiceUrl("https://github.com/yicm")????????????//?API文檔版本
????????????.version("1.0")????????????//?API負責人的聯系信息
????????????.contact(contact)????????????//?API的許可證Url
????????????.licenseUrl("http://license.coscl.org.cn/MulanPSL")
????????????.license("MulanPSL")
????????????.build();
????}
}

通過添加文檔信息編譯對象ApiInfoBuilder可以配置API文檔的各種信息,包括標題、描述、服務條款、版本、責任人、許可證等。最后在Docket中添加信息配置對象即可生效。

4.3 API分組配置、API精細配置

4.3.1 API分組展示

上面的文檔信息配置中默認是沒有對API分組的,即所有的API都展示在了一個頁面,沒有隔離,如果需要分組,那我們需要對不同API組分配Bean,目前示例可以分為用戶API組和產品API組,然后通過apis()?和?paths()進行API過濾。

為了不顯示某個包下面API或某個URL路徑下API,?Docket提供了?apis()?和?paths()?兩 個方法來幫助我們在不同級別上過濾接口(上面示例我們默認對這兩個設置是不做任何過濾,掃描所有API):

  • apis():這種方式可以通過指定包名的方式,讓 Swagger2 只去某些包下面掃描

  • paths():這種方式可以通過篩選 API 的 URL 來進行過濾

apis和paths中的Predicates除了any、ant、none,還支持regex正則表達式。

如:

PathSelectors.regex("/api/v2/users.*")

下面就是分組示例代碼,實現分組,很簡單,就是在Docket中配置組名就好了:

@Configuration@EnableSwagger2public?class?Swagger2Config?{????@Bean
????public?Docket?usersApis()?{????????return?new?Docket(DocumentationType.SWAGGER_2)
????????		.groupName("用戶管理接口")????????		//?select()返回的是ApiSelectorBuilder對象,而非Docket對象
????????????????.select()
????????????????
????????????????.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))
????????????????.paths(Predicates.or(????????????????????????//?兩個**,可以匹配底下所有URL
????????????????????????//?一個*,只能匹配一級URL分段
????????????????????????PathSelectors.ant("/api/v1/users/**"),
????????????????????????PathSelectors.ant("/api/v1/users/*")))??????????????
????????????????//?build()返回的是Docket對象
????????????????.build()????????????????//?測試API時的主機URL
????????????????.host("https://xiaobaiai.net")????
????????????????//?API前綴,最終所有API的基礎地址就是host+prefix:?https://xiaobaiai.net/prefix
????????????????.pathProvider(new?RelativePathProvider(null)?{????????????????????@Override
????????????????????public?String?getApplicationBasePath()?{????????????????????????return?"/prefix";
????????????????????}
????????????????})
????????????????.apiInfo(apiInfo());
????}????
????@Bean
????public?Docket?productsApis()?{????????return?new?Docket(DocumentationType.SWAGGER_2)
????????		.groupName("產品管理接口")????????		//?select()返回的是ApiSelectorBuilder對象,而非Docket對象
????????????????.select()
????????????????
????????????????.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product"))
????????????????.paths(Predicates.or(????????????????????????//?兩個**,可以匹配底下所有URL
????????????????????????//?一個*,只能匹配一級URL分段
????????????????????????PathSelectors.ant("/api/v1/products/**"),
????????????????????????PathSelectors.ant("/api/v1/products/*")))??????????????
????????????????//?build()返回的是Docket對象
????????????????.build()????????????????//?測試API時的主機URL
????????????????.host("https://xiaobaiai.net")????
????????????????//?API前綴
????????????????.pathProvider(new?RelativePathProvider(null)?{????????????????????@Override
????????????????????public?String?getApplicationBasePath()?{????????????????????????return?"/prefix";
????????????????????}
????????????????})
????????????????.apiInfo(apiInfo());
????}????
????public?ApiInfo?apiInfo()?{????	//?API負責人的聯系信息
????	final?Contact?contact?=?new?Contact(????			"Ethan",?"https://xiaobaiai.net",?"ycm_hy@163.com");????????return?new?ApiInfoBuilder()????????	//?API文檔標題
????????????.title("X系統平臺接口文檔")????????????//?API文檔描述
????????????.description("用戶/產品相關API,?更多請關注公眾號:?小白AI?或微信小程序:小白AI博客")????????????//?服務條款URL
????????????.termsOfServiceUrl("https://github.com/yicm")????????????//?API文檔版本
????????????.version("1.0")????????????//?API負責人的聯系信息
????????????.contact(contact)????????????//?API的許可證Url
????????????.licenseUrl("http://license.coscl.org.cn/MulanPSL")
????????????.license("MulanPSL")
????????????.build();
????}
}

分組配置完成后,重新啟動,打開瀏覽器就可以看到效果了:

Spring Boot從零入門6_Swagger2生成生產環

4.3.2 API精細配置

雖然上面我們已經可以控制API的顯示和分組了,但是對于API一些更詳細,對組內API再次歸類之類的,比如小組的描述信息,以及每個API如何去控制它的參數說明,返回值說明等。這些都是通過注解去實現的,接下來我們講述常用的注解及作用:

  1. @Api?: 將這個注解添加到控制器類上,則可以給控制器添加描述類信息:

相關可設置參數有:

  • value: 用作承載資源的API聲明的“路徑”,可以說是API URL的別名

  • tags:如果設置這個值、value的值會被覆蓋

  • description:已過時,對api資源的描述

  • protocols:協議類型如: http, https, ws, wss.

  • hidden:配置為true ,隱藏此資源下的操作(試驗了下,貌似無法生效,替代方案還是用@ApiIgnore吧)

  • produces:如 “application/json, application/xml”

  • consumes: 如 “application/json, application/xml”

  • authorizations:高級特性認證時配置

示例:

//?Swagger配置類@Configuration@EnableSwagger2public?class?Swagger2Config?{@Bean
????public?Docket?productsApis()?{????????return?new?Docket(DocumentationType.SWAGGER_2)
????????		.groupName("產品管理接口")
????????????????.select()
????????????????.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product"))
????????????????.paths(Predicates.or(
????????????????????????PathSelectors.ant("/api/v1/products/**"),
????????????????????????PathSelectors.ant("/api/v1/products/*")))??????????????
????????????????.build()
????????????????.host("https://xiaobaiai.net")????
????????????????.pathProvider(new?RelativePathProvider(null)?{????????????????????@Override
????????????????????public?String?getApplicationBasePath()?{????????????????????????return?"/prefix";
????????????????????}
????????????????})
????????????????.apiInfo(apiInfo())
????????????????.tags(new?Tag("產品操作分組1",?"產品查詢相關操作."),????????????????????????new?Tag("產品操作分組2",?"產品添加或刪除相關操作."),????????????????????????new?Tag("產品操作分組3",?"產品更新相關操作."),????????????????????????new?Tag("產品操作分組4",?"產品相關全部操作."));
????}
}
//?控制器類@RestController@RequestMapping("/api/v1")@Api(tags={"產品接口文檔列表"})public?class?ProductServiceController?{?...?}

效果如下:

Spring Boot從零入門6_Swagger2生成生產環

  1. @ApiIgnore: 作用在REST API控制器方法上,則該API不會被顯示出來:

@ApiIgnore@RequestMapping(value?=?"/users/{id}",?method?=?RequestMethod.DELETE)public?ResponseEntity<object>?delete(@PathVariable("id")?String?id)?{?...?}
  1. @ApiOperation?注解用于控制器方法上面,用于對方法的描述,相關參數設置描述如下:

  • value:接口的名稱

  • notes:接口注意點說明

  • response: 接口的返回類型,比如說:response = String.class

  • hidden: 配置為true 將在文檔中隱藏

示例:

@ApiOperation(value?=?"獲取所有產品",?notes?=?"每調用一次,就耗費流量100M",?response?=?String.class)@GetMapping(value?=?"/products")public?ResponseEntity<object>?getProduct()?{	return?new?ResponseEntity&lt;&gt;(productService.getProducts(),?HttpStatus.OK);
}

最后效果就是:

Spring Boot從零入門6_Swagger2生成生產環

  1. @ApiImplicitParams@ApiImplicitParam?注解用于控制器方法傳入參數的說明。默認情況下,Swagger會根據API方法中的傳入參數進行參數說明的生成,不過參數說明默認就是變量名,因為這兩個注解不一定需要。相關參數設置說明如下:

  • name:參數名稱,注意一定要與實際方法的形參名一致,否則無法生效

  • value:參數值

  • defaultValue:參數默認值

  • required:是否為必需項

  • allowMultiple: 是否允許重復

  • dataType: 數據類型,如object,string,array,int,等

  • paramType:參數傳遞類型

    • header : 放在請求頭。請求參數的獲?。?code >@RequestHeader(代碼中接收注解)

    • query : 用于get請求的參數拼接。請求參數的獲?。?code >@RequestParam(代碼中接收注解)

    • path : 用于restful接口,請求參數的獲?。?code >@PathVariable(代碼中接收注解)

    • body : 放在請求體。請求參數的獲?。?code >@RequestBody(代碼中接收注解)

    • form : 不常用

  • examples: 示例

示例:

//?如果只有一個參數,則僅僅@ApiImplicitParam就可以了@ApiImplicitParams({	@ApiImplicitParam(name="id",?value="產品ID值",?required?=?true),	@ApiImplicitParam(name="product",?value="產品內容",?required?=?true)
})@RequestMapping(value?=?"/products/{id}",?method?=?RequestMethod.PUT)public?ResponseEntity<object>?updateProduct(@PathVariable("id")?String?id,?@RequestBody?Product?product)?{
	productService.updateProduct(id,?product);	return?new?ResponseEntity&lt;&gt;("Product?is?updated?successsfully",?HttpStatus.OK);
}

Spring Boot從零入門6_Swagger2生成生產環

焦作國醫堂胃腸醫院評價怎么樣:http://jz.lieju.com/zhuankeyiyuan/37174965.htm

  1. @ApiParam: 作用同ApiImplicitParam,單個參數描述一般常用該注解,而且該注解只能與JAX-RS 1.x/2.x注解結合使用。參數設置說明如下:

  • name: 參數名稱

  • value: 參數值

  • required: 是否為必須項

  • defaultValue: 默認值

  • type: 參數類型

  • hidden: 是否因此該參數

  1. @ApiResponses、@ApiResponse: 用于控制器方法返回值的說明,參數設置說明如下:

  • code: http的狀態碼

  • message:返回狀態描述

  • response: 狀態響應,默認響應類為Void

示例:

@ApiOperation(value?=?"獲取所有產品",?notes?=?"每調用一次,就耗費流量100M",response?=Product.class,?responseContainer="List")@ApiResponses({????@ApiResponse(code?=?200,?message?=?"成功!",?response=Product.class),????@ApiResponse(code?=?401,?message?=?"未授權!",?response=Product.class),????@ApiResponse(code?=?404,?message?=?"頁面未找到!",?response=Product.class),????@ApiResponse(code?=?403,?message?=?"出錯了!",?response=Product.class)
})@GetMapping(value?=?"/products")public?ResponseEntity<object>?getProduct()?{	return?new?ResponseEntity&lt;&gt;(productService.getProducts(),?HttpStatus.OK);
}

效果如下:

Spring Boot從零入門6_Swagger2生成生產環

  1. @Deprecated: 作用于控制器方法上,標注該方法已經過時,建議開發者采用新的方式之類的。

  2. @ApiModel:作用在JavaBean類上,說明JavaBean的用途,如我們定義的Product.java類。常用參數設置如下:

  • value: 實體類別名,默認為類名字

  • description: 描述

  • parent: 父類,默認為Void.class

  • subTypes: 默認為{}

  • reference: 依賴,默認為""

示例:

@ApiModel(value="Product",description="對產品定義的描述")public?class?Product?{?...?}
  1. @ApiModelProperty: 同樣用于在JavaBean類的屬性上面,說明相關屬性。類似于方法上說明的@ApiImplicitParam。設置參數有:

  • name: 屬性名稱,需與JavaBean內保持一致

  • value: 屬性值

  • notes: 說明

  • dataType: 數據類型

  • required: 是否必須

  • readOnly: 是否只讀,默認為false

  • reference: 依賴,默認為""

  • allowEmptyValue: 是否允許空值

  • allowableValues: 允許值,默認為""

4.4 API歷史版本管理

管理不同API版本有好幾種方式:

  • 通過URL的方式,將版本號包含在URL中,如/api/v1/users。通過這種方式,我們可以在Docket中過濾出不同版本,結合分組,可以實現不同版本的API管理。

  • 通過查詢參數,將版本號作為一個具體參數,如/api/users?version=1

  • 通過自定義HTTP頭–定義一個新的頭,其中包含請求中的版本號

  • 通過內容(Content)協商:版本號與接受的內容類型一起包含在“Accept”頭中,如curl -H "Accept: application/vnd.piomin.v1+json" http://localhost:8080/api/users

這里我們對第一種方式示例展示:

在Swagger2Config.java中新添加一個用戶API Docket:

@Configuration@EnableSwagger2public?class?Swagger2Config?{????@Bean("UsersApis_V1")????public?Docket?usersApisV1()?{????????return?new?Docket(DocumentationType.SWAGGER_2)
????????		.groupName("用戶管理接口V1")
????????????????.select()
????????????????.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))
????????????????.paths(Predicates.or(????????????????????????//?過濾版本v1
????????????????????????PathSelectors.ant("/api/v1/users/**"),
????????????????????????PathSelectors.ant("/api/v1/users/*")))??????
????????????????.build()
????????????????.host("https://xiaobaiai.net")????
????????????????.pathProvider(new?RelativePathProvider(null)?{????????????????????@Override
????????????????????public?String?getApplicationBasePath()?{????????????????????????return?"/prefix";
????????????????????}
????????????????})
????????????????.apiInfo(apiInfo());
????}????
????@Bean("UsersApis_V21")????public?Docket?usersApisV2()?{????????return?new?Docket(DocumentationType.SWAGGER_2)
????????		.groupName("用戶管理接口V2")
????????????????.select()
????????????????.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))
????????????????.paths(Predicates.or(????????????????????????//?過濾版本v1
????????????????????????PathSelectors.ant("/api/v2/users/**"),
????????????????????????PathSelectors.ant("/api/v2/users/*")))??????
????????????????.build()
????????????????.host("https://xiaobaiai.net")????
????????????????.pathProvider(new?RelativePathProvider(null)?{????????????????????@Override
????????????????????public?String?getApplicationBasePath()?{????????????????????????return?"/prefix";
????????????????????}
????????????????})
????????????????.apiInfo(apiInfo());
????}????
????@Bean
????public?Docket?productsApis()?{????????return?new?Docket(DocumentationType.SWAGGER_2)
????????	.....
????}????
????public?ApiInfo?apiInfo()?{????	final?Contact?contact?=?new?Contact(????			"Ethan",?"https://xiaobaiai.net",?"ycm_hy@163.com");????????return?new?ApiInfoBuilder()
????????????.title("X系統平臺接口文檔")
????????????.description("用戶/產品相關API,?更多請關注公眾號:?小白AI?或微信小程序:小白AI博客")
????????????.termsOfServiceUrl("https://github.com/yicm")
????????????.version("1.0")
????????????.contact(contact)
????????????.licenseUrl("http://license.coscl.org.cn/MulanPSL")
????????????.license("MulanPSL")
????????????.build();
????}
}

然后控制器添加新版本API方法:

@RestController@RequestMapping("/api")public?class?UserServiceController?{	@Autowired
	UserService?userService;	
	@DeleteMapping({"/v1/users/{id}",?"/v2/users/{id}"})	public?ResponseEntity<object>?delete(@PathVariable("id")?String?id)?{
		userService.deleteUser(id);		return?new?ResponseEntity&lt;&gt;("User?is?deleted?successsfully",?HttpStatus.OK);
	}	@PutMapping({"/v1/users/{id}",?"/v2/users/{id}"})	public?ResponseEntity<object>?updateUser(@PathVariable("id")?String?id,?@RequestBody?User?user)?{
		userService.updateUser(id,?user);		return?new?ResponseEntity&lt;&gt;("User?is?updated?successsfully",?HttpStatus.OK);
	}	@PostMapping({"/v1/users",?"/v2/users"})	public?ResponseEntity<object>?createUser(@RequestBody?User?user)?{
		userService.createUser(user);		return?new?ResponseEntity&lt;&gt;("User?is?created?successfully",?HttpStatus.CREATED);
	}	@GetMapping({"/v1/users"})	@Deprecated
	public?ResponseEntity<object>?getUser()?{		return?new?ResponseEntity&lt;&gt;(userService.getUsers(),?HttpStatus.OK);
	}	
	@GetMapping(value?=?"/v2/users")	public?ResponseEntity<object>?getUser(@RequestParam?String?id)?{		return?new?ResponseEntity&lt;&gt;(userService.getUsers(),?HttpStatus.OK);
	}
}

最后效果:

Spring Boot從零入門6_Swagger2生成生產環

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女