Spring Boot從零入門6_Swagger2生成生產(chǎn)環(huán)境中REST API文檔

本文屬于原創(chuàng)答倡,轉(zhuǎn)載注明出處莹桅,歡迎關(guān)注微信小程序小白AI博客 微信公眾號(hào)小白AI或者網(wǎng)站 https://xiaobaiai.net

[TOC]

1 前言

在如今前后端分離開發(fā)的模式下,前端調(diào)用后端提供的API去實(shí)現(xiàn)數(shù)據(jù)的展示或者相關(guān)的數(shù)據(jù)操作恰梢,保證及時(shí)更新和完整的REST API文檔將會(huì)大大地提高兩邊的工作效率淤击,減少不必要的溝通成本晃酒。本文采用的Swagger2就是一個(gè)當(dāng)前流行的通過少量的注解就可以生成漂亮的API文檔工具,且在生成的在線文檔中提供類似POSTMAN直接調(diào)試能力隙咸,不僅僅是靜態(tài)的文檔沐悦。接下來將會(huì)利用這個(gè)工具與Spring Boot項(xiàng)目結(jié)合,最終生成我們上一篇文章中所涉及到的REST API文檔五督。

這一篇文章基本將Swagger2在生產(chǎn)環(huán)境中可能會(huì)用到的配置都有涉及藏否,慢慢看吧,看了這一篇因該是夠了充包。

2 Swagger2簡介

Swagger是與用于實(shí)現(xiàn) OpenAPI 文檔廣泛使用的工具副签,Swagger工具集包括開源工具遥椿,免費(fèi)工具和商業(yè)工具的組合,可在API生命周期的不同階段使用淆储。

  • Swagger Editor(開源):使用Swagger編輯器冠场,可以在瀏覽器內(nèi)的YAML文檔中編輯OpenAPI規(guī)范并支持實(shí)時(shí)預(yù)覽文檔,可以參考官方的Demo https://editor.swagger.io/
  • Swagger UI(開源):讓Swagger產(chǎn)生的文檔更漂亮本砰,而且支持API交互操作碴裙,在生成文檔后,直接在瀏覽器中瀏覽点额,并可以實(shí)現(xiàn)類似curl命令或者postman訪問我們的API,并返回相關(guān)數(shù)據(jù)。
  • Swagger Codegen(開源): 是一個(gè)代碼生成器驻龟,可以通過Swagger API定義生成不同語言版本的服務(wù)端和客戶端工程代碼徽千。
  • Swagger Core(開源):用于生成Swagger API規(guī)范的示例和服務(wù)器集成,可輕松訪問REST API珍手,結(jié)合Swagger UI办铡,讓生成的文檔更漂亮。
  • Swagger Parser(開源): Java開發(fā)珠十,解析OpenAPI定義的獨(dú)立庫
  • Swagger Inspector(免費(fèi)):API在線測試工具料扰,驗(yàn)證API并從現(xiàn)有API生成OpenAPI定義功能 https://goo.gl/fZYHWz
  • SwaggerHub(免費(fèi)和商用版):API設(shè)計(jì)和文檔化,為使用OpenAPI的團(tuán)隊(duì)打造焙蹭。

3 開始使用

3.1 構(gòu)建Restful WEB服務(wù)

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

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

3.2 集成Swagger2

構(gòu)建好RESTful WEB服務(wù)后孔厉,接下來我們集成Swagger拯钻,然后對(duì)上節(jié)中的REST API自動(dòng)生成接口文檔。

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有一個(gè)專用對(duì)象Docket,可以靈活的配置Swagger的各種屬性污桦,首先我們簡單的創(chuàng)建一個(gè)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注解用于定義配置類亩歹,被注解的類內(nèi)部包含有一個(gè)或多個(gè)被@Bean注解的方法,這些方法將會(huì)被AnnotationConfigApplicationContext類進(jìn)行掃描凡橱,并用于構(gòu)建Bean定義小作,初始化對(duì)象。@ComponentScan會(huì)自動(dòng)獲取所有的Spring Components稼钩,包括@Configuration類顾稀。另外這里的“用戶管理模塊”API生成配置很簡單,對(duì)所有路徑上API都去生成文檔坝撑。

