日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

詳解SpringBoot如何統(tǒng)一后端返回格式

瀏覽:187日期:2023-02-24 16:29:14
目錄為什么要對SpringBoot返回統(tǒng)一的標(biāo)準(zhǔn)格式第一種:返回 String第二種:返回自定義對象第三種:接口異常定義返回標(biāo)準(zhǔn)格式高級實現(xiàn)方式接口異常問題SpringBoot為什么需要全局異常處理器體驗效果全局異常接入返回的標(biāo)準(zhǔn)格式

今天我們來聊一聊在基于SpringBoot前后端分離開發(fā)模式下,如何友好的返回統(tǒng)一的標(biāo)準(zhǔn)格式以及如何優(yōu)雅的處理全局異常。

首先我們來看看為什么要返回統(tǒng)一的標(biāo)準(zhǔn)格式?

為什么要對SpringBoot返回統(tǒng)一的標(biāo)準(zhǔn)格式

在默認(rèn)情況下,SpringBoot的返回格式常見的有三種:

第一種:返回 String

@GetMapping('/hello')public String getStr(){ return 'hello,javadaily';}

此時調(diào)用接口獲取到的返回值是這樣:

hello,javadaily

第二種:返回自定義對象

@GetMapping('/aniaml')public Aniaml getAniaml(){ Aniaml aniaml = new Aniaml(1,'pig'); return aniaml;}

此時調(diào)用接口獲取到的返回值是這樣:

{ 'id': 1, 'name': 'pig'}第三種:接口異常

@GetMapping('/error')public int error(){ int i = 9/0; return i;}

此時調(diào)用接口獲取到的返回值是這樣:

{ 'timestamp': '2021-07-08T08:05:15.423+00:00', 'status': 500, 'error': 'Internal Server Error', 'path': '/wrong'}

基于以上種種情況,如果你和前端開發(fā)人員聯(lián)調(diào)接口她們就會很懵逼,由于我們沒有給他一個統(tǒng)一的格式,前端人員不知道如何處理返回值。

還有甚者,有的同學(xué)比如小張喜歡對結(jié)果進(jìn)行封裝,他使用了Result對象,小王也喜歡對結(jié)果進(jìn)行包裝,但是他卻使用的是Response對象,當(dāng)出現(xiàn)這種情況時我相信前端人員一定會抓狂的。

所以我們項目中是需要定義一個統(tǒng)一的標(biāo)準(zhǔn)返回格式的。

定義返回標(biāo)準(zhǔn)格式

一個標(biāo)準(zhǔn)的返回格式至少包含3部分:

status 狀態(tài)值:由后端統(tǒng)一定義各種返回結(jié)果的狀態(tài)碼 message 描述:本次接口調(diào)用的結(jié)果描述 data 數(shù)據(jù):本次返回的數(shù)據(jù)

{ 'status':'100', 'message':'操作成功', 'data':'hello,javadaily'}

當(dāng)然也可以按需加入其他擴(kuò)展值,比如我們就在返回對象中添加了接口調(diào)用時間

timestamp: 接口調(diào)用時間

定義返回對象

@Datapublic class ResultData<t> { /** 結(jié)果狀態(tài) ,具體狀態(tài)碼參見ResultData.java*/ private int status; private String message; private T data; private long timestamp ; public ResultData (){ this.timestamp = System.currentTimeMillis(); } public static <t> ResultData<t> success(T data) { ResultData<t> resultData = new ResultData<>(); resultData.setStatus(ReturnCode.RC100.getCode()); resultData.setMessage(ReturnCode.RC100.getMessage()); resultData.setData(data); return resultData; } public static <t> ResultData<t> fail(int code, String message) { ResultData<t> resultData = new ResultData<>(); resultData.setStatus(code); resultData.setMessage(message); return resultData; }}

定義狀態(tài)碼

