日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot - 统一格式封装及高阶全局异常处理

發布時間:2025/3/21 javascript 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot - 统一格式封装及高阶全局异常处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • Pre
  • 演進過程
  • 版本V1
  • 版本2
    • Step1 約定統一返回格式
    • Step2 開發統一返回對象
    • Step3 約定接口狀態碼
    • Step4 驗證
    • Step5 完善全局異常處理 @RestControllerAdvice + @ExceptionHandler
    • 全局異常處理器的必要行
  • 版本3 (ResponseBodyAdvice)
    • Step1 自定義ResponseBodyAdvice接口實現類
    • Step2 全局異常整合到返回的標準格式
  • 源碼


Pre

Spring Boot2.x-11 使用@ControllerAdvice和@ExceptionHandler實現自定義全局異常


演進過程

我們搞個boot工程 ,來看下為什么以及如何來實現統一格式封裝及高階全局異常處理

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>jakarta.validation</groupId><artifactId>jakarta.validation-api</artifactId></dependency></dependencies>


版本V1

@RestController // 返回JSON @RequestMapping("/v1") public class ArtisanV1Controller {/*** 返回字符串** @return*/@GetMapping("/getString")public String getStr() {return "OOOOOOOK";}/*** 返回自定義對象** @return*/@GetMapping("/getArtisan")public Artisan getArt() {Artisan artisan = new Artisan();artisan.setJob("ArtisanJob");artisan.setAge(18);return artisan;}/*** 接口異常** @return*/@GetMapping("/getMockError")public int getMockError() {int i = 1 / 0;return i;}}

分別測試下

這混亂的格式, 前端同學怎么想


版本2

Step1 約定統一返回格式

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

  • status 狀態值

    由后端統一定義各種返回結果的狀態碼

  • message 描述

    本次接口調用的結果描述

  • data 數據

    本次接口返回的數據

如果需要可以加入其他節點,比如在返回對象中添加了接口調用時間 (timestamp: 接口調用時間)

Step2 開發統一返回對象

package com.artisan.resp;import lombok.Data;/*** @author 小工匠* @version 1.0* @description: 公共結果 * @mark: show me the code , change the world*/ @Data public class ResponseData<T> {/*** 結果狀態 ,具體狀態碼參見ResponseCode*/private int status;/*** 響應消息**/private String message;/*** 響應數據**/private T data;/*** 接口請求時間**/private long timestamp;/*** 初始化,增加接口請求事件*/public ResponseData() {this.timestamp = System.currentTimeMillis();}/*** 成功** @param <T>* @return*/public static <T> ResponseData<T> success() {ResponseData<T> resultData = new ResponseData<>();resultData.setStatus(ResponseCode.RC100.getCode());resultData.setMessage(ResponseCode.RC100.getMessage());return resultData;}/*** 成功** @param message* @param <T>* @return*/public static <T> ResponseData<T> success(String message) {ResponseData<T> resultData = new ResponseData<>();resultData.setStatus(ResponseCode.RC100.getCode());resultData.setMessage(message);return resultData;}/*** 成功** @param data* @param <T>* @return*/public static <T> ResponseData<T> success(T data) {ResponseData<T> resultData = new ResponseData<>();resultData.setStatus(ResponseCode.RC100.getCode());resultData.setMessage(ResponseCode.RC100.getMessage());resultData.setData(data);return resultData;}/*** 失敗** @param message* @param <T>* @return*/public static <T> ResponseData<T> fail(String message) {ResponseData<T> resultData = new ResponseData<>();resultData.setStatus(ResponseCode.RC999.getCode());resultData.setMessage(message);return resultData;}/*** 失敗** @param code* @param message* @param <T>* @return*/public static <T> ResponseData<T> fail(int code, String message) {ResponseData<T> resultData = new ResponseData<>();resultData.setStatus(code);resultData.setMessage(message);return resultData;}/*** 失敗** @param <T>* @return*/public static <T> ResponseData<T> fail() {ResponseData<T> resultData = new ResponseData<>();resultData.setStatus(ResponseCode.RC999.getCode());resultData.setMessage(ResponseCode.RC999.getMessage());return resultData;}}

Step3 約定接口狀態碼

