今天小編給大家分享一下SpringBoot統一接口返回及全局異常怎么處理的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
網站制作、建網站找專業的建站公司成都創新互聯:定制網站、模板網站、仿站、小程序制作、軟件開發、app軟件定制開發等。做網站價格咨詢成都創新互聯:服務完善、10余年建站、值得信賴!網站制作電話:13518219792
默認情況下,SpringBoot會有如下三種返回情況。
@GetMapping("/getUserName") public String getUserName(){ return "HuaGe"; }
調用接口返回結果:
HuaGe
@GetMapping("/getUserName") public User getUserName(){ return new User("HuaGe",18,"男"); }
調用接口返回結果:
{ "name": "HuaGe", "age": "18", "性別": "男", }
@GetMapping("/getUserName") public static String getUserName(){ HashMap hashMap = Maps.newHashMap(); return hashMap.get(0).toString(); }
模擬一個空指針異常,在不做任何異常處理的情況下,可以看下SpringBoot的默認返回結果:
{ "timestamp": "2021-08-09T06:56:41.524+00:00", "status": 500, "error": "Internal Server Error", "path": "/sysUser/getUserName" }
對于上面這幾種情況,如果整個項目沒有定義統一的返回格式,五個后臺開發人員定義五種返回格式,這樣不僅代碼臃腫,前后端對接效率低,而且還會有一些意向不到的情況發生,比如前端直接顯示異常詳情等,這給用戶的體驗是非常差的。
項目中最常見到的是封裝一個工具類,類中定義需要返回的字段信息,把需要返回前端的接口信息,通過該類進行封裝,這樣就可以解決返回格式不統一的現象了。
code:狀態碼,后臺可以維護一套統一的狀態碼;
message:描述信息,接口調用成功/失敗的提示信息;
data:返回數據。
新建Result類
public class Result<T> { private int code; private String message; private T data; public Result() {} public Result(int code, String message) { this.code = code; this.message = message; } /** * 成功 */ public static <T> Result<T> success(T data) { Result<T> result = new Result<T>(); result.setCode(ResultMsgEnum.SUCCESS.getCode()); result.setMessage(ResultMsgEnum.SUCCESS.getMessage()); result.setData(data); return result; } /** * 失敗 */ public static <T> Result<T> error(int code, String message) { return new Result(code, message); } }
定義返回狀態碼
public enum ResultMsgEnum { SUCCESS(0, "成功"), FAIL(-1, "失敗"), AUTH_ERROR(502, "授權失敗!"), SERVER_BUSY(503, "服務器正忙,請稍后再試!"), DATABASE_OPERATION_FAILED(504, "數據庫操作失敗"); private int code; private String message; ResultMsgEnum(int code, String message) { this.code = code; this.message = message; } public int getCode() { return this.code; } public String getMessage() { return this.message; } }
使用方式
上面兩步定義了數據返回格式
和狀態碼
,接下來就要看下在接口中如何使用了。
@GetMapping("/getUserName") public Result getUserName(){ return Result.success("huage"); }
調用結果如下,可以看到是我們在Result中定義的參數類型。
{ "code": 0, "message": "成功", "data": "huage" }
這樣寫雖然能夠滿足日常需求,而且我相信很多小伙伴也是這么用的,但是如果我們有大量的接口,然后在每一個接口中都使用Result.success
來包裝返回信息,會新增很多重復代碼,顯得不夠優雅,甚至都不好意思拿出去顯擺。 肯定會有一種方式能夠再一次提高代碼逼格,實現最優解。
基本用法學會后,接下來看點究極版本,主要用到如下兩個知識點,用法簡單,無論是拿出來教學妹,還是指點小姐姐,都是必備技能。
ResponseBodyAdvice:該接口是SpringMVC 4.1提供的,它允許在 執行 @ResponseBody
后自定義返回數據,用來封裝統一數據格式返回;
@RestControllerAdvice:該注解是對Controller進行增強的,可以全局捕獲拋出的異常。
新建ResponseAdvice
類;
實現ResponseBodyAdvice
接口,實現supports
、beforeBodyWrite
方法;
該類用于統一封裝controller中接口的返回結果。
@RestControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice<Object> { @Autowired private ObjectMapper objectMapper; /** * 是否開啟功能 true:是 */ @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; } /** * 處理返回結果 */ @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { //處理字符串類型數據 if(o instanceof String){ try { return objectMapper.writeValueAsString(Result.success(o)); } catch (JsonProcessingException e) { e.printStackTrace(); } } return Result.success(o); } }
我們可以通過getUserName
接口測試一下,會發現和直接使用Result
返回的結果是一致的。
不過,細心的小伙伴們肯定注意到了,在ResponseAdvice
我們全部使用了Result.success(o)
來處理結果,對于error類型的結果未做處理。我們來看下,發生異常情況時,返回結果是什么樣呢?繼續使用上面HashMap空指針異常的代碼,測試結果如下:
{ "code": 0, "message": "成功", "data": { "timestamp": "2021-08-09T09:33:26.805+00:00", "status": 405, "error": "Method Not Allowed", "path": "/sysUser/getUserName" } }
雖然格式上沒有毛病,但是在code、data字段的具體數據上是不友好或不正確的。不處理好這些事情,會嚴重影響自己在前端妹妹心中的高大形象的,這是決不能容忍的。
以前我們遇到異常時,第一時間想到的應該是try..catch..finnal吧,不過這種方式會導致大量代碼重復,維護困難,邏輯臃腫等問題,這不是我們想要的結果。
今天我們要用的全局異常處理方式,用起來是比較簡單的。首先新增一個類,增加@RestControllerAdvice
注解,該注解的作用花哥上面已經介紹過,就不再嘮叨了。
@RestControllerAdvice public class CustomerExceptionHandler { }
如果我們有想要攔截的異常類型,就新增一個方法,使用@ExceptionHandler
注解修飾,注解參數為目標異常類型。
例如:controller中接口發生Exception異常時,就會進入到Execption
方法中進行捕獲,將雜亂的異常信息,轉換成指定格式后交給ResponseAdvice
方法進行統一格式封裝并返回給前端小伙伴。
@RestControllerAdvice @Slf4j public class CustomerExceptionHandler { @ExceptionHandler(AuthException.class) public String ErrorHandler(AuthorizationException e) { log.error("沒有通過權限驗證!", e); return "沒有通過權限驗證!"; } @ExceptionHandler(Exception.class) public Result Execption(Exception e) { log.error("未知異常!", e); return Result.error(ResultMsgEnum.SERVER_BUSY.getCode(),ResultMsgEnum.SERVER_BUSY.getMessage()); } }
再次調用接口getUserName
查看返回結果,會發現還是有一些問題,因為我們在CustomerExceptionHandler
中已經將接口返回結果封裝成Result
類型,而代碼執行到統一結果返回類ResponseAdvice
時,又會結果再次封裝,就出現了如下問題。
{ "code": 0, "message": "成功", "data": { "code": 503, "message": "服務器正忙,請稍后再試!", "data": null } }
解決上述問題非常簡單,只要在beforeBodyWrite
中增加一條判斷即可。
@RestControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice<Object> { @Autowired private ObjectMapper objectMapper; /** * 是否開啟功能 true:開啟 */ @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; } /** * 處理返回結果 */ @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { //處理字符串類型數據 if(o instanceof String){ try { return objectMapper.writeValueAsString(Result.success(o)); } catch (JsonProcessingException e) { e.printStackTrace(); } } //返回類型是否已經封裝 if(o instanceof Result){ return o; } return Result.success(o); } }
以上就是“SpringBoot統一接口返回及全局異常怎么處理”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注創新互聯行業資訊頻道。
文章標題:SpringBoot統一接口返回及全局異常怎么處理
標題URL:http://vcdvsql.cn/article6/iijiig.html
成都網站建設公司_創新互聯,為您提供營銷型網站建設、企業建站、定制開發、服務器托管、商城網站、App設計
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