public enum ReturnCode { /**操作成功**/ RC100(100,'操作成功'), /**操作失敗**/ RC999(999,'操作失敗'), /**服務(wù)限流**/ RC200(200,'服務(wù)開啟限流保護(hù),請稍后再試!'), /**服務(wù)降級**/ RC201(201,'服務(wù)開啟降級保護(hù),請稍后再試!'), /**熱點(diǎn)參數(shù)限流**/ RC202(202,'熱點(diǎn)參數(shù)限流,請稍后再試!'), /**系統(tǒng)規(guī)則不滿足**/ RC203(203,'系統(tǒng)規(guī)則不滿足要求,請稍后再試!'), /**授權(quán)規(guī)則不通過**/ RC204(204,'授權(quán)規(guī)則不通過,請稍后再試!'), /**access_denied**/ RC403(403,'無訪問權(quán)限,請聯(lián)系管理員授予權(quán)限'), /**access_denied**/ RC401(401,'匿名用戶訪問無權(quán)限資源時的異常'), /**服務(wù)異常**/ RC500(500,'系統(tǒng)異常,請稍后重試'), INVALID_TOKEN(2001,'訪問令牌不合法'), ACCESS_DENIED(2003,'沒有權(quán)限訪問該資源'), CLIENT_AUTHENTICATION_FAILED(1001,'客戶端認(rèn)證失敗'), USERNAME_OR_PASSWORD_ERROR(1002,'用戶名或密碼錯誤'), UNSUPPORTED_GRANT_TYPE(1003, '不支持的認(rèn)證模式'); /**自定義狀態(tài)碼**/ private final int code; /**自定義描述**/ private final String message; ReturnCode(int code, String message){this.code = code;this.message = message; } public int getCode() {return code; } public String getMessage() {return message; }}

統(tǒng)一返回格式

@GetMapping('/hello')public ResultData<string> getStr(){return ResultData.success('hello,javadaily');}

此時調(diào)用接口獲取到的返回值是這樣:

{ 'status': 100, 'message': 'hello,javadaily', 'data': null, 'timestamp': 1625736481648, 'httpStatus': 0}

這樣確實已經(jīng)實現(xiàn)了我們想要的結(jié)果,我在很多項目中看到的都是這種寫法,在Controller層通過ResultData.success()對返回結(jié)果進(jìn)行包裝后返回給前端。

看到這里我們不妨停下來想想,這樣做有什么弊端呢?

最大的弊端就是我們后面每寫一個接口都需要調(diào)用ResultData.success()這行代碼對結(jié)果進(jìn)行包裝,重復(fù)勞動,浪費(fèi)體力;而且還很容易被其他老鳥給嘲笑。

所以呢我們需要對代碼進(jìn)行優(yōu)化,目標(biāo)就是不要每個接口都手工制定ResultData返回值。

高級實現(xiàn)方式

要優(yōu)化這段代碼很簡單,我們只需要借助SpringBoot提供的ResponseBodyAdvice即可。

ResponseBodyAdvice的作用:攔截Controller方法的返回值,統(tǒng)一處理返回值/響應(yīng)體,一般用來統(tǒng)一返回格式,加解密,簽名等等。

先來看下ResponseBodyAdvice的源碼:

public interface ResponseBodyAdvice<t> {/*** 是否支持advice功能* true 支持,false 不支持*/ boolean supports(MethodParameter var1, Class<!--? extends HttpMessageConverter<?-->> var2); /*** 對返回的數(shù)據(jù)進(jìn)行處理*/ @Nullable T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<!--? extends HttpMessageConverter<?-->> var4, ServerHttpRequest var5, ServerHttpResponse var6);}

我們只需要編寫一個具體實現(xiàn)類即可

/** * @author jam * @date 2021/7/8 10:10 上午 */@RestControllerAdvicepublic class ResponseAdvice implements ResponseBodyAdvice<object> { @Autowired private ObjectMapper objectMapper; @Override public boolean supports(MethodParameter methodParameter, Class<!--? extends HttpMessageConverter<?-->> aClass) {return true; } @SneakyThrows @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<!--? extends HttpMessageConverter<?-->> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {if(o instanceof String){ return objectMapper.writeValueAsString(ResultData.success(o));}return ResultData.success(o); }}

需要注意兩個地方:

@RestControllerAdvice注解