package com.artisan.resp;import lombok.Getter;/*** @author 小工匠* @version 1.0* @description: 狀態碼集合* @mark: show me the code , change the world*/ public enum ResponseCode {/*** 操作成功**/RC100(100, "操作成功"),/*** 操作失敗**/RC999(999, "操作失敗"),/*** access_denied**/RC403(403, "無訪問權限,請聯系管理員授予權限"),/*** access_denied**/RC401(401, "匿名用戶訪問無權限資源時的異常"),/*** 服務異常**/RC500(500, "系統異常,請稍后重試"),ILLEGAL_ARGUMENT(3001, "非法參數"),INVALID_TOKEN(2001, "訪問令牌不合法"),ACCESS_DENIED(2003, "沒有權限訪問該資源"),CLIENT_AUTHENTICATION_FAILED(1001, "客戶端認證失敗"),USERNAME_OR_PASSWORD_NOTMATCH(1002, "用戶名或密碼錯誤"); /*** 自定義狀態碼**/@Getterprivate final int code;/*** 自定義描述**/@Getterprivate final String message;ResponseCode(int code, String message) {this.code = code;this.message = message;}}

Step4 驗證

package com.artisan.controller;import com.artisan.entity.Artisan; import com.artisan.resp.ResponseData; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;/*** @author 小工匠* @version 1.0* @description: 版本2* @mark: show me the code , change the world*/@RestController @RequestMapping("/v2") public class ArtisanV2Controller {@GetMapping("/getString")public ResponseData<String> getStr() {return ResponseData.success("OOOOOOK");}@GetMapping("/getArtisan")public ResponseData<Artisan> getArt() {Artisan artisan = new Artisan();artisan.setJob("CodeMonkey");artisan.setAge(18);return ResponseData.success(artisan);}@GetMapping("/getMockError")public ResponseData<Integer> getMockError() {int i = 1 / 0;return ResponseData.success(i);}}

好像部分實現了統一格式返回,確實也是有很多項目在Controller層通過ResponseData.success()對返回結果進行包裝后返回給前端。

但是這個拋異常的這么玩還是不行呀? ------------------------> 全局異常處理

Step5 完善全局異常處理 @RestControllerAdvice + @ExceptionHandler

package com.artisan.resp;import com.artisan.exception.BaseException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindException; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.ValidationException; import java.util.stream.Collectors;/*** @author 小工匠* @version 1.0* @description: 全局異常處理* @mark: show me the code , change the world*/ @Slf4j @RestControllerAdvice public class GlobalExceptionHandler {/*** 默認全局異常處理。** @param e e* @return ResponseData*/@ExceptionHandler(Exception.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public ResponseData<String> exception(Exception e) {log.error("兜底異常信息 ex={}", e.getMessage());return ResponseData.fail(ResponseCode.RC500.getCode(), e.getMessage());}/*** Assert異常*/@ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class})@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public ResponseData<String> exception(IllegalArgumentException e) {return ResponseData.fail(ResponseCode.ILLEGAL_ARGUMENT.getCode(), e.getMessage());}/*** 抓取自定義異常 BaseException*/@ExceptionHandler(BaseException.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public ResponseData<String> exception(BaseException e) {return ResponseData.fail(e.getErrorCode(), e.getMessage());}}
  • @ExceptionHandler,統一處理某一類異常, 減少代碼重復率和復雜度,比如要捕獲自定義異常可以@ExceptionHandler(BusinessException.class)

  • @ResponseStatus指定客戶端收到的http狀態碼

重新驗證下


