电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解SpringBoot如何統一后端返回格式

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

今天我們來聊一聊在基于SpringBoot前后端分離開發模式下,如何友好的返回統一的標準格式以及如何優雅的處理全局異常。

首先我們來看看為什么要返回統一的標準格式?

為什么要對SpringBoot返回統一的標準格式

在默認情況下,SpringBoot的返回格式常見的有三種:

第一種:返回 String

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

此時調用接口獲取到的返回值是這樣:

hello,javadaily

第二種:返回自定義對象

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

此時調用接口獲取到的返回值是這樣:

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

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

此時調用接口獲取到的返回值是這樣:

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

基于以上種種情況,如果你和前端開發人員聯調接口她們就會很懵逼,由于我們沒有給他一個統一的格式,前端人員不知道如何處理返回值。

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

所以我們項目中是需要定義一個統一的標準返回格式的。

定義返回標準格式

一個標準的返回格式至少包含3部分:

status 狀態值:由后端統一定義各種返回結果的狀態碼 message 描述:本次接口調用的結果描述 data 數據:本次返回的數據

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

當然也可以按需加入其他擴展值,比如我們就在返回對象中添加了接口調用時間

timestamp: 接口調用時間

定義返回對象

@Datapublic class ResultData<t> { /** 結果狀態 ,具體狀態碼參見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; }}

定義狀態碼

public enum ReturnCode { /**操作成功**/ RC100(100,'操作成功'), /**操作失敗**/ RC999(999,'操作失敗'), /**服務限流**/ RC200(200,'服務開啟限流保護,請稍后再試!'), /**服務降級**/ RC201(201,'服務開啟降級保護,請稍后再試!'), /**熱點參數限流**/ RC202(202,'熱點參數限流,請稍后再試!'), /**系統規則不滿足**/ RC203(203,'系統規則不滿足要求,請稍后再試!'), /**授權規則不通過**/ RC204(204,'授權規則不通過,請稍后再試!'), /**access_denied**/ RC403(403,'無訪問權限,請聯系管理員授予權限'), /**access_denied**/ RC401(401,'匿名用戶訪問無權限資源時的異常'), /**服務異常**/ RC500(500,'系統異常,請稍后重試'), INVALID_TOKEN(2001,'訪問令牌不合法'), ACCESS_DENIED(2003,'沒有權限訪問該資源'), CLIENT_AUTHENTICATION_FAILED(1001,'客戶端認證失敗'), USERNAME_OR_PASSWORD_ERROR(1002,'用戶名或密碼錯誤'), UNSUPPORTED_GRANT_TYPE(1003, '不支持的認證模式'); /**自定義狀態碼**/ 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; }}

統一返回格式

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

此時調用接口獲取到的返回值是這樣:

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

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

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

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

所以呢我們需要對代碼進行優化,目標就是不要每個接口都手工制定ResultData返回值。

高級實現方式

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

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

先來看下ResponseBodyAdvice的源碼:

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

我們只需要編寫一個具體實現類即可

