0、前言
任何系統,我們不會傻傻的在每一個地方進行例外捕獲和處理,整個系統一般我們會在一個的地方統一進行例外處理,spring boot全域例外處理很簡單;
介紹前先說點題外話,我們現在開發系統,都是前后端完全分離的,后端只提供RESTfull API,禁止涉及任何界面,什么thymeleaf、JSP那些后端模板,是絕對禁止使用的,那些東西請扔垃圾箱,不要浪費大好青春去研究,那是墮落;前端則負責界面相關,常用Vue;如果公司還沒前后端分離,還在thymeleaf還在前后端一起寫,那你還是早做跳槽打算吧,他們養不起你,更養不起你的家人;
前后端分離,后端API,一般對于例外處理,要做得無非兩件事,
1是記錄日志及相應通知處理,這是對內的,
2是給出回傳結果給API呼叫者,這是對外的;
對API呼叫者來說,他只需要一個回傳結果(包含錯誤代碼、提示資訊),其他的他不關心
對后端來說,他只需要記錄日志,通知或者給發布相應訊息給其他佇列處理相關事項;
所以:看到過不少人封裝了很多個自定義例外類,其實,完全沒有必要,只需要一個例外處理來處理所有例外即可,然后封裝一個錯誤識別碼和提示訊息的列舉,用于回傳給API呼叫者;然后后端的處理,直接在一個例外處理方法中全部處理就行了,完全沒必要封裝N多個自定義例外,那沒有任何意義;
0-1、關于例外的思想認識
我們應該認識到,一切例外,對系統來說,都是不正常的表現,都是屬于缺陷,都屬于BUG,盡管有些例外是我們主動拋出的;
我們要做的,是應該盡量提高系統可用性,最大限度避免任何例外的出現,而不是去指望完善例外處理來完善系統;
例外處理,是例外無法避免的出現了而采取的一種應急措施,主要目的是對外增加友好性,對內提供補救線索;
不要認為完善的例外處理是系統核心,他不是,不要指望例外處理盡善盡美,不要指望例外處理來給系統缺陷擦屁股;
如果系統例外過多,那么你要做的不是去完善例外處理機制,而是要好好去反思:系統架構設計是否合理,系統邏輯設計是否合理;
1、全域例外處理
使用@ControllerAdvice、@ExceptionHandler注解封裝一個例外處理類即可package com.anson.common.exception;import com.anson.common.result.ResultBody;import com.anson.common.result.ResultCode;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;/** * @description: 全域例外處理類 * @author: anson * @Date: 2019/12/17 20:56 */@ControllerAdvicepublic class GlobalExceptionHandler{ private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 所有例外處理 * @param e * @return */ @ExceptionHandler(value =Exception.class) @ResponseBody public ResultBody exceptionHandler(Exception e) { //1、寫日志及其他處理,對內 logger.error("未知例外!原因是:",e); System.out.println("未知例外!原因是:"+e); //2、回傳錯誤識別碼和提示給API呼叫者、對外 return ResultBody.failed(ResultCode.FAILED); }}
這樣就可以了,
ResultBody、ResultCode這個我們下節會說到;
-------------------華麗麗的分割線--------------------------2、自定義例外
上面的例外處理可以處理所有例外了,但是有時候,比如在攔截器、AOP、偵聽器中,我們要主動拋出特定例外,比如沒有權限、登錄過期等,這個時候,我們可以增加一個自動以例外來統一處理,如下:
2.1、增加一個自定義例外類:
package com.anson.common.exception;import com.anson.common.result.IErrorCode;/** * @description: 自定義例外類 * @author: anson * @Date: 2019/12/30 9:14 */public class BizException extends RuntimeException{ private static final long serialVersionUID = 1L; protected long errorCode; //錯誤碼 protected String errorMsg; //錯誤資訊 //構造1 public BizException() { super(); } //構造2 public BizException(IErrorCode errorInfoInterface) { super(String.valueOf(errorInfoInterface.getCode())); this.errorCode = errorInfoInterface.getCode(); this.errorMsg = errorInfoInterface.getMessage(); } public BizException(IErrorCode errorInfoInterface, Throwable cause) { super(String.valueOf(errorInfoInterface.getCode()), cause); this.errorCode = errorInfoInterface.getCode(); this.errorMsg = errorInfoInterface.getMessage(); } public BizException(String errorMsg) { super(errorMsg); this.errorMsg = errorMsg; } public BizException(long errorCode, String errorMsg) { super(String.valueOf(errorCode)); this.errorCode = errorCode; this.errorMsg = errorMsg; } public BizException(long errorCode, String errorMsg, Throwable cause) { super(String.valueOf(errorCode), cause); this.errorCode = errorCode; this.errorMsg = errorMsg; } public long getErrorCode() { return errorCode; } public void setErrorCode(long errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } public String getMessage() { return errorMsg; } @Override public Throwable fillInStackTrace() { return this; }}
2.2、在全域例外處理中增加處理自定義例外:
package com.anson.common.exception;import com.anson.common.result.ResultBody;import com.anson.common.result.ResultCode;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;/** * @description: 全域例外處理類 * @author: anson * @Date: 2019/12/10 20:56 */@ControllerAdvicepublic class GlobalExceptionHandler{ private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 1、處理自定義的業務例外 * @param req * @param e * @return */ @ExceptionHandler(value = BizException.class) @ResponseBody public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e){ logger.error("發生業務例外!原因是:{}",e.getErrorMsg()); return ResultBody.failed(e.getErrorCode(),e.getErrorMsg()); } /** * 2、處理其他例外 * @param e * @return */ @ExceptionHandler(value =Exception.class) @ResponseBody public ResultBody exceptionHandler(Exception e) {//1、寫日志及其他處理,對內 logger.error("未知例外!原因是:",e); System.out.println("未知例外!原因是:"+e); logger.trace("trace level"); logger.debug("debug level"); logger.info("info level"); logger.warn("warn level"); logger.error("error level"); long beginTime = System.currentTimeMillis(); logger.info("請求處理結束,耗時:{}毫秒", (System.currentTimeMillis() - beginTime)); //第一種用法 logger.info("請求處理結束,耗時:" + (System.currentTimeMillis() - beginTime) + "毫秒"); //第二種用法//------------------------------//2、回傳錯誤識別碼和提示給API呼叫者、對外 return ResultBody.failed(ResultCode.FAILED); }}
2.3、然后,在需要的地方上拋例外即可
//主動拋出自定義例外 throw new BizException(ResultCode.UNAUTHORIZED.getCode(),ResultCode.UNAUTHORIZED.getMessage());
運行后即可看到上拋了自定義例外:

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/29194.html
標籤:架構設計
下一篇:Springboot 專案原始碼 Activiti6 作業流 vue.js html 跨域 前后分離 websocket即時通訊