全局異常處理器的必要行

  • 避免try…catch,由全局異常處理器統一捕獲
  • 自定義異常,只能通過全局異常處理器來處理
  • Validator參數校驗器的時候,參數校驗不通過會拋出異常,無法用try…catch捕獲,只能使用全局異常處理器。

  • 版本3 (ResponseBodyAdvice)

    V2版本有缺陷么?

    我們不難發現每寫一個接口都需要調用ResponseData.success()對結果進行包裝 ,程序猿懶啊, 能不寫嗎


    Step1 自定義ResponseBodyAdvice接口實現類

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

    package com.artisan.resp.v3;import com.artisan.resp.ResponseData; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;/*** @author 小工匠* @version 1.0* @description: 攔截Controller方法的返回值,統一處理返回值/響應體* @mark: show me the code , change the world*/@RestControllerAdvice public class CustomResponseAdvice implements ResponseBodyAdvice<Object> {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {return true;}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {// 處理String類型 if (o instanceof String) {return objectMapper.writeValueAsString(ResponseData.success(o));}// 若是統一返回類型,則不用再此封裝 // if (o instanceof ResponseData) { // return o; // }return ResponseData.success(o);} }
    • @RestControllerAdvice,RestController的增強類,可用于實現全局異常處理器

    • 有一個地方對String做了特殊處理,因為如果Controller直接返回String ,SpringBoot是直接返回,所以我們需要手動轉換成json


    接入@RestControllerAdvice后, Controller就正常寫就可以了,不用統一格式去包裝了,如下

    @RestController @RequestMapping("/v3") public class ArtisanV3Controller {@GetMapping("/getString")public String getStr() {return "OOOOOOK";}@GetMapping("/getArtisan")public Artisan getArt() {Artisan artisan = new Artisan();artisan.setJob("CodeMonkey");artisan.setAge(18);return artisan;}@GetMapping("/getMockError")public int getMockError() {int i = 1 / 0;return i;}}

    測試下

    看到問題了吧,當我們同時啟用統一標準格式封裝功能ResponseAdvice和RestExceptionHandler全局異常處理器時,統一格式增強功能會給返回的異常結果再次封裝,所以跟前端的接口響應又迷糊了


    Step2 全局異常整合到返回的標準格式

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

    // 若是統一返回類型,則不用再此封裝if (o instanceof ResponseData) {return o;}

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

    重新測試 ,


    源碼

    https://github.com/yangshangwei/boot2

    總結

    以上是生活随笔為你收集整理的SpringBoot - 统一格式封装及高阶全局异常处理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 成人av黄色| 爱插视频 | 黑人专干日本人xxxx | 久久精品伦理 | 欧美日韩有码 | 一起草最新网址 | 波多野结衣高清在线 | 亚洲网站在线看 | 免费黄网站在线观看 | 影视av| 欧美在线激情 | 国产精品久久久爽爽爽麻豆色哟哟 | 国产图片一区 | 国产喷白浆一区二区三区 | 国产精品久久久久久久久久久久久久久久久 | 天堂网avav| 人人干天天操 | 国产乡下妇女做爰视频 | 与亲女洗澡时伦了毛片 | 日本黄色a级片 | 久久久久亚洲国产 | 日韩欧美中文在线 | 久99久视频 | 色午夜婷婷 | 女人下面喷水视频 | 亚洲精品国产精品国自产 | aaaa级片 | 亚洲欧美动漫 | 日韩在线视频免费 | 在线中出 | 欧美性猛交xxxx乱大交退制版 | 91伦理视频 | 亚洲h视频在线观看 | 欧美成人午夜精品久久久 | 日本大尺度床戏揉捏胸 | 深夜福利成人 | 国产伦精品一区二区三区88av | 国产高清一区二区 | 拔插拔插海外华人永久免费 | 欧美亚洲第一区 | 自拍偷自拍亚洲精品播放 | 香蕉视频三级 | aaaaa黄色片| 国产精品视频免费 | 日韩欧美视频在线播放 | 福利片一区二区 | 日本一区二区三区视频在线播放 | 成人精品视频99在线观看免费 | 男女无遮挡xx00动态图120秒 | 日本泡妞xxxx免费视频软件 | 九七精品| 女女高潮h冰块play失禁百合 | 国产成人亚洲精品 | 欧美操女人 | 色婷婷97 | 操操综合网 | 国产精品一区二区在线播放 | 日p免费视频 | 欧美h视频在线观看 | 亚洲欧美日韩国产成人精品影院 | 欧美成人精品二区三区99精品 | 色播五月激情 | 扒开伸进免费视频 | 亚洲精品久久久久久无码色欲四季 | 国产一级特黄 | 亚洲福利一区二区 | 懂色一区二区三区免费观看 | 女人被灌满精子 | 2018天天弄 | www.亚洲人 | 久久色av| 国产精久久一区二区三区 | 亚洲成人自拍偷拍 | 秋霞在线一区二区 | 一区二区在线视频播放 | 久久国产一区 | 日韩一级片网站 | 久久久无码精品亚洲国产 | 成人黄色网页 | 成年人在线免费观看视频网站 | 特级丰满少妇一级aaaa爱毛片 | 九九热视频免费 | 久操视频免费在线观看 | 成人在线亚洲 | 韩国一区二区三区视频 | 少妇三级 | 另类二区 | 乖女从小调教h尿便器小说 欧美韩一区二区 | 欧美成人a视频 | 天堂av在线免费观看 | 精品视频一区二区三区 | 色黄啪啪网 | 欧美成人性生活片 | 国产精品夜色一区二区三区 | 国产毛片毛片毛片 | 99久久精品国产成人一区二区 | 人人超碰在线 | 少妇人妻综合久久中文字幕 | 中文在线字幕免费观 |