@RestControllerAdvice是@RestController注解的增強(qiáng),可以實現(xiàn)三個方面的功能:

全局異常處理 全局?jǐn)?shù)據(jù)綁定全 局?jǐn)?shù)據(jù)預(yù)處理

String類型判斷

if(o instanceof String){ return objectMapper.writeValueAsString(ResultData.success(o));}

這段代碼一定要加,如果Controller直接返回String的話,SpringBoot是直接返回,故我們需要手動轉(zhuǎn)換成json。

經(jīng)過上面的處理我們就再也不需要通過ResultData.success()來進(jìn)行轉(zhuǎn)換了,直接返回原始數(shù)據(jù)格式,SpringBoot自動幫我們實現(xiàn)包裝類的封裝。

@GetMapping('/hello')public String getStr(){ return 'hello,javadaily';}

此時我們調(diào)用接口返回的數(shù)據(jù)結(jié)果為:

@GetMapping('/hello')public String getStr(){ return 'hello,javadaily';}

是不是感覺很完美,別急,還有個問題在等著你呢。

接口異常問題

此時有個問題,由于我們沒對Controller的異常進(jìn)行處理,當(dāng)我們調(diào)用的方法一旦出現(xiàn)異常,就會出現(xiàn)問題,比如下面這個接口

@GetMapping('/wrong')public int error(){ int i = 9/0; return i;}

返回的結(jié)果為:

詳解SpringBoot如何統(tǒng)一后端返回格式

這顯然不是我們想要的結(jié)果,接口都報錯了還返回操作成功的響應(yīng)碼,前端看了會打人的。

別急,接下來我們進(jìn)入第二個議題,如何優(yōu)雅的處理全局異常。

SpringBoot為什么需要全局異常處理器

不用手寫try...catch,由全局異常處理器統(tǒng)一捕獲

使用全局異常處理器最大的便利就是程序員在寫代碼時不再需要手寫try...catch了,前面我們講過,默認(rèn)情況下SpringBoot出現(xiàn)異常時返回的結(jié)果是這樣:

{ 'timestamp': '2021-07-08T08:05:15.423+00:00', 'status': 500, 'error': 'Internal Server Error', 'path': '/wrong'}

這種數(shù)據(jù)格式返回給前端,前端是看不懂的,所以這時候我們一般通過try...catch來處理異常

@GetMapping('/wrong')public int error(){ int i; try{i = 9/0; }catch (Exception e){log.error('error:{}',e);i = 0; } return i;}

我們追求的目標(biāo)肯定是不需要再手動寫try...catch了,而是希望由全局異常處理器處理。

對于自定義異常,只能通過全局異常處理器來處理

@GetMapping('error1')public void empty(){throw new RuntimeException('自定義異常');}

當(dāng)我們引入Validator參數(shù)校驗器的時候,參數(shù)校驗不通過會拋出異常,此時是無法用try...catch捕獲的,只能使用全局異常處理器。

SpringBoot集成參數(shù)校驗請參考這篇文章SpringBoot開發(fā)秘籍 - 集成參數(shù)校驗及高階技巧

如何實現(xiàn)全局異常處理器

@Slf4j@RestControllerAdvicepublic class RestExceptionHandler { /** * 默認(rèn)全局異常處理。 * @param e the e * @return ResultData */ @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResultData<string> exception(Exception e) {log.error('全局異常信息 ex={}', e.getMessage(), e);return ResultData.fail(ReturnCode.RC500.getCode(),e.getMessage()); }}

有三個細(xì)節(jié)需要說明一下:

@RestControllerAdvice,RestController的增強(qiáng)類,可用于實現(xiàn)全局異常處理器 @ExceptionHandler,統(tǒng)一處理某一類異常,從而減少代碼重復(fù)率和復(fù)雜度,比如要獲取自定義異常可以@ExceptionHandler(BusinessException.class) @ResponseStatus指定客戶端收到的http狀態(tài)碼體驗效果

這時候我們調(diào)用如下接口:

@GetMapping('error1')public void empty(){ throw new RuntimeException('自定義異常');}

返回的結(jié)果如下:

{ 'status': 500, 'message': '自定義異常', 'data': null, 'timestamp': 1625795902556}

基本滿足我們的需求了。

但是當(dāng)我們同時啟用統(tǒng)一標(biāo)準(zhǔn)格式封裝功能ResponseAdvice和RestExceptionHandler全局異常處理器時又出現(xiàn)了新的問題:

{ 'status': 100, 'message': '操作成功', 'data': { 'status': 500, 'message': '自定義異常', 'data': null, 'timestamp': 1625796167986 }, 'timestamp': 1625796168008}

此時返回的結(jié)果是這樣,統(tǒng)一格式增強(qiáng)功能會給返回的異常結(jié)果再次封裝,所以接下來我們需要解決這個問題。

全局異常接入返回的標(biāo)準(zhǔn)格式

要讓全局異常接入標(biāo)準(zhǔn)格式很簡單,因為全局異常處理器已經(jīng)幫我們封裝好了標(biāo)準(zhǔn)格式,我們只需要直接返回給客戶端即可。

@SneakyThrows@Overridepublic Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<!--? extends HttpMessageConverter<?-->> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { if(o instanceof String){ return objectMapper.writeValueAsString(ResultData.success(o)); } if(o instanceof ResultData){ return o; } return ResultData.success(o);}

關(guān)鍵代碼:

if(o instanceof ResultData){ return o;}

如果返回的結(jié)果是ResultData對象,直接返回即可。

這時候我們再調(diào)用上面的錯誤方法,返回的結(jié)果就符合我們的要求了。

{ 'status': 500, 'message': '自定義異常', 'data': null, 'timestamp': 1625796580778}

好了,今天的文章就到這里了,希望通過這篇文章你能掌握如何在你項目中友好實現(xiàn)統(tǒng)一標(biāo)準(zhǔn)格式到返回并且可以優(yōu)雅的處理全局異常。

github地址:https://github.com/jianzh5/cloud-blog/