/** * @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注解的增強,可以實現三個方面的功能:

全局異常處理 全局數據綁定全 局數據預處理

String類型判斷

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

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

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

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

此時我們調用接口返回的數據結果為:

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

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

接口異常問題

此時有個問題,由于我們沒對Controller的異常進行處理,當我們調用的方法一旦出現異常,就會出現問題,比如下面這個接口

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

返回的結果為:

詳解SpringBoot如何統一后端返回格式

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

別急,接下來我們進入第二個議題,如何優雅的處理全局異常。

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

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

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

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

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

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

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

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

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

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

SpringBoot集成參數校驗請參考這篇文章SpringBoot開發秘籍 - 集成參數校驗及高階技巧

如何實現全局異常處理器

@Slf4j@RestControllerAdvicepublic class RestExceptionHandler { /** * 默認全局異常處理。 * @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()); }}

有三個細節需要說明一下:

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

這時候我們調用如下接口:

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

返回的結果如下:

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

基本滿足我們的需求了。

但是當我們同時啟用統一標準格式封裝功能ResponseAdvice和RestExceptionHandler全局異常處理器時又出現了新的問題:

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

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

全局異常接入返回的標準格式

要讓全局異常接入標準格式很簡單,因為全局異常處理器已經幫我們封裝好了標準格式,我們只需要直接返回給客戶端即可。

@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);}

關鍵代碼:

if(o instanceof ResultData){ return o;}

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

這時候我們再調用上面的錯誤方法,返回的結果就符合我們的要求了。

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

好了,今天的文章就到這里了,希望通過這篇文章你能掌握如何在你項目中友好實現統一標準格式到返回并且可以優雅的處理全局異常。

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

到此這篇關于詳解SpringBoot如何統一后端返回格式的文章就介紹到這了,更多相關SpringBoot 統一后端返回格式內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
主站蜘蛛池模板: 恒温槽_恒温水槽_恒温水浴槽-上海方瑞仪器有限公司 | 超高频感应加热设备_高频感应电源厂家_CCD视觉检测设备_振动盘视觉检测设备_深圳雨滴科技-深圳市雨滴科技有限公司 | 电加热导热油炉-空气加热器-导热油加热器-翅片电加热管-科安达机械 | 昆明网络公司|云南网络公司|昆明网站建设公司|昆明网页设计|云南网站制作|新媒体运营公司|APP开发|小程序研发|尽在昆明奥远科技有限公司 | 中视电广_短视频拍摄_短视频推广_短视频代运营_宣传片拍摄_影视广告制作_中视电广 | 带式过滤机厂家_价格_型号规格参数-江西核威环保科技有限公司 | 断桥铝破碎机_铝合金破碎机_废铁金属破碎机-河南鑫世昌机械制造有限公司 | 安徽控制器-合肥船用空调控制器-合肥家电控制器-合肥迅驰电子厂 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 刮板输送机,粉尘加湿搅拌机,螺旋输送机,布袋除尘器 | 蓝鹏测控平台 - 智慧车间系统 - 车间生产数据采集与分析系统 | 日本东丽膜_反渗透膜_RO膜价格_超滤膜_纳滤膜-北京东丽阳光官网 日本细胞免疫疗法_肿瘤免疫治疗_NK细胞疗法 - 免疫密码 | 宁波普瑞思邻苯二甲酸盐检测仪,ROHS2.0检测设备,ROHS2.0测试仪厂家 | 上海诺狮景观规划设计有限公司 | 超细粉碎机|超微气流磨|气流分级机|粉体改性设备|超微粉碎设备-山东埃尔派粉碎机厂家 | 西安标准厂房_陕西工业厂房_西咸新区独栋厂房_长信科技产业园官方网站 | 青岛美佳乐清洁工程有限公司|青岛油烟管道清洗|酒店|企事业单位|学校工厂厨房|青岛油烟管道清洗 插针变压器-家用电器变压器-工业空调变压器-CD型电抗器-余姚市中驰电器有限公司 | 丹佛斯压力传感器,WISE温度传感器,WISE压力开关,丹佛斯温度开关-上海力笙工业设备有限公司 | 粘弹体防腐胶带,聚丙烯防腐胶带-全民塑胶 | 警用|治安|保安|不锈钢岗亭-售货亭价格-垃圾分类亭-移动厕所厂家-苏州灿宇建材 | 镀锌钢格栅_热镀锌格栅板_钢格栅板_热镀锌钢格板-安平县昊泽丝网制品有限公司 | 小型气象站_便携式自动气象站_校园气象站-竞道气象设备网 | 交变/复合盐雾试验箱-高低温冲击试验箱_安奈设备产品供应杭州/江苏南京/安徽马鞍山合肥等全国各地 | 挤出机_橡胶挤出机_塑料挤出机_胶片冷却机-河北伟源橡塑设备有限公司 | 长沙一级消防工程公司_智能化弱电_机电安装_亮化工程专业施工承包_湖南公共安全工程有限公司 | 陶氏道康宁消泡剂_瓦克消泡剂_蓝星_海明斯德谦_广百进口消泡剂 | 恒温恒湿箱(药品/保健品/食品/半导体/细菌)-兰贝石(北京)科技有限公司 | 单级/双级旋片式真空泵厂家,2xz旋片真空泵-浙江台州求精真空泵有限公司 | 合肥卓创建筑装饰,专业办公室装饰、商业空间装修与设计。 | 学生作文网_中小学生作文大全与写作指导 | ICP备案查询_APP备案查询_小程序备案查询 - 备案巴巴 | 吊篮式|移动式冷热冲击试验箱-二槽冷热冲击试验箱-广东科宝 | 电子元器件呆滞料_元器件临期库存清仓尾料_尾料优选现货采购处理交易商城 | 四川成都干燥设备_回转筒干燥机_脉冲除尘器_输送设备_热风炉_成都川工星科机电设备有限公司 | 利浦顿蒸汽发生器厂家-电蒸汽发生器/燃气蒸汽发生器_湖北利浦顿热能科技有限公司官网 | 超声波气象站_防爆气象站_空气质量监测站_负氧离子检测仪-风途物联网 | 淘趣英语网 - 在线英语学习,零基础英语学习网站 | 顺景erp系统_erp软件_erp软件系统_企业erp管理系统-广东顺景软件科技有限公司 | 深圳美安可自动化设备有限公司,喷码机,定制喷码机,二维码喷码机,深圳喷码机,纸箱喷码机,东莞喷码机 UV喷码机,日期喷码机,鸡蛋喷码机,管芯喷码机,管内壁喷码机,喷码机厂家 | 12cr1mov无缝钢管切割-15crmog无缝钢管切割-40cr无缝钢管切割-42crmo无缝钢管切割-Q345B无缝钢管切割-45#无缝钢管切割 - 聊城宽达钢管有限公司 | 哈尔滨京科脑康神经内科医院-哈尔滨治疗头痛医院-哈尔滨治疗癫痫康复医院 | 碳化硅,氮化硅,冰晶石,绢云母,氟化铝,白刚玉,棕刚玉,石墨,铝粉,铁粉,金属硅粉,金属铝粉,氧化铝粉,硅微粉,蓝晶石,红柱石,莫来石,粉煤灰,三聚磷酸钠,六偏磷酸钠,硫酸镁-皓泉新材料 |