您的位置:首頁 > 軟件教程 > 教程 > SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

來源:好特整理 | 時(shí)間:2024-08-13 09:57:12 | 閱讀:131 |  標(biāo)簽: a T Pi API Ri S in 開發(fā)   | 分享到:

接口服務(wù)主要由兩部分組成,即參數(shù)(輸入)部分,響應(yīng)(輸出)部分。其中在SpringBoot中主要是Controller層作為API的開發(fā)處,其實(shí)在架構(gòu)層面來講,Controller本身是一個(gè)最高的應(yīng)用層,它的職責(zé)是調(diào)用、組裝下層的interface服務(wù)數(shù)據(jù),核心是組裝和調(diào)用,不應(yīng)該摻雜其他相關(guān)的邏輯

寫在前面

博主最近在做一個(gè)數(shù)據(jù)服務(wù)的項(xiàng)目,而這個(gè)數(shù)據(jù)服務(wù)的核心就是對(duì)外暴露的API,值得高興的這是一個(gè)從0開始的項(xiàng)目,所以終于不用受制于“某些歷史”因素去續(xù)寫各種風(fēng)格的Controller,可以在項(xiàng)目伊始就以規(guī)范的技術(shù)和統(tǒng)一形式去搭建API。借此機(jī)會(huì),梳理和匯總一下基于SpringBoot項(xiàng)目開發(fā)REST API的技術(shù)點(diǎn)和規(guī)范點(diǎn)。

接口服務(wù)主要由兩部分組成,即參數(shù)(輸入)部分,響應(yīng)(輸出)部分。其中在SpringBoot中主要是Controller層作為API的開發(fā)處,其實(shí)在架構(gòu)層面來講, Controller 本身是一個(gè)最高的應(yīng)用層,它的職責(zé)是調(diào)用、組裝下層的interface服務(wù)數(shù)據(jù),核心是組裝和調(diào)用,不應(yīng)該摻雜其他相關(guān)的邏輯。

但是往往很多項(xiàng)目里針對(duì)Controller部分的代碼都是十分混亂,有的 Controller 兼顧各種if else的參數(shù)校驗(yàn),有的甚至直接在Controller進(jìn)行業(yè)務(wù)代碼編寫;對(duì)于 Controller 的輸出,有的粗略的加個(gè)外包裝,有的甚至直接把service層的結(jié)構(gòu)直接丟出去;對(duì)于異常的處理也是各種各樣。

以上對(duì)于 Controller 相關(guān)的問題,這里統(tǒng)一用一系列 Controller 的封裝處理來提供優(yōu)化思路。優(yōu)雅且規(guī)范的開發(fā)REST API需要做以下幾步:

  • 接口版本控制
  • 參數(shù)校驗(yàn)
  • 異常捕獲處理
  • 統(tǒng)一響應(yīng)封裝
  • 接口文檔的維護(hù)和更新

@RestController注解

直接來看@RestController源碼

@RestController注解等價(jià)于@Controller和@@ResponseBody,@ResponseBody注解的作用是告訴Spring MVC框架,該方法的返回值應(yīng)該直接寫入HTTP響應(yīng)體中,而不是返回一個(gè)視圖(View)。當(dāng)一個(gè)控制器方法被標(biāo)記為 @ResponseBody 時(shí),Spring MVC會(huì)將方法的返回值序列化成JSON或XML等格式,然后發(fā)送給客戶端。更適用于REST API的構(gòu)建。

所以針對(duì)Controller接口的開發(fā), 直接使用@RestController為好。它會(huì)自動(dòng)將Controller下的方法返回內(nèi)容轉(zhuǎn)為REST API的形式 。

例如:

接口版本管理