3.2.3 啟動(dòng)服務(wù)并驗(yàn)證

當(dāng)完成Swagger2的配置類時(shí)静秆,啟動(dòng)WEB服務(wù)粮揉,通過http://localhost:8080/v2/api-docs就可以訪問生成文檔內(nèi)容,但是瀏覽器返回的是JSON內(nèi)容抚笔,基本上很難給需要用到相關(guān)API的開發(fā)人員進(jìn)行參考扶认。這個(gè)時(shí)候就需要用到Swagger2 UI了。

3.3 集成Swagger2 UI

pom.xml添加依賴塔沃,然后重啟WEB服務(wù)就可以了蝠引,再次訪問http://localhost:8080/swagger-ui.html,這時(shí)候看到的就是WEB文檔了蛀柴。

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

從swagger-ui頁面看到的內(nèi)容有一部無關(guān)的內(nèi)容螃概,或者是如何明顯表現(xiàn)跟項(xiàng)目相關(guān)的內(nèi)容呢?下面章節(jié)詳細(xì)講解Swagger的各種配置鸽疾,能夠應(yīng)用到實(shí)際生產(chǎn)環(huán)境中去吊洼。

4 Swagger2 深度配置

4.1 深度配置目標(biāo)

首先,如果要將我們最后生成的API文檔給生產(chǎn)環(huán)境的開發(fā)人員查閱制肮,那么友好的展示信息和歸類是很有必要的冒窍,我們接下來實(shí)現(xiàn)如下目標(biāo):

  • 文檔的各種信息說明
    • 文檔標(biāo)題
    • 文檔描述
    • 文檔版本號(hào)
    • Logo
    • 文檔責(zé)任人
    • 文檔許可證信息
    • 文檔服務(wù)條款
  • API分組
    • 組描述
    • 各API描述
  • 附加部分(非API)
  • 定制化文檔頁面風(fēng)格

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

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

4.2 文檔信息配置

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

通過添加文檔信息編譯對(duì)象ApiInfoBuilder可以配置API文檔的各種信息谬莹,包括標(biāo)題、描述桩了、服務(wù)條款附帽、版本、責(zé)任人井誉、許可證等蕉扮。最后在Docket中添加信息配置對(duì)象即可生效。

4.3 API分組配置颗圣、API精細(xì)配置

4.3.1 API分組展示

上面的文檔信息配置中默認(rèn)是沒有對(duì)API分組的喳钟,即所有的API都展示在了一個(gè)頁面,沒有隔離在岂,如果需要分組荚藻,那我們需要對(duì)不同API組分配Bean,目前示例可以分為用戶API組和產(chǎn)品API組洁段,然后通過apis()paths()進(jìn)行API過濾。

為了不顯示某個(gè)包下面API或某個(gè)URL路徑下API共郭, Docket提供了 apis()paths() 兩 個(gè)方法來幫助我們?cè)诓煌?jí)別上過濾接口(上面示例我們默認(rèn)對(duì)這兩個(gè)設(shè)置是不做任何過濾祠丝,掃描所有API):

  • apis():這種方式可以通過指定包名的方式疾呻,讓 Swagger2 只去某些包下面掃描
  • paths():這種方式可以通過篩選 API 的 URL 來進(jìn)行過濾

apis和paths中的Predicates除了anyant写半、none岸蜗,還支持regex正則表達(dá)式。

如:

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

下面就是分組示例代碼叠蝇,實(shí)現(xiàn)分組璃岳,很簡單,就是在Docket中配置組名就好了:

@Configuration
@EnableSwagger2
public class Swagger2Config {
    @Bean
    public Docket usersApis() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("用戶管理接口")
                // select()返回的是ApiSelectorBuilder對(duì)象悔捶,而非Docket對(duì)象
                .select()
                
