做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; } }