摘要:全局異常處理類用于全局返回,如需返回請使用繼承了,對于一些類似于請求方式異常的異常進行捕獲重寫,自定義處理過程這里將異常直接傳給方法進行處理,返回值為保證友好的返回,而不是出現錯誤碼。
前言
異常的處理在我們的日常開發中是一個繞不過去的坎,在Spring Boot 項目中如何優雅的去處理異常,正是我們這一節課需要研究的方向。
異常的分類在一個Spring Boot項目中,我們可以把異常分為兩種,第一種是請求到達Controller層之前,第二種是到達Controller層之后項目代碼中發生的錯誤。而第一種又可以分為兩種錯誤類型:1. 路徑錯誤 2. 類似于請求方式錯誤,參數類型不對等類似錯誤。
定義ReturnVO和ReturnCode為了保持返回值的統一,我們這里定義了統一返回的類ReturnVO,以及一個記錄錯誤返回碼和錯誤信息的枚舉類ReturnCode,而具體的錯誤信息和錯誤代碼保存到了response.properties中,使用流進行讀取。
ReturnVOpublic class ReturnVO { private static Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + CommonUrl.RESPONSE_PROP_URL); /** * 返回代碼 */ private String code; /** * 返回信息 */ private String message; /** * 返回數據 */ private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } /** * 默認構造,返回操作正確的返回代碼和信息 */ public ReturnVO() { this.setCode(properties.getProperty(ReturnCode.SUCCESS.val())); this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg())); } /** * 返回代碼,這里需要在枚舉中去定義 * @param code */ public ReturnVO(ReturnCode code) { this.setCode(properties.getProperty(code.val())); this.setMessage(properties.getProperty(code.msg())); } /** * 返回數據,默認返回正確的code和message * @param data */ public ReturnVO(Object data) { this.setCode(properties.getProperty(ReturnCode.SUCCESS.val())); this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg())); this.setData(data); } /** * 返回錯誤的代碼,以及自定義的錯誤信息 * @param code * @param message */ public ReturnVO(ReturnCode code, String message) { this.setCode(properties.getProperty(code.val())); this.setMessage(message); } /** * 返回自定義的code,message,以及data * @param code * @param message * @param data */ public ReturnVO(ReturnCode code, String message, Object data) { this.setCode(code.val()); this.setMessage(message); this.setData(data); } @Override public String toString() { return "ReturnVO{" + "code="" + code + """ + ", message="" + message + """ + ", data=" + data + "}"; } }ReturnCode
其他的錯誤處理只需要在枚舉類中添加對應的異常即可,枚舉的名稱要定義為異常的名稱,這樣可以直接不用對其他的代碼進行修改,添加一個新的異常時,僅僅添加枚舉類中的字段和properties文件中的屬性。
public enum ReturnCode { /** 操作成功 */ SUCCESS("SUCCESS_CODE", "SUCCESS_MSG"), /** 操作失敗 */ FAIL("FAIL_CODE", "FAIL_MSG"), /** 空指針異常 */ NullPointerException("NPE_CODE", "NPE_MSG"), /** 自定義異常之返回值為空 */ NullResponseException("NRE_CODE", "NRE_MSG"), /** 運行時異常 */ RuntimeException("RTE_CODE","RTE_MSG"), /** 請求方式錯誤異常 */ HttpRequestMethodNotSupportedException("REQUEST_METHOD_UNSUPPORTED_CODE","REQUEST_METHOD_UNSUPPORTED_MSG"), /** INTERNAL_ERROR */ BindException("BIND_EXCEPTION_CODE","BIND_EXCEPTION_MSG"), /** 頁面路徑不對 */ UrlError("UE_CODE","UE_MSG"); private ReturnCode(String value, String msg){ this.val = value; this.msg = msg; } public String val() { return val; } public String msg() { return msg; } private String val; private String msg; }response.properties
這里我自定義了一些異常用于后面的測試,在我們實際的項目中需要定義很多的異常去完善。
SUCCESS_CODE=2000 SUCCESS_MSG=操作成功 FAIL_CODE=5000 FAIL_MSG=操作失敗 NPE_CODE=5001 NPE_MSG=空指針異常 NRE_CODE=5002 NRE_MSG=返回值為空 RTE_CODE=5001 RTE_MSG=運行時異常 UE_CODE=404 UE_MSG=頁面路徑有誤 REQUEST_METHOD_UNSUPPORTED_CODE=4000 REQUEST_METHOD_UNSUPPORTED_MSG=請求方式異常 BIND_EXCEPTION_CODE=4001 BIND_EXCEPTION_MSG=請求參數綁定失敗路徑錯誤處理
這里的路徑錯誤處理方式是采用了實現ErrorController接口,然后實現了getErrorPath()方法:
/** * 請求路徑有誤 * @author yangwei * @since 2019-01-02 18:13 */ @RestController public class RequestExceptionHandler implements ErrorController { @Override public String getErrorPath() { return "/error"; } @RequestMapping("/error") public ReturnVO errorPage(){ return new ReturnVO(ReturnCode.UrlError); } }
這里可以進行測試一下:
使用ControllerAdvice對其他類型的異常進行處理類似于到達Controller之前的請求參數錯誤,請求方式錯誤,數據格式不對等等錯誤都歸類為一種,這里僅僅展示請求方式錯誤的處理方式。
/** * 全局異常處理類 * @author yangwei * * 用于全局返回json,如需返回ModelAndView請使用ControllerAdvice * 繼承了ResponseEntityExceptionHandler,對于一些類似于請求方式異常的異常進行捕獲 */ @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { private static Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + CommonUrl.RESPONSE_PROP_URL); /** * 重寫handleExceptionInternal,自定義處理過程 **/ @Override protected ResponseEntity
這里我們可以進行測試:
@RestController @RequestMapping(value = "/user") public class UserController { @Autowired private IUserService userService; @PostMapping(value = "/findAll") public Object findAll() { throw new RuntimeException("ffffd"); } @RequestMapping(value = "/findAll1") public ReturnVO findAll1(UserDO userDO) { System.out.println(userDO); return new ReturnVO(userService.findAll1()); } @RequestMapping(value = "/test") public ReturnVO test() { throw new RuntimeException("測試非自定義運行時異常"); } }
直接在瀏覽器訪問findAll,默認為get方法,這里按照我們期望會拋出請求方式異常的錯誤:
訪問findAll1?id=123ss,這里由于我們接受的UserDO中id屬性是Integer類型,所以這里報一個參數綁定異常:
訪問test,測試非自定義運行時異常:
結合AOP使用,放入公用模塊減少代碼的重復我們上節課使用AOP對于全局異常處理進行了一次簡單的操作,這節課進行了完善,并將其放入到我們的公用模塊,使用時只需導入jar包,然后在啟動類配置掃描包路徑即可
/** * 統一封裝返回值和異常處理 * * @author vi * @since 2018/12/20 6:09 AM */ @Slf4j @Aspect @Order(5) @Component public class ResponseAop { @Autowired private GlobalExceptionHandler exceptionHandler; /** * 切點 */ @Pointcut("execution(public * indi.viyoung.viboot.*.controller..*(..))") public void httpResponse() { } /** * 環切 */ @Around("httpResponse()") public ReturnVO handlerController(ProceedingJoinPoint proceedingJoinPoint) { ReturnVO returnVO = new ReturnVO(); try { Object proceed = proceedingJoinPoint.proceed(); if (proceed instanceof ReturnVO) { returnVO = (ReturnVO) proceed; } else { returnVO.setData(proceed); } } catch (Throwable throwable) { // 這里直接調用剛剛我們在handler中編寫的方法 returnVO = exceptionHandler.handlerException(throwable); } return returnVO; } }
做完這些準備工作,以后我們在進行異常處理的時候只需要進行以下幾步操作:
引入公用模塊jar包
在啟動類上配置掃描包路徑
如果新增異常的話,在枚舉類中新增后,再去properties中進行返回代碼和返回信息的編輯即可(注意:枚舉類的變量名一定要和異常名保持一致)
公眾號文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75701.html
摘要:挺多人咨詢的,異常處理用切面注解去實現去全局異常處理。全局異常處理類,代碼如下代碼解析如下抽象類是用來處理全局錯誤時進行擴展和實現注解標記的切面排序,值越小擁有越高的優先級,這里設置優先級偏高。 本文內容 為什么要全局異常處理? WebFlux REST 全局異常處理實戰 小結 摘錄:只有不斷培養好習慣,同時不斷打破壞習慣,我們的行為舉止才能夠自始至終都是正確的。 一、為什么要全局...
摘要:接口日志有啥用在我們日常的開發過程中,我們可以通過接口日志去查看這個接口的一些詳細信息。在切入點返回內容之后切入內容可以用來對處理返回值做一些加工處理。 接口日志有啥用 在我們日常的開發過程中,我們可以通過接口日志去查看這個接口的一些詳細信息。比如客戶端的IP,客戶端的類型,響應的時間,請求的類型,請求的接口方法等等,我們可以對這些數據進行統計分析,提取出我們想要的信息。 怎么拿到接口...
摘要:最近棧長看到一個框架,官方號稱可以比快倍,居然這么牛逼,有這么神奇嗎今天帶大家來認識一下。官網簡介很簡單,翻譯過來就是一個快速輕量級和更高效的微服務框架。 最近棧長看到一個框架,官方號稱可以比 Spring Boot 快 44 倍,居然這么牛逼,有這么神奇嗎?今天帶大家來認識一下。 這個框架名叫:light-4j。 官網簡介:A fast, lightweight and more p...
摘要:在領域,有兩大主流的安全框架,和。角色角色是一組權限的集合。安全框架的實現注解的實現本套安全框架一共定義了四個注解。該注解用來告訴安全框架,本項目中所有類所在的包,從而能夠幫助安全框架快速找到類,避免了所有類的掃描。 寫在最前 本文是《手把手項目實戰系列》的第三篇文章,預告一下,整個系列會介紹如下內容: 《手把手0基礎項目實戰(一)——教你搭建一套可自動化構建的微服務框架(Sprin...
摘要:下面我們來測試一下,訪問我們經過修改后的編寫的接口這里我將返回值統一為,以便數據存入,實際類型應是接口的返回類型。如果沒有返回值的話,那就可以一個對象直接通過構造方法賦值即可。 為什么要統一返回值 在我們做后端應用的時候,前后端分離的情況下,我們經常會定義一個數據格式,通常會包含code,message,data這三個必不可少的信息來方便我們的交流,下面我們直接來看代碼 ReturnV...
閱讀 3406·2021-11-24 09:39
閱讀 1797·2021-11-17 09:33
閱讀 3503·2021-10-12 10:12
閱讀 5019·2021-09-22 15:51
閱讀 1112·2019-08-30 13:11
閱讀 3572·2019-08-30 10:59
閱讀 564·2019-08-30 10:48
閱讀 1311·2019-08-26 13:48