對(duì)于API來講,一般是對(duì)外服務(wù)的基礎(chǔ),不能隨意變更,但是隨著需求和業(yè)務(wù)不斷變化,接口和參數(shù)也會(huì)發(fā)生相應(yīng)的變化。此時(shí)盡可能保證“開閉原則”,以新增接口或增強(qiáng)接口功能來支撐,此時(shí)就需要對(duì)API的版本進(jìn)行維護(hù),以版本號(hào)來確定同一接口的不同能力,一般版本都基于url來控制

例如:

進(jìn)行API版本控制主要分三步:

  • 定義版本號(hào)注解
  • 編寫版本號(hào)匹配邏輯處理器
  • 注冊(cè)處理器

定義版本號(hào)注解

該注解可直接使用在Controller類上

編寫版本號(hào)匹配邏輯處理器

首先定義一個(gè)條件匹配類,對(duì)應(yīng)解析Url中的version與ApiVersion注解

這里補(bǔ)充一下 RequestCondition 相關(guān)概念:

它是 Spring 框架中用于請(qǐng)求映射處理的一部分。在 Spring MVC 中, RequestCondition 接口允許開發(fā)者定義自定義的請(qǐng)求匹配邏輯,這可以基于請(qǐng)求的任何屬性,例如路徑、參數(shù)、HTTP 方法、頭部等。相關(guān)的應(yīng)用場景包括:

  1. 路徑匹配(Path Matching) :使用 PatternsRequestCondition 來定義請(qǐng)求的路徑模式,支持 Ant 風(fēng)格的路徑模式匹配,如 /api/* 可以匹配所有 /api 開頭的請(qǐng)求路徑 。

  2. 請(qǐng)求方法匹配(Request Method Matching) :通過 RequestMethodsRequestCondition 來限制請(qǐng)求的 HTTP 方法,例如只允許 GET 或 POST 請(qǐng)求 。

  3. 請(qǐng)求參數(shù)匹配(Request Params Matching) :使用 ParamsRequestCondition 來定義請(qǐng)求必須包含的參數(shù),例如某些接口可能需要特定的查詢參數(shù)才能訪問 。

  4. 請(qǐng)求頭匹配(Request Headers Matching) HeadersRequestCondition 允許定義請(qǐng)求頭的條件,例如某些接口可能需要特定的認(rèn)證頭部才能訪問 。

  5. 消費(fèi)媒體類型匹配(Consumes Media Type Matching) ConsumesRequestCondition 用來定義控制器方法能夠處理的請(qǐng)求體媒體類型,通常用于 RESTful API 中,例如只處理 application/json 類型的請(qǐng)求體 。

  6. 產(chǎn)生媒體類型匹配(Produces Media Type Matching) ProducesRequestCondition 定義了控制器方法能夠返回的媒體類型,這通常與 Accept 請(qǐng)求頭結(jié)合使用以確定響應(yīng)的格式 。

  7. 自定義條件匹配 :開發(fā)者可以通過實(shí)現(xiàn) RequestCondition 接口來定義自己的匹配邏輯,例如根據(jù)請(qǐng)求中的版本號(hào)來路由到不同版本的 API,實(shí)現(xiàn) API 的版本控制 。

  8. 組合條件匹配(Composite Conditions Matching) :在某些情況下,可能需要根據(jù)多個(gè)條件來匹配請(qǐng)求, CompositeRequestCondition 可以將多個(gè) RequestCondition 組合成一個(gè)條件來進(jìn)行匹配 。

  9. 請(qǐng)求映射的優(yōu)先級(jí)選擇(Priority Selection for Request Mapping) :當(dāng)存在多個(gè)匹配的處理器方法時(shí), RequestCondition compareTo 方法用于確定哪個(gè)條件具有更高的優(yōu)先級(jí),以選擇最合適的處理器方法 。

創(chuàng)建一個(gè)版本映射處理器,使用 ApiVersionCondition 作為自定義條件來處理請(qǐng)求映射。當(dāng) Spring MVC 處理請(qǐng)求時(shí),它會(huì)使用這個(gè)自定義的映射處理器來確定哪個(gè)版本的 API 應(yīng)該處理請(qǐng)求。

注冊(cè)處理器

將上述的處理器注冊(cè)到SpringMvc的處理流程中

驗(yàn)證:

針對(duì)test接口進(jìn)行不同版本的請(qǐng)求:

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

針對(duì)Account擴(kuò)展版本調(diào)用上一版本接口

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

當(dāng)請(qǐng)求對(duì)應(yīng)的版本不存在接口時(shí),會(huì)匹配之前版本的接口,即請(qǐng)求 /v2/account/extend 接口時(shí),由于v2 控制器未實(shí)現(xiàn)該接口,所以自動(dòng)匹配v1 版本中的接口。這就實(shí)現(xiàn)了 API版本繼承 。

參數(shù)校驗(yàn)

@Validated注解

@Validated 是一個(gè)用于 Java 應(yīng)用程序中的注解,特別是在 Spring 框架中,以指示目標(biāo)對(duì)象或方法需要進(jìn)行驗(yàn)證。這個(gè)注解通常與 JSR 303/JSR 380 規(guī)范的 Bean Validation API 結(jié)合使用,以確保數(shù)據(jù)的合法性和完整性。

@Validated注解的三種用法:

方法級(jí)別驗(yàn)證 :當(dāng) @Validated 注解用在方法上時(shí),它指示 Spring 在調(diào)用該方法之前執(zhí)行參數(shù)的驗(yàn)證。如果參數(shù)不符合指定的驗(yàn)證條件,將拋出 MethodArgumentNotValidException 。

類級(jí)別驗(yàn)證 :將 @Validated 注解用在類上,表示該類的所有處理請(qǐng)求的方法都會(huì)進(jìn)行驗(yàn)證。這可以減少在每個(gè)方法上重復(fù)注解的需要。

組合注解 :Spring 還提供了 @Valid 注解,它是 @Validated 的一個(gè)更簡單的形式,只觸發(fā)驗(yàn)證并不指定特定的驗(yàn)證組(Validation Groups)。 @Validated 允許你指定一個(gè)或多個(gè)驗(yàn)證組,這在需要根據(jù)不同情況執(zhí)行不同驗(yàn)證規(guī)則時(shí)非常有用。

使用注解進(jìn)行參數(shù)校驗(yàn)

在REST API中進(jìn)行參數(shù)驗(yàn)證一般使用方法級(jí)別驗(yàn)證即可,即對(duì)參數(shù)Dto的類內(nèi)信息進(jìn)行驗(yàn)證,例如一個(gè)分頁的查詢參數(shù)類:

在Controller中配合@Validated使用:

此時(shí)如果前端傳入?yún)?shù)不合法,例如pageNo為0又或者productType不存在,則會(huì)拋出 MethodArgumentNotValidException 的異常。稍后對(duì)于異常進(jìn)行處理即可完成參數(shù)的驗(yàn)證。

這里的@Max 、 @Min @NotNull 注解屬于 Bean Validation API 的一部分,這是一個(gè) JSR 303/JSR 380 規(guī)范,用于在 Java 應(yīng)用程序中提供聲明式驗(yàn)證功能。這些注解用于約束字段值的范圍和非空性。類似的注解還有:

注解 作用

@NotNull

驗(yàn)證注解的字段值不能為 null
@NotEmpty @NotNull 類似,但用于集合或字符串,驗(yàn)證注解的字段值不能為 null ,且對(duì)于字符串,長度不能為 0。
@NotBlank 驗(yàn)證注解的字段值不能為 null ,且不能是空白字符串(空白包括空格、制表符等)。
@Min(value) 驗(yàn)證注解的字段值是否大于或等于指定的最小值。 value 參數(shù)接受一個(gè)整數(shù)。
@Max(value) 驗(yàn)證注解的字段值是否小于或等于指定的最大值。 value 參數(shù)接受一個(gè)整數(shù)。
@Size(min, max) 驗(yàn)證字符串或集合的大小在指定的最小值和最大值之間。
@Pattern(regex) 驗(yàn)證字段值是否符合指定的正則表達(dá)式。

注:SpringBoot 2.3.1 版本默認(rèn)移除了校驗(yàn)功能,如果想要開啟的話需要添加以上依賴

統(tǒng)一異常捕獲

@RestControllerAdvice注解

@RestControllerAdvice 是 @ResponseBody+@ControllerAdvice的集合注解,用于定義一個(gè)控制器級(jí)別的異常處理類。一般用來進(jìn)行全局異常處理,在 @RestControllerAdvice 類中處理異常后,可以直接返回一個(gè)對(duì)象,該對(duì)象會(huì)被轉(zhuǎn)換為 JSON 或 XML 響應(yīng)體,返回給客戶端。

使用@RestControllerAdvice注解處理參數(shù)異常

使用@Validated和 Bean Validation API 的注解進(jìn)行參數(shù)校驗(yàn)后,當(dāng)出現(xiàn)不符合規(guī)定的參數(shù)會(huì)拋出 MethodArgumentNotValidException 異常 ,這里就可以使用@RestControllerAdvice注解來創(chuàng)建一個(gè)全局Controller異常攔截類,來統(tǒng)一處理各類異常

這里只以 MethodArgumentNotValidException 異常進(jìn)行攔截,在 @RestControllerAdvice類內(nèi)可以創(chuàng)建多個(gè)方法,通過@ExceptionHandler對(duì)不同的異常進(jìn)行定制化處理,這樣當(dāng)Controller內(nèi)發(fā)生異常,都可以在@RestControllerAdvice類內(nèi)進(jìn)行截獲、處理、返回給客戶端安全的信息。

統(tǒng)一響應(yīng)封裝

首先,進(jìn)行統(tǒng)一的響應(yīng)格式,這里需要封裝一個(gè)固定返回格式的結(jié)構(gòu)對(duì)象: ResponseData

統(tǒng)一狀態(tài)碼

其中對(duì)于相關(guān)的狀態(tài)碼最好進(jìn)行統(tǒng)一的封裝,便于以后的開發(fā),創(chuàng)建狀態(tài)枚舉:

統(tǒng)一返回結(jié)構(gòu)

將上述的 ResponseData 中狀態(tài)類相關(guān)替換為枚舉

這樣Controller的接口統(tǒng)一返回格式就是標(biāo)準(zhǔn)的結(jié)構(gòu)了。

統(tǒng)一封裝Controller響應(yīng)

有了統(tǒng)一響應(yīng)體的Controller在返回時(shí)可以這樣寫:

即便如此,團(tuán)隊(duì)開發(fā)中可能還會(huì)出現(xiàn)換個(gè)人新寫Controller不知道有統(tǒng)一返回體這回事,為了更保險(xiǎn),可以通過AOP進(jìn)行統(tǒng)一對(duì)結(jié)果進(jìn)行封裝,不論Controller返回啥,到客戶端的數(shù)據(jù)都包含一個(gè)包裝體。

具體實(shí)現(xiàn)是使用 @RestControllerAdvice類 實(shí)現(xiàn) ResponseBodyAdvice 接口來完成。

我們以test接口為例,test接口原本返回的是String,而toint返回的是Integer

但是頁面返回是JSON字符串和返回體:

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

文檔:調(diào)試維護(hù)API利器—Swagger

接口開發(fā)完成,調(diào)試時(shí),大多數(shù)都是使用Postman模擬請(qǐng)求調(diào)試或者直接用前端代碼調(diào)用調(diào)試,其實(shí)這兩種都比較麻煩,尤其面對(duì)復(fù)制參數(shù)時(shí),Postman要逐個(gè)接口的錄入,十分費(fèi)事,其實(shí)這里可以在SpringBoot中引入Swagger接口文檔組件,接口文檔和接口調(diào)試一并解決。

引入依賴

直接在maven中引入相關(guān)依賴:

標(biāo)準(zhǔn)的swagger3引入以上兩個(gè)依賴即可,相關(guān)版本可自行選擇

裝配配置類

下面進(jìn)行swagger的配置類和一些swagger相關(guān)頁面的配置

使用注解

Swagger相關(guān)注解明細(xì)

注解 使用位置 作用
@Api 作用在類上, Controller 表示對(duì)類的說明,通常用于描述 Controller 的作用和分類,如 @Api(tags = "用戶管理"),后續(xù)會(huì)在Swagger文檔中以 目錄形式 展示
@ApiOperation 作用在方法上,一般為 Controller中具體方法 描述 API 接口的具體操作和功能,例如 @ApiOperation(value = "獲取用戶列表", notes = "根據(jù)條件獲取用戶列表") ,在swagger文檔中以目錄內(nèi)容體現(xiàn)
@ApiModel 作用于類上,一般是 參數(shù)實(shí)體類 表示這是一個(gè)模型類,通常與 @ApiModelProperty 結(jié)合使用來描述模型屬性 。
@ApiModelProperty 用于模型類的屬性上, 參數(shù)類的成員變量 描述屬性的信息,如 @ApiModelProperty(value = "用戶名", required = true)
@ApiImplicitParams @ApiImplicitParam 用于方法上,一般為 Controller中具體方法 描述接口的隱含參數(shù),例如請(qǐng)求參數(shù)或請(qǐng)求頭信息
@ApiResponses @ApiResponse 用于方法上,一般為 Controller中具體方法 描述接口的響應(yīng)信息,可以指定不同的響應(yīng)狀態(tài)碼和對(duì)應(yīng)的描述信息 。
@ApiIgnore 用于類或方法上 表示忽略該類或方法,不將其顯示在Swagger文檔中。

@Api @ApiOperation 使用

@ApiMode @ApiModelProperty

@ApiImplicitParams @ApiImplicitParam

與ApiMode和ApiModeProperty功能一致,一般用于get請(qǐng)求中的參數(shù)描述

效果

使用swagger后,直接在頁面訪問 http://127.0.0.1:8080/XXX/doc.html即可訪問接口頁面

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

不要復(fù)雜的postman調(diào)用,本地調(diào)試可以直接使用調(diào)試功能

SpringBoot優(yōu)雅開發(fā)REST API最佳實(shí)踐

補(bǔ)充:完整的Controller類代碼模板

補(bǔ)充:完整的@RestControllerAdvice類代碼模板

關(guān)于參數(shù)驗(yàn)證的異常處理和統(tǒng)一返回結(jié)構(gòu),可以使用一個(gè)類來完成,以下是完整模板:

小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認(rèn)同期限觀點(diǎn)或證實(shí)其描述。

a 1.0
a 1.0
類型:休閑益智  運(yùn)營狀態(tài):正式運(yùn)營  語言:中文   

游戲攻略

游戲禮包

游戲視頻

游戲下載

游戲活動(dòng)

《alittletotheleft》官網(wǎng)正版是一款備受歡迎的休閑益智整理游戲。玩家的任務(wù)是對(duì)日常生活中的各種雜亂物
RPG Ri序章 0.2.1
RPG Ri序章 0.2.1
類型:角色扮演  運(yùn)營狀態(tài):正式運(yùn)營  語言: 日文  

游戲攻略

游戲禮包

游戲視頻

游戲下載

游戲活動(dòng)

《RPG_Ri序章》是GameMaker'Child-Dream'制作的一款幻想廢土風(fēng)RPG手游,完全免費(fèi)的幻想廢土風(fēng)RPG登場!元

相關(guān)視頻攻略

更多

掃二維碼進(jìn)入好特網(wǎng)手機(jī)版本!

掃二維碼進(jìn)入好特網(wǎng)微信公眾號(hào)!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]

湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2024 haote.com 好特網(wǎng)