做WEB項目,發展到現在,前后端分離的框架已經成為主流。面對前后端分離項目,基本思路都是后端提供restful接口,前端接受數據往組件上綁定(vue)。但是想要把框架做好,接口、數據的統一是繞不開的話題,這是基礎中的基礎。本篇內容將先分析springboot框架下的ControllerAdvice是怎樣對異常、response進行統一攔截處理的。而后會附上一篇示例代碼,用程序來講述其運用。
下面這張圖是我跟蹤源碼后簡單畫下來的(源碼內容過多不宜粘貼),只求達意,並不是完整的運行流程。需要知道的是ResponseBodyAdvice是在將數據最終寫入response流前發生的,一定在異常處理的后面。
源碼:查詢Bean工廠中的ControllerAdvice類型的Bean
源碼:對ControllerAdviceBean進行解析,獲取繼承自ResponseBodyAdvice的Bean,解析有異常處理程序的Bean
接下來附上我的測試示例。其作用一是捕獲自己定義的業務校驗類異常,二是將restful接口的返回值統一封裝成 JsonResult 這樣的一個對象。前端項目在解析接口返回值的時候,不管是異常還是正常數據,其基礎結構都是一致的,偏於編寫統一處理的代碼。(小東西,用途很大)東西比較簡單,不細說了,大家看看就好。
一、異常捕獲
/** * @author simm */ @ControllerAdvice public class MyExceptionHandlerAdvice { /** * 處理業務異常 * @param request * @param response * @param handler * @param ex * @return */ @ExceptionHandler(BizException.class) @ResponseBody JsonResult handleBizException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handler, Throwable ex) { JsonResult result = new JsonResult(false); result.error(ex.getMessage()); return result; } /** * 處理業務異常 * @param request * @param response * @param handler * @param ex * @return */ @ExceptionHandler(Exception.class) @ResponseBody JsonResult handleException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handler, Throwable ex) { JsonResult result = new JsonResult(false); result.error(Throwables.getStackTraceAsString(ex)); return result; } }
二、responsebody統一封裝
/** * 數據返回結構統一組裝 * * @author simm */ @ControllerAdvice public class MyResponseBodyAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; } /** * 處理string轉換器 */ private final static String HTTP_MESSAGE_CONVERTER = "StringHttpMessageConverter"; @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if(JsonResult.class.isAssignableFrom(body.getClass())){ //異常已經被包裝 return body; } //將返回值包裝成jsonresult結構 JsonResult<Object> jsonResult = new JsonResult<>(true); jsonResult.setData(body); // if (selectedConverterType.getSimpleName().contains(HTTP_MESSAGE_CONVERTER)) { // return JSON.toJSONString(jsonResult); // } return jsonResult; } }
三、拋個業務異常試試
/** * 測試異常 * @author simm */ @Controller @RequestMapping("exception") public class ExceptionTestController { /** * 拋出業務異常 * @return */ @RequestMapping("/biz") @ResponseBody public Object biz() { throw new BizException("這是我的自定義異常"); } /** * 拋出程序異常 * @return */ @RequestMapping("/process") @ResponseBody public Object process() { int i = 0; int j = 100/0; return true; } }