到此這篇關(guān)于詳解SpringBoot如何統(tǒng)一后端返回格式的文章就介紹到這了,更多相關(guān)SpringBoot 統(tǒng)一后端返回格式內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Spring
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
精品中文一区| 欧美日一区二区| 亚洲精品激情| 亚洲欧美日韩国产一区二区| 国产高清久久| 日韩视频一区二区三区在线播放免费观看| 成人免费一区| 日本久久黄色| 国产粉嫩在线观看| 日韩一区电影| 五月天久久久| 在线精品观看| 国产精品一区亚洲| 国产精品www994| 精品国产乱码久久久久久樱花| 国产精品九九| 老司机精品视频在线播放| 九九99久久精品在免费线bt| 精品久久99| 91精品国产乱码久久久久久久| 亚洲先锋成人| 在线 亚洲欧美在线综合一区| 国产精品腿扒开做爽爽爽挤奶网站| 亚洲精品一二三区区别| 蜜桃视频一区二区三区| 日本久久一区| 精品中文在线| 久久香蕉国产| 伊人www22综合色| 欧美精品91| 亚洲成av人片一区二区密柚| 丝袜脚交一区二区| 国产精品777777在线播放| 日韩免费一区| 亚洲一区导航| 国产一区国产二区国产三区| 精品一区二区三区中文字幕在线| 在线一区视频观看| 亚洲伊人精品酒店| 国产suv精品一区二区四区视频 | 奇米色欧美一区二区三区| 国产精品白丝久久av网站| 日韩在线第七页| 视频一区中文字幕| 国产高清精品二区| 99精品一区| 亚洲精品成人一区| 欧美交a欧美精品喷水| 午夜久久免费观看| 欧美日韩网址| 日韩黄色大片| 日本一区二区三区视频在线看| 国产一区调教| 亚洲一区不卡| 国产69精品久久| 亚洲精品无吗| 亚洲电影有码| 国产精品一区二区精品视频观看 | 国产精品久久久久9999高清| 99久久视频| 欧美在线观看天堂一区二区三区| 日本欧美不卡| 国产日本精品| 水蜜桃久久夜色精品一区的特点 | 国产精品一区免费在线| 不卡一区综合视频| 欧美91在线| 蜜桃视频免费观看一区| 美女福利一区二区三区| 日韩精品乱码av一区二区| 日韩中文影院| 欧美精选一区二区三区| 免费在线成人| 亚洲影视一区| 国内激情久久| 精品精品久久| 奇米亚洲欧美| 中文日韩在线| 日韩欧美一区二区三区在线视频 | 午夜精品亚洲| 精品国产aⅴ| 蜜桃伊人久久| 久久久久久美女精品| 老司机精品视频在线播放| 日韩精品欧美大片| 蜜臀av一区二区在线免费观看| 深夜视频一区二区| 国产91在线播放精品| 国产精品久久久久久av公交车| 中文视频一区| 激情五月色综合国产精品| 深夜福利视频一区二区| 久久福利在线| 欧美日韩亚洲国产精品| 日韩在线麻豆| 亚洲欧美日韩专区| www在线观看黄色| 久久99蜜桃| 国产亚洲精品美女久久久久久久久久| 欧美日韩四区| 久久激情中文| 国产夫妻在线| 精品一区二区三区中文字幕视频 | 国产精品久久| 国产欧美日韩视频在线| 日韩精品久久理论片| 亚洲一级大片| 水野朝阳av一区二区三区| 99pao成人国产永久免费视频| 成人国产精品一区二区免费麻豆| 亚洲成人一区在线观看| 亚洲综合不卡| 久久久久九九精品影院| 久久国产精品亚洲77777| 国产精品88久久久久久| 欧美激情五月| 四虎国产精品免费观看| 国产成人久久精品麻豆二区| 日韩精品久久久久久久电影99爱| 日韩精品亚洲专区在线观看| 国产成年精品| 麻豆免费精品视频| 免费一级欧美片在线观看网站| 国产麻豆精品| 日本不卡视频在线观看| 欧美一级二级视频| 国产免费久久| 国产精品极品在线观看| 精品一区视频| 日韩欧美少妇| 国产亚洲在线| 日本综合视频| 国产精品videossex| 国语精品一区| 日韩大片在线播放| 午夜精品免费| 婷婷视频一区二区三区| 日韩 欧美一区二区三区| 欧美日韩一区二区高清| 欧美中文高清| 久久亚洲人体| 亚洲成人va| 亚洲精品综合| 国产福利一区二区精品秒拍| 97精品中文字幕| 欧美日韩国产传媒| 亚洲精品少妇| 你懂的国产精品永久在线| 桃色一区二区| 日韩精品一级中文字幕精品视频免费观看| 亚洲日本在线观看视频| 激情欧美一区二区三区| 欧美专区18| 亚洲精品影视| av成人国产| 欧美日韩精品一本二本三本| 在线观看免费一区二区| 亚洲精品系列| 亚洲专区在线| 高清一区二区| 精品中文字幕一区二区三区四区| 亚洲一级在线| 国产精品白丝久久av网站| 久久久成人网| 91精品精品| 99精品综合| 国产videos久久| 日韩一区二区三区在线看| 男女男精品视频网| 最新亚洲国产| 国产伦理一区| 国产图片一区| 欧美在线观看天堂一区二区三区| 影音先锋久久精品| 麻豆精品少妇| 久久精品国产久精国产爱| 日韩精品视频网| 久久99精品久久久野外观看| 欧美欧美黄在线二区| 国产女人18毛片水真多18精品| 欧美日韩精品免费观看视欧美高清免费大片 | 国产乱码精品一区二区三区亚洲人| 亚洲啊v在线| 欧美精品成人| 91亚洲精品在看在线观看高清| 国产一区二区精品福利地址| 国产精品外国| 日韩伦理在线一区| 亚洲aⅴ网站| 久久久男人天堂| 亚洲色图综合| 欧洲一区二区三区精品| 日韩av一区二区在线影视| 色爱综合av| 国产精品一区二区中文字幕| aa亚洲婷婷| 成人免费网站www网站高清| 日韩精品视频在线看| 亚洲福利国产| 国产精品永久|