springMVC 統一異常處理的一種方式
阿新 • • 發佈:2018-12-21
後端發生異常的時候,如果不處理,返回前段的會是printStackTrace()打出來的結果,會洩露我們伺服器程式碼資訊,可能會被利用攻擊,所以需要一個統一的異常處理機制。
解決方案 @ExceptionHandler 和@ControllerAdvice 註解,在一個檔案中處理所有異常型別,並介面返回固定格式。
@ControllerAdvice public class WebExceptionHandle { @ExceptionHandler(DataAccessException.class) @ResponseBody ResultDTO handleSqlException(Exception e){ // 處理sql異常 return ResultDTO.faileResult(null,"sql failed"); } @ExceptionHandler() @ResponseBody ResultDTO handleException(Exception e){ //預設異常處理 return ResultDTO.faileResult(null,"sql failed"); }
}
博文:https://blog.csdn.net/liujia120103/article/details/75126124 給出了這2個註解的解釋,但沒有說明具體如何能捕獲異常並處理的,通過除錯觀察呼叫堆疊,發現是通過springMVC 的handlerExceptionResolvers.resolveException後呼叫的。這個處理過程應該是如下:
- spring在啟動過程通過註解@ExceptionHandler將 方法封裝成bean並注入到handlerExceptionResolvers的集合中
- 當controller執行完成後,執行processDispatchResult對結果進行處理
- 呼叫processHandlerException 方法,遍歷handlerExceptionResolvers,執行handlerExceptionResolver.resolveException方法。
springMVC過程
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { try { try { ModelAndView mv = null; Object dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this.getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); ...... // web的前置處理器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 執行controller的對應方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, mv); // web的後置處理器 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed", var21); } //處理controller的執行結果 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); } catch (Exception var22) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
processDispatchResult 中執行processHandlerException方法
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
ModelAndView exMv = null;
Iterator var6 = this.handlerExceptionResolvers.iterator();
while(var6.hasNext()) {
HandlerExceptionResolver handlerExceptionResolver = (HandlerExceptionResolver)var6.next();
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
} else {
if (!exMv.hasView()) {
exMv.setViewName(this.getDefaultViewName(request));
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, this.getServletName());
return exMv;
}
} else {
throw ex;
}
}