使用ResponseEntity處理API返回問(wèn)題
最近在做Google AMP mail的時(shí)候遇到了一個(gè)問(wèn)題,在調(diào)用/unsub(退訂)接口的時(shí)候需要向google client返回特定的ResponseHeader。
但是項(xiàng)目使用的是Springboot 2.x,通常使用@RestController修飾API層,無(wú)法做到動(dòng)態(tài)的返回特殊的Header。那么如何對(duì)一些特殊的API做一些特別的返回值封裝呢?
Spring framework中的ResponseEntity類(lèi)很好的解決了此問(wèn)題。
眾所周知,我們的HTTP/HTTPS的響應(yīng)由狀態(tài)碼、頭部信息以及響應(yīng)體內(nèi)容三大塊組成,響應(yīng)體內(nèi)容可以通過(guò)返回值進(jìn)行一系列封裝回傳出結(jié)果,而狀態(tài)碼與頭部信息需要特別設(shè)置。
ResponseEntity的使用
先上源碼,看看ResponseEntity到底如何使用的。
1. ResponseEntity的第一種使用方式
public class ResponseEntity<T> extends HttpEntity<T> { public ResponseEntity(HttpStatus status) { this((Object)null, (MultiValueMap)null, (HttpStatus)status); } public ResponseEntity(@Nullable T body, HttpStatus status) { this(body, (MultiValueMap)null, (HttpStatus)status); } public ResponseEntity(MultiValueMap<String, String> headers, HttpStatus status) { this((Object)null, headers, (HttpStatus)status); } public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) { super(body, headers); Assert.notNull(status, "HttpStatus must not be null"); this.status = status; } private ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, Object status) { super(body, headers); Assert.notNull(status, "HttpStatus must not be null"); this.status = status; } }
可以看到這個(gè)類(lèi)提供了五個(gè)構(gòu)造方法,返回的狀態(tài)碼是必傳的外,頭部信息以及響應(yīng)體內(nèi)容都是可選擇的。
當(dāng)我們需要使用的時(shí)候,直接new一個(gè)ResponseEntity對(duì)象作為API返回值即可,這就是它的第一種使用方式。
需要注意的是,在有headers作為參數(shù)的構(gòu)造方法中,需要傳入一個(gè)類(lèi)型為MultiValueMap<String, String>的參數(shù)。
MultiValueMap繼承自Map這個(gè)抽象類(lèi),其中擁有一個(gè)叫做HttpHeaders的子類(lèi),我們可以當(dāng)它為一個(gè)key和value都為String類(lèi)型的HashMap使用。
HttpHeaders里面保存了一些常用的Header的key值,例如"Accept-Charset"。當(dāng)然也可以自定義一些特殊的key。
HttpHeaders headers = new HttpHeaders(); headers.add("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin"); return new ResponseEntity<>(resultBody, headers, HttpStatus.OK);
2. ResponseEntity的第二種使用方式
繼續(xù)看源碼,發(fā)現(xiàn)了好多返回值為ResponseEntity.BodyBuilder的方法有木有
public static ResponseEntity.BodyBuilder status(HttpStatus status) { Assert.notNull(status, "HttpStatus must not be null"); return new ResponseEntity.DefaultBuilder(status); } public static ResponseEntity.BodyBuilder status(int status) { return new ResponseEntity.DefaultBuilder(status); } public static ResponseEntity.BodyBuilder ok() { return status(HttpStatus.OK); } public static ResponseEntity.BodyBuilder created(URI location) { ResponseEntity.BodyBuilder builder = status(HttpStatus.CREATED); return (ResponseEntity.BodyBuilder)builder.location(location); } public static ResponseEntity.BodyBuilder accepted() { return status(HttpStatus.ACCEPTED); } public static ResponseEntity.HeadersBuilder<?> noContent() { return status(HttpStatus.NO_CONTENT); } public static ResponseEntity.BodyBuilder badRequest() { return status(HttpStatus.BAD_REQUEST); } public static ResponseEntity.HeadersBuilder<?> notFound() { return status(HttpStatus.NOT_FOUND); } public static ResponseEntity.BodyBuilder unprocessableEntity() { return status(HttpStatus.UNPROCESSABLE_ENTITY); } .........
事實(shí)證明,越是偉大的軟件工程師是越“懶惰”的,為了節(jié)約時(shí)間增加效率,我們可以用Builder的方式去生成ResponseEntity對(duì)象并返回:
Map<String, String> resultBody = new HashMap<>(); resultBody.put("name":"Lucas"); resultBody.put("school":"harvard university"); return ResponseEntity.status(HttpStatus.OK) .body(resultBody);
與其他方式對(duì)比
@RestController
注解修飾controller層。
@RestController = @Controller + @ResponseBody
@ResponseBody是將controller的方法返回的對(duì)象通過(guò)適當(dāng)?shù)霓D(zhuǎn)換器轉(zhuǎn)換為指定的格式之后,寫(xiě)入到response對(duì)象的body區(qū),通常用來(lái)返回JSON數(shù)據(jù)或者是XML數(shù)據(jù)。
注意:在使用此注解之后不會(huì)再走視圖處理器(ModelAndView),而是直接將數(shù)據(jù)寫(xiě)入到輸入流中,他的效果等同于通過(guò)response對(duì)象輸出指定格式的數(shù)據(jù)。
@ResponseStatus
這個(gè)注解主要用在自定義的Exception 上,或者直接用在controller層的API方法上也可,當(dāng)發(fā)生異常/方法執(zhí)行結(jié)束時(shí),會(huì)返回相應(yīng)的Http狀態(tài)碼和msg。
@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="不允許訪問(wèn)")
注:
- ResponseEntity的優(yōu)先級(jí)高于@ResponseBody。
- 只有在返回值不為ResponseEntity的情況下才去檢查有沒(méi)有@ResponseBody注解;如果響應(yīng)類(lèi)型是ResponseEntity則會(huì)忽略@ResponseBody注解。
總結(jié)
ResponseEntity能夠非常方便的修改返回值的狀態(tài)碼,但最優(yōu)秀的用法仍然是能夠?yàn)椴煌珹PI設(shè)置不同的返回響應(yīng)頭。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
常用校驗(yàn)注解之@NotNull,@NotBlank,@NotEmpty的區(qū)別及說(shuō)明
這篇文章主要介紹了常用校驗(yàn)注解之@NotNull,@NotBlank,@NotEmpty的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(6)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07mybatis中insert主鍵ID獲取和多參數(shù)傳遞的示例代碼
這篇文章主要介紹了mybatis中insert主鍵ID獲取和多參數(shù)傳遞的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03Java使用wait和notify實(shí)現(xiàn)線程之間的通信
Java 線程通信是將多個(gè)獨(dú)立的線程個(gè)體進(jìn)行關(guān)聯(lián)處理,使得線程與線程之間能進(jìn)行相互通信,下面這篇文章主要給大家介紹了關(guān)于Java使用wait和notify實(shí)現(xiàn)線程之間通信的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04mybatis如何使用Java8的日期LocalDate和LocalDateTime詳解
這篇文章主要給大家介紹了關(guān)于mybatis如何使用Java8的日期LocalDate和LocalDateTime的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09Java實(shí)現(xiàn)郵件發(fā)送的過(guò)程及代碼詳解
這篇文章主要介紹了Java實(shí)現(xiàn)郵件發(fā)送的過(guò)程及代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07java隨機(jī)數(shù)生產(chǎn)算法實(shí)例
下面小編就為大家?guī)?lái)一篇java隨機(jī)數(shù)生產(chǎn)算法實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10