springboot 統一異常處理(包含統一數據校驗)

一、統一異常處理的優點前端

在開發中,咱們是否遇到過以下兩種奇葩現象:java

(1)只要沒有成功,無論什麼緣由,前端界面給出提示:服務端錯誤/異常。哪怕是數據校驗不過,也這樣提示(嗯,反正先把鍋甩出去再說,具體什麼緣由我纔不在意呢,老子就是這麼聰明);spring

若是想學習Java工程化、高性能及分佈式、深刻淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友能夠加個人Java高級交流:787707172,羣裏有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給你們。後端

(2)前端不作任何提示,一切提示信息都來自後端,成功的時候天然沒什麼,失敗的時候,好比將Exception的描述信息(e.getMessage)返回。springboot

現象(1)沒什麼好說的,直接拖出去槍斃吧;現象(2)先把產品經理宰了再說吧,看起來好像很專業的樣子,出了什麼問題直接看response返回的結果就知道個大概,研發測試都很方便,只是,你們想過沒有,研發測試運維的問題,憑什麼要用戶買單,你見過淘寶京東有時候出了問題給你相似於「out of memory」的異常提示嗎?架構

那麼異常統一處理有什麼好處呢?mvc

提升用戶體驗;app

業務邏輯和異常處理邏輯解耦;運維

對異常進行分類統一處理,減小冗餘代碼;分佈式

便於代碼風格統一,而且更優雅(好比參數校驗的時候,得寫不少if else,而且不一樣的人寫法不一致);

二、統一異常處理的實現

2.1 springboot的默認異常處理

Spring Boot提供了一個默認的映射:/error,當處理中拋出異常以後,會轉到該請求中處理,而且該請求有一個全局的錯誤頁面用來展現異常內容。

好比:

@RestController
public class Test {
 @RequestMapping(value = {"/test"},method = RequestMethod.GET)
 public String test(@RequestParam("id")Integer id){
 return "id:"+id;
 }
}

運行後訪問結果以下:

springboot 統一異常處理(包含統一數據校驗)

 

 

這種直接返回錯誤頁面,對於用戶而言,顯然是太不友好了哈!

2.2 統一異常處理

java異常詳解

首先,定義本身的異常類,隨便起個名字哈,MyException.java

@Data

public class MyException extends Exception{
 
 private Integer code;
 private String Message;
 
 public MyException(Integer code,String Message) {
 this.code = code;
 this.Message = Message;
 }
}

而後定義本身的異常處理類,ExceptionHandle.java

若是想學習Java工程化、高性能及分佈式、深刻淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友能夠加個人Java高級交流:787707172,羣裏有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給你們。

若是返回的對象是JSON的話,能夠用@RestControllerAdvice

@ControllerAdvice

public class ExceptionHandle {
 
 private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
 
 @ExceptionHandler(value = Exception.class)
 @ResponseBody
 public Result handle(Exception e) {
 if (e instanceof MyException) {
 MyException myException = (MyException) e;
 return ResultUtil.error(boyException.getCode(), boyException.getMessage());
 }else {
 logger.error("【系統異常】{}", e);
 return new Result(-1, "未知錯誤");
 }
 }
}

三、統一異常處理源碼解析

3.1 註解源碼解析

java註解詳解

@ControllerAdvice

@ExceptionHandler

@RestControllerAdvice與@ExceptionHandler註解是sprngmvc中與異常捕獲與處理相關的註解,它的入口也是DispatcherServlet中的doDispatcher()方法中,以下:

this.processDispatchResult(processedRequest, 
response, mappedHandler, mv, (Exception)dispatchException);

後面會進入HandlerExceptionResolverComposite的resolveException方法,這個ExceptionHandlerResolverComposite包含三個ExcpetionHandlerResolver,是在springmvc中生成的,在springboot中其生成代碼以下:

 

@Bean
	public HandlerExceptionResolver handlerExceptionResolver() {
		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
		configureHandlerExceptionResolvers(exceptionResolvers);
		if (exceptionResolvers.isEmpty()) {
			addDefaultHandlerExceptionResolvers(exceptionResolvers);
		}
		extendHandlerExceptionResolvers(exceptionResolvers);
		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
		composite.setOrder(0);
		composite.setExceptionResolvers(exceptionResolvers);
		return composite;
	}

後面他會進入ExceptionHandlerExceptionResolver類的方法:

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
			HttpServletResponse response, @Nullable HandlerMethod handlerMethod,
 Exception exception) {
 
		 ServletInvocableHandlerMethod exceptionHandlerMethod = 
 getExceptionHandlerMethod(handlerMethod, exception);
 }

在這個方法中的第一行,getExceptionHandlerMethod方法,其進行了查找對應的帶有@ControllerAdvice註解的類型和對應匹配的方法,而後在doResolverHandlerMethod方法中進行了處理,這就是整個流程。

@ControllerAdvice的加載過程:

首先在springboot掃描的時候,會把@ControllerAdvice的bean放入到beanFactory裏面去,此時只要從beanFactory中獲取到須要的bean便可,處理方式在ExceptionHandlerExceptionResolver類中:

@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBodyAdvice beans
		initExceptionHandlerAdviceCache();
	private void initExceptionHandlerAdviceCache() {
		if (getApplicationContext() == null) {
			return;
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for exception mappings: " + getApplicationContext());
		}
 
		List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

封裝好後,獲取帶有@Exceptionhandler的註解方法,即根據異常類型進行調用了。

歡迎工做一到八年的Java工程師朋友們加入Java高級交流:787707172

本羣提供免費的學習指導 架構資料 以及免費的解答

不懂得問題均可以在本羣提出來 以後還會有直播平臺和講師直接交流噢

相關文章
相關標籤/搜索