接口服務主要由兩部分組成,即參數(shù)(輸入)部分,響應(輸出)部分。其中在SpringBoot中主要是Controller層作為API的開發(fā)處,其實在架構(gòu)層面來講,Controller本身是一個最高的應用層,它的職責是調(diào)用、組裝下層的interface服務數(shù)據(jù),核心是組裝和調(diào)用,不應該摻雜其他相關(guān)的邏輯
博主最近在做一個數(shù)據(jù)服務的項目,而這個數(shù)據(jù)服務的核心就是對外暴露的API,值得高興的這是一個從0開始的項目,所以終于不用受制于“某些歷史”因素去續(xù)寫各種風格的Controller,可以在項目伊始就以規(guī)范的技術(shù)和統(tǒng)一形式去搭建API。借此機會,梳理和匯總一下基于SpringBoot項目開發(fā)REST API的技術(shù)點和規(guī)范點。
接口服務主要由兩部分組成,即參數(shù)(輸入)部分,響應(輸出)部分。其中在SpringBoot中主要是Controller層作為API的開發(fā)處,其實在架構(gòu)層面來講, Controller 本身是一個最高的應用層,它的職責是調(diào)用、組裝下層的interface服務數(shù)據(jù),核心是組裝和調(diào)用,不應該摻雜其他相關(guān)的邏輯。
但是往往很多項目里針對Controller部分的代碼都是十分混亂,有的 Controller 兼顧各種if else的參數(shù)校驗,有的甚至直接在Controller進行業(yè)務代碼編寫;對于 Controller 的輸出,有的粗略的加個外包裝,有的甚至直接把service層的結(jié)構(gòu)直接丟出去;對于異常的處理也是各種各樣。
以上對于 Controller 相關(guān)的問題,這里統(tǒng)一用一系列 Controller 的封裝處理來提供優(yōu)化思路。優(yōu)雅且規(guī)范的開發(fā)REST API需要做以下幾步:
直接來看@RestController源碼
@RestController注解等價于@Controller和@@ResponseBody,@ResponseBody注解的作用是告訴Spring MVC框架,該方法的返回值應該直接寫入HTTP響應體中,而不是返回一個視圖(View)。當一個控制器方法被標記為
@ResponseBody
時,Spring MVC會將方法的返回值序列化成JSON或XML等格式,然后發(fā)送給客戶端。更適用于REST API的構(gòu)建。
所以針對Controller接口的開發(fā), 直接使用@RestController為好。它會自動將Controller下的方法返回內(nèi)容轉(zhuǎn)為REST API的形式 。
例如:
對于API來講,一般是對外服務的基礎(chǔ),不能隨意變更,但是隨著需求和業(yè)務不斷變化,接口和參數(shù)也會發(fā)生相應的變化。此時盡可能保證“開閉原則”,以新增接口或增強接口功能來支撐,此時就需要對API的版本進行維護,以版本號來確定同一接口的不同能力,一般版本都基于url來控制
例如:
http://localhost:8080/dataserver/v1/queryAccount
http://localhost:8080/dataserver/v2/queryAccount:相比v1版本增強了參數(shù)查詢的靈活性
進行API版本控制主要分三步:
該注解可直接使用在Controller類上
首先定義一個條件匹配類,對應解析Url中的version與ApiVersion注解
這里補充一下 RequestCondition
相關(guān)概念: 它是 Spring 框架中用于請求映射處理的一部分。在 Spring MVC 中,
RequestCondition
接口允許開發(fā)者定義自定義的請求匹配邏輯,這可以基于請求的任何屬性,例如路徑、參數(shù)、HTTP 方法、頭部等。相關(guān)的應用場景包括:
路徑匹配(Path Matching) :使用
PatternsRequestCondition
來定義請求的路徑模式,支持 Ant 風格的路徑模式匹配,如/api/*
可以匹配所有/api
開頭的請求路徑 。請求方法匹配(Request Method Matching) :通過
RequestMethodsRequestCondition
來限制請求的 HTTP 方法,例如只允許 GET 或 POST 請求 。請求參數(shù)匹配(Request Params Matching) :使用
ParamsRequestCondition
來定義請求必須包含的參數(shù),例如某些接口可能需要特定的查詢參數(shù)才能訪問 。請求頭匹配(Request Headers Matching) :
HeadersRequestCondition
允許定義請求頭的條件,例如某些接口可能需要特定的認證頭部才能訪問 。消費媒體類型匹配(Consumes Media Type Matching) :
ConsumesRequestCondition
用來定義控制器方法能夠處理的請求體媒體類型,通常用于 RESTful API 中,例如只處理application/json
類型的請求體 。產(chǎn)生媒體類型匹配(Produces Media Type Matching) :
ProducesRequestCondition
定義了控制器方法能夠返回的媒體類型,這通常與Accept
請求頭結(jié)合使用以確定響應的格式 。自定義條件匹配 :開發(fā)者可以通過實現(xiàn)
RequestCondition
接口來定義自己的匹配邏輯,例如根據(jù)請求中的版本號來路由到不同版本的 API,實現(xiàn) API 的版本控制 。組合條件匹配(Composite Conditions Matching) :在某些情況下,可能需要根據(jù)多個條件來匹配請求,
CompositeRequestCondition
可以將多個RequestCondition
組合成一個條件來進行匹配 。請求映射的優(yōu)先級選擇(Priority Selection for Request Mapping) :當存在多個匹配的處理器方法時,
RequestCondition
的compareTo
方法用于確定哪個條件具有更高的優(yōu)先級,以選擇最合適的處理器方法 。
創(chuàng)建一個版本映射處理器,使用
ApiVersionCondition
作為自定義條件來處理請求映射。當 Spring MVC 處理請求時,它會使用這個自定義的映射處理器來確定哪個版本的 API 應該處理請求。
將上述的處理器注冊到SpringMvc的處理流程中
驗證:
針對test接口進行不同版本的請求:
針對Account擴展版本調(diào)用上一版本接口
當請求對應的版本不存在接口時,會匹配之前版本的接口,即請求
/v2/account/extend
接口時,由于v2 控制器未實現(xiàn)該接口,所以自動匹配v1 版本中的接口。這就實現(xiàn)了
API版本繼承
。
@Validated
是一個用于 Java 應用程序中的注解,特別是在 Spring 框架中,以指示目標對象或方法需要進行驗證。這個注解通常與 JSR 303/JSR 380 規(guī)范的 Bean Validation API 結(jié)合使用,以確保數(shù)據(jù)的合法性和完整性。
@Validated注解的三種用法:
方法級別驗證
:當
@Validated
注解用在方法上時,它指示 Spring 在調(diào)用該方法之前執(zhí)行參數(shù)的驗證。如果參數(shù)不符合指定的驗證條件,將拋出
MethodArgumentNotValidException
。
類級別驗證
:將
@Validated
注解用在類上,表示該類的所有處理請求的方法都會進行驗證。這可以減少在每個方法上重復注解的需要。
組合注解
:Spring 還提供了
@Valid
注解,它是
@Validated
的一個更簡單的形式,只觸發(fā)驗證并不指定特定的驗證組(Validation Groups)。
@Validated
允許你指定一個或多個驗證組,這在需要根據(jù)不同情況執(zhí)行不同驗證規(guī)則時非常有用。
在REST API中進行參數(shù)驗證一般使用方法級別驗證即可,即對參數(shù)Dto的類內(nèi)信息進行驗證,例如一個分頁的查詢參數(shù)類:
在Controller中配合@Validated使用:
此時如果前端傳入?yún)?shù)不合法,例如pageNo為0又或者productType不存在,則會拋出
MethodArgumentNotValidException
的異常。稍后對于異常進行處理即可完成參數(shù)的驗證。
這里的@Max
、
@Min
和
@NotNull
注解屬于 Bean Validation API 的一部分,這是一個 JSR 303/JSR 380 規(guī)范,用于在 Java 應用程序中提供聲明式驗證功能。這些注解用于約束字段值的范圍和非空性。類似的注解還有:
注解 | 作用 |
@NotNull |
驗證注解的字段值不能為
null
。
|
@NotEmpty |
與
@NotNull
類似,但用于集合或字符串,驗證注解的字段值不能為
null
,且對于字符串,長度不能為 0。
|
@NotBlank |
驗證注解的字段值不能為
null
,且不能是空白字符串(空白包括空格、制表符等)。
|
@Min(value) |
驗證注解的字段值是否大于或等于指定的最小值。
value
參數(shù)接受一個整數(shù)。
|
@Max(value) |
驗證注解的字段值是否小于或等于指定的最大值。
value
參數(shù)接受一個整數(shù)。
|
@Size(min, max) | 驗證字符串或集合的大小在指定的最小值和最大值之間。 |
@Pattern(regex) | 驗證字段值是否符合指定的正則表達式。 |
注:SpringBoot 2.3.1 版本默認移除了校驗功能,如果想要開啟的話需要添加以上依賴
@RestControllerAdvice
是 @ResponseBody+@ControllerAdvice的集合注解,用于定義一個控制器級別的異常處理類。一般用來進行全局異常處理,在@RestControllerAdvice
類中處理異常后,可以直接返回一個對象,該對象會被轉(zhuǎn)換為 JSON 或 XML 響應體,返回給客戶端。
在
使用@Validated和 Bean Validation API 的注解進行參數(shù)校驗后,當出現(xiàn)不符合規(guī)定的參數(shù)會拋出
MethodArgumentNotValidException
異常
,這里就可以使用@RestControllerAdvice注解來創(chuàng)建一個全局Controller異常攔截類,來統(tǒng)一處理各類異常
這里只以
MethodArgumentNotValidException
異常進行攔截,在
@RestControllerAdvice類內(nèi)可以創(chuàng)建多個方法,通過@ExceptionHandler對不同的異常進行定制化處理,這樣當Controller內(nèi)發(fā)生異常,都可以在@RestControllerAdvice類內(nèi)進行截獲、處理、返回給客戶端安全的信息。
首先,進行統(tǒng)一的響應格式,這里需要封裝一個固定返回格式的結(jié)構(gòu)對象: ResponseData
其中對于相關(guān)的狀態(tài)碼最好進行統(tǒng)一的封裝,便于以后的開發(fā),創(chuàng)建狀態(tài)枚舉:
將上述的 ResponseData 中狀態(tài)類相關(guān)替換為枚舉
這樣Controller的接口統(tǒng)一返回格式就是標準的結(jié)構(gòu)了。
有了統(tǒng)一響應體的Controller在返回時可以這樣寫:
即便如此,團隊開發(fā)中可能還會出現(xiàn)換個人新寫Controller不知道有統(tǒng)一返回體這回事,為了更保險,可以通過AOP進行統(tǒng)一對結(jié)果進行封裝,不論Controller返回啥,到客戶端的數(shù)據(jù)都包含一個包裝體。
具體實現(xiàn)是使用 @RestControllerAdvice類 實現(xiàn) ResponseBodyAdvice 接口來完成。
我們以test接口為例,test接口原本返回的是String,而toint返回的是Integer
但是頁面返回是JSON字符串和返回體:
接口開發(fā)完成,調(diào)試時,大多數(shù)都是使用Postman模擬請求調(diào)試或者直接用前端代碼調(diào)用調(diào)試,其實這兩種都比較麻煩,尤其面對復制參數(shù)時,Postman要逐個接口的錄入,十分費事,其實這里可以在SpringBoot中引入Swagger接口文檔組件,接口文檔和接口調(diào)試一并解決。
直接在maven中引入相關(guān)依賴:
標準的swagger3引入以上兩個依賴即可,相關(guān)版本可自行選擇
下面進行swagger的配置類和一些swagger相關(guān)頁面的配置
Swagger相關(guān)注解明細
注解 | 使用位置 | 作用 |
@Api | 作用在類上, Controller 類 |
表示對類的說明,通常用于描述 Controller 的作用和分類,如
@Api(tags = "用戶管理"),后續(xù)會在Swagger文檔中以
目錄形式
展示
|
@ApiOperation | 作用在方法上,一般為 Controller中具體方法 |
描述 API 接口的具體操作和功能,例如
@ApiOperation(value = "獲取用戶列表", notes = "根據(jù)條件獲取用戶列表")
,在swagger文檔中以目錄內(nèi)容體現(xiàn)
|
@ApiModel | 作用于類上,一般是 參數(shù)實體類 |
表示這是一個模型類,通常與
@ApiModelProperty
結(jié)合使用來描述模型屬性 。
|
@ApiModelProperty | 用于模型類的屬性上, 參數(shù)類的成員變量 |
描述屬性的信息,如
@ApiModelProperty(value = "用戶名", required = true)
|
@ApiImplicitParams 和 @ApiImplicitParam | 用于方法上,一般為 Controller中具體方法 | 描述接口的隱含參數(shù),例如請求參數(shù)或請求頭信息 |
@ApiResponses 和 @ApiResponse | 用于方法上,一般為 Controller中具體方法 | 描述接口的響應信息,可以指定不同的響應狀態(tài)碼和對應的描述信息 。 |
@ApiIgnore | 用于類或方法上 | 表示忽略該類或方法,不將其顯示在Swagger文檔中。 |
@Api 和 @ApiOperation 使用
@ApiMode 和 @ApiModelProperty
@ApiImplicitParams 和 @ApiImplicitParam
與ApiMode和ApiModeProperty功能一致,一般用于get請求中的參數(shù)描述
使用swagger后,直接在頁面訪問 http://127.0.0.1:8080/XXX/doc.html即可訪問接口頁面
不要復雜的postman調(diào)用,本地調(diào)試可以直接使用調(diào)試功能
關(guān)于參數(shù)驗證的異常處理和統(tǒng)一返回結(jié)構(gòu),可以使用一個類來完成,以下是完整模板:
本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請發(fā)郵件[email protected]
湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2025 haote.com 好特網(wǎng)