@ControllerAdvice的异常捕获与响应增强处理

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

原文地址:https://www.cnblogs.com/MrSi/p/13512223.html