                .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))
                .paths(Predicates.or(
                        // 兩個(gè)**铃慷,可以匹配底下所有URL
                        // 一個(gè)*,只能匹配一級(jí)URL分段
                        PathSelectors.ant("/api/v1/users/**"),
                        PathSelectors.ant("/api/v1/users/*")))              
                // build()返回的是Docket對(duì)象
                .build()
                // 測試API時(shí)的主機(jī)URL
                .host("https://xiaobaiai.net")    
                // API前綴蜕该,最終所有API的基礎(chǔ)地址就是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("產(chǎn)品管理接口")
                // select()返回的是ApiSelectorBuilder對(duì)象犁柜,而非Docket對(duì)象
                .select()
                
                .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product"))
                .paths(Predicates.or(
                        // 兩個(gè)**,可以匹配底下所有URL
                        // 一個(gè)*堂淡,只能匹配一級(jí)URL分段
                        PathSelectors.ant("/api/v1/products/**"),
                        PathSelectors.ant("/api/v1/products/*")))              
                // build()返回的是Docket對(duì)象
                .build()
                // 測試API時(shí)的主機(jī)URL
                .host("https://xiaobaiai.net")    
                // API前綴
                .pathProvider(new RelativePathProvider(null) {
                    @Override
                    public String getApplicationBasePath() {
                        return "/prefix";
                    }
                })
                .apiInfo(apiInfo());
    }
    
    public ApiInfo apiInfo() {
        // API負(fù)責(zé)人的聯(lián)系信息
        final Contact contact = new Contact(
                "Ethan", "https://xiaobaiai.net", "ycm_hy@163.com");
        return new ApiInfoBuilder()
            // API文檔標(biāo)題
            .title("X系統(tǒng)平臺(tái)接口文檔")
            // API文檔描述
            .description("用戶/產(chǎn)品相關(guān)API, 更多請(qǐng)關(guān)注公眾號(hào): 小白AI 或微信小程序:小白AI博客")
            // 服務(wù)條款URL
            .termsOfServiceUrl("https://github.com/yicm")
            // API文檔版本
            .version("1.0")
            // API負(fù)責(zé)人的聯(lián)系信息
            .contact(contact)
            // API的許可證Url
            .licenseUrl("http://license.coscl.org.cn/MulanPSL")
            .license("MulanPSL")
            .build();
    }
}

分組配置完成后馋缅,重新啟動(dòng),打開瀏覽器就可以看到效果了:

4.3.2 API精細(xì)配置

雖然上面我們已經(jīng)可以控制API的顯示和分組了绢淀,但是對(duì)于API一些更詳細(xì)萤悴,對(duì)組內(nèi)API再次歸類之類的,比如小組的描述信息皆的,以及每個(gè)API如何去控制它的參數(shù)說明覆履,返回值說明等。這些都是通過注解去實(shí)現(xiàn)的祭务,接下來我們講述常用的注解及作用:

  1. @Api : 將這個(gè)注解添加到控制器類上内狗,則可以給控制器添加描述類信息:

相關(guān)可設(shè)置參數(shù)有:

  • value: 用作承載資源的API聲明的“路徑”,可以說是API URL的別名
  • tags:如果設(shè)置這個(gè)值义锥、value的值會(huì)被覆蓋
  • description:已過時(shí)柳沙,對(duì)api資源的描述
  • protocols:協(xié)議類型如: http, https, ws, wss.
  • hidden:配置為true ,隱藏此資源下的操作(試驗(yàn)了下拌倍,貌似無法生效赂鲤,替代方案還是用@ApiIgnore吧)
  • produces:如 “application/json, application/xml”
  • consumes: 如 “application/json, application/xml”
  • authorizations:高級(jí)特性認(rèn)證時(shí)配置

示例:

// Swagger配置類
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
    public Docket productsApis() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("產(chǎn)品管理接口")
                .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("產(chǎn)品操作分組1", "產(chǎn)品查詢相關(guān)操作."),
                        new Tag("產(chǎn)品操作分組2", "產(chǎn)品添加或刪除相關(guān)操作."),
                        new Tag("產(chǎn)品操作分組3", "產(chǎn)品更新相關(guān)操作."),
                        new Tag("產(chǎn)品操作分組4", "產(chǎn)品相關(guān)全部操作."));
    }
}
// 控制器類
@RestController
@RequestMapping("/api/v1")
@Api(tags={"產(chǎn)品接口文檔列表"})
public class ProductServiceController { ... }

效果如下:

  1. @ApiIgnore: 作用在REST API控制器方法上,則該API不會(huì)被顯示出來:
@ApiIgnore
@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Object> delete(@PathVariable("id") String id) { ... }
  1. @ApiOperation 注解用于控制器方法上面柱恤,用于對(duì)方法的描述数初,相關(guān)參數(shù)設(shè)置描述如下:
  • value:接口的名稱
  • notes:接口注意點(diǎn)說明
  • response: 接口的返回類型,比如說:response = String.class
  • hidden: 配置為true 將在文檔中隱藏

示例:

@ApiOperation(value = "獲取所有產(chǎn)品", notes = "每調(diào)用一次梗顺,就耗費(fèi)流量100M", response = String.class)
@GetMapping(value = "/products")
public ResponseEntity<Object> getProduct() {
    return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK);
}

最后效果就是:

  1. @ApiImplicitParams@ApiImplicitParam 注解用于控制器方法傳入?yún)?shù)的說明泡孩。默認(rèn)情況下,Swagger會(huì)根據(jù)API方法中的傳入?yún)?shù)進(jìn)行參數(shù)說明的生成寺谤,不過參數(shù)說明默認(rèn)就是變量名仑鸥,因?yàn)檫@兩個(gè)注解不一定需要吮播。相關(guān)參數(shù)設(shè)置說明如下:
  • name:參數(shù)名稱,注意一定要與實(shí)際方法的形參名一致眼俊,否則無法生效
  • value:參數(shù)值
  • defaultValue:參數(shù)默認(rèn)值
  • required:是否為必需項(xiàng)
  • allowMultiple: 是否允許重復(fù)
  • dataType: 數(shù)據(jù)類型意狠,如object,string,array,int,等
  • paramType:參數(shù)傳遞類型
    • header : 放在請(qǐng)求頭。請(qǐng)求參數(shù)的獲却帧:@RequestHeader(代碼中接收注解)
    • query : 用于get請(qǐng)求的參數(shù)拼接环戈。請(qǐng)求參數(shù)的獲取:@RequestParam(代碼中接收注解)
    • path : 用于restful接口澎灸,請(qǐng)求參數(shù)的獲仍喝:@PathVariable(代碼中接收注解)
    • body : 放在請(qǐng)求體。請(qǐng)求參數(shù)的獲然骱ⅰ:@RequestBody(代碼中接收注解)
    • form : 不常用
  • examples: 示例

示例:

// 如果只有一個(gè)參數(shù)迫悠,則僅僅@ApiImplicitParam就可以了
@ApiImplicitParams({
    @ApiImplicitParam(name="id", value="產(chǎn)品ID值", required = true),
    @ApiImplicitParam(name="product", value="產(chǎn)品內(nèi)容", 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<>("Product is updated successsfully", HttpStatus.OK);
}
  1. @ApiParam: 作用同ApiImplicitParam,單個(gè)參數(shù)描述一般常用該注解巩梢,而且該注解只能與JAX-RS 1.x/2.x注解結(jié)合使用创泄。參數(shù)設(shè)置說明如下:
  • name: 參數(shù)名稱
  • value: 參數(shù)值
  • required: 是否為必須項(xiàng)
  • defaultValue: 默認(rèn)值
  • type: 參數(shù)類型
  • hidden: 是否因此該參數(shù)
  1. @ApiResponses@ApiResponse: 用于控制器方法返回值的說明括蝠,參數(shù)設(shè)置說明如下:
  • code: http的狀態(tài)碼
  • message:返回狀態(tài)描述
  • response: 狀態(tài)響應(yīng)鞠抑,默認(rèn)響應(yīng)類為Void

示例:

@ApiOperation(value = "獲取所有產(chǎn)品", notes = "每調(diào)用一次,就耗費(fèi)流量100M",response =Product.class, responseContainer="List")
@ApiResponses({
    @ApiResponse(code = 200, message = "成功忌警!", response=Product.class),
    @ApiResponse(code = 401, message = "未授權(quán)搁拙!", response=Product.class),
    @ApiResponse(code = 404, message = "頁面未找到!", response=Product.class),
    @ApiResponse(code = 403, message = "出錯(cuò)了法绵!", response=Product.class)
})
@GetMapping(value = "/products")
public ResponseEntity<Object> getProduct() {
    return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK);
}

效果如下:

  1. @Deprecated: 作用于控制器方法上箕速,標(biāo)注該方法已經(jīng)過時(shí),建議開發(fā)者采用新的方式之類的朋譬。

  2. @ApiModel:作用在JavaBean類上盐茎,說明JavaBean的用途,如我們定義的Product.java類徙赢。常用參數(shù)設(shè)置如下:

  • value: 實(shí)體類別名字柠,默認(rèn)為類名字
  • description: 描述
  • parent: 父類,默認(rèn)為Void.class
  • subTypes: 默認(rèn)為{}
  • reference: 依賴狡赐,默認(rèn)為""

示例:

@ApiModel(value="Product",description="對(duì)產(chǎn)品定義的描述")
public class Product { ... }
  1. @ApiModelProperty: 同樣用于在JavaBean類的屬性上面窑业,說明相關(guān)屬性。類似于方法上說明的@ApiImplicitParam枕屉。設(shè)置參數(shù)有:
  • name: 屬性名稱常柄,需與JavaBean內(nèi)保持一致
  • value: 屬性值
  • notes: 說明
  • dataType: 數(shù)據(jù)類型
  • required: 是否必須
  • readOnly: 是否只讀,默認(rèn)為false
  • reference: 依賴,默認(rèn)為""
  • allowEmptyValue: 是否允許空值
  • allowableValues: 允許值西潘,默認(rèn)為""

4.4 API歷史版本管理

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

  • 通過URL的方式铜异,將版本號(hào)包含在URL中,如/api/v1/users秸架。通過這種方式,我們可以在Docket中過濾出不同版本咆蒿,結(jié)合分組东抹,可以實(shí)現(xiàn)不同版本的API管理。
  • 通過查詢參數(shù)沃测,將版本號(hào)作為一個(gè)具體參數(shù)缭黔,如/api/users?version=1
  • 通過自定義HTTP頭–定義一個(gè)新的頭,其中包含請(qǐng)求中的版本號(hào)
  • 通過內(nèi)容(Content)協(xié)商:版本號(hào)與接受的內(nèi)容類型一起包含在“Accept”頭中蒂破,如curl -H "Accept: application/vnd.piomin.v1+json" http://localhost:8080/api/users

這里我們對(duì)第一種方式示例展示:

在Swagger2Config.java中新添加一個(gè)用戶API Docket:

@Configuration
@EnableSwagger2
public 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系統(tǒng)平臺(tái)接口文檔")
            .description("用戶/產(chǎn)品相關(guān)API, 更多請(qǐng)關(guān)注公眾號(hào): 小白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<>("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<>("User is updated successsfully", HttpStatus.OK);
    }

    @PostMapping({"/v1/users", "/v2/users"})
    public ResponseEntity<Object> createUser(@RequestBody User user) {
        userService.createUser(user);
        return new ResponseEntity<>("User is created successfully", HttpStatus.CREATED);
    }

    @GetMapping({"/v1/users"})
    @Deprecated
    public ResponseEntity<Object> getUser() {
        return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK);
    }
    
    @GetMapping(value = "/v2/users")
    public ResponseEntity<Object> getUser(@RequestParam String id) {
        return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK);
    }
}

最后效果:

其他的方式類似也差不多馏谨,如在Header中區(qū)分版本,這里就不展開了附迷。

4.5 其他配置

4.5.1 為每個(gè)API配置全局Token實(shí)現(xiàn)一次性授權(quán)

當(dāng)我們的REST API加入的授權(quán)機(jī)制時(shí)惧互,即需具有對(duì)該API的訪問權(quán)限,才能夠操作該API喇伯,但是我們想在Swagger UI中去調(diào)試API喊儡,那么如何解決每個(gè)API一次性授權(quán),全部API可訪問呢稻据?增加使用的方便性艾猜,不用每次都對(duì)每個(gè)API進(jìn)行授權(quán)。不過需要在WEB服務(wù)中已經(jīng)使用了API授權(quán)機(jī)制才會(huì)需要這項(xiàng)配置捻悯。這里暫不展開匆赃,后面單獨(dú)講述Spring Security + Swagger2 UI配置。

4.5.2 在線文檔頁面中更換語言

應(yīng)該是不能的: https://github.com/swagger-api/swagger-ui#known-issues

  • translations is not implemented.

5 總結(jié)

這一篇從介紹Swagger2入手今缚,講述在Spring Boot中如何集成和配置Swagger2算柳,并生成生成環(huán)境中的在線API文檔,包括如何將API分組荚斯,組信息描述埠居,API信息描述,API方法參數(shù)描述事期,如果對(duì)API版本進(jìn)行管理等滥壕,最后還擴(kuò)展了內(nèi)容,包括如何為每個(gè)API配置全局Token等兽泣。內(nèi)容很全绎橘,參考這一篇應(yīng)該是夠了,繼續(xù)!

6 參考文檔

本文屬于原創(chuàng)称鳞,轉(zhuǎn)載注明出處涮较,歡迎關(guān)注CSDNfreeape或微信小程序小白AI博客 微信公眾號(hào)小白AI或者網(wǎng)站 https://xiaobaiai.net

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冈止,隨后出現(xiàn)的幾起案子狂票,更是在濱河造成了極大的恐慌,老刑警劉巖熙暴,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闺属,死亡現(xiàn)場離奇詭異,居然都是意外死亡周霉,警方通過查閱死者的電腦和手機(jī)掂器,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俱箱,“玉大人国瓮,你說我怎么就攤上這事∧祝” “怎么了乃摹?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芋簿。 經(jīng)常有香客問我峡懈,道長,這世上最難降的妖魔是什么与斤? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任肪康,我火速辦了婚禮,結(jié)果婚禮上撩穿,老公的妹妹穿的比我還像新娘磷支。我一直安慰自己,他們只是感情好食寡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布雾狈。 她就那樣靜靜地躺著,像睡著了一般抵皱。 火紅的嫁衣襯著肌膚如雪善榛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天呻畸,我揣著相機(jī)與錄音移盆,去河邊找鬼。 笑死伤为,一個(gè)胖子當(dāng)著我的面吹牛咒循,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼叙甸,長吁一口氣:“原來是場噩夢啊……” “哼颖医!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起裆蒸,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤熔萧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后僚祷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哪痰,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年久妆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跷睦。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筷弦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抑诸,到底是詐尸還是另有隱情烂琴,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布蜕乡,位于F島的核電站奸绷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏层玲。R本人自食惡果不足惜号醉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辛块。 院中可真熱鬧畔派,春花似錦、人聲如沸润绵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尘盼。三九已至憨愉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卿捎,已是汗流浹背配紫。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娇澎,地道東北人笨蚁。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親括细。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伪很,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容