阅读 229

RuoYi-Vue 前后端分离版代码浅析-全局异常捕捉

前言

本节介绍RuoYi-Vue的模块中如何使用全局异常捕捉,全局异常捕捉对于每个项目而言都是必须的,在它的帮助下我们可以集中精力进行业务代码的开发,不用考虑异常的处理,所有的异常都可以由这里进行捕获之后统一处理。 ruoyi中使用的是@RestControllerAdvice,它相对@ControllerAdvice,减少了@ResponseBody注解,只需要在具体方法上添加@ExceptionHandler注解,对于我们现在前后端分离的代码而言,直接使用@RestControllerAdvice即可。

@RestControllerAdvice

一般来说我们的RestControllerAdvice必须的处理方法有以下几种

自定义验证异常

它主要是处理@Validated错误的,用来将返回的验证消息格式成我们已经写好的返回类。MethodArgumentNotValidExceptionBindException的子类。

/**  * 自定义验证异常  */ @ExceptionHandler(BindException.class) public AjaxResult handleBindException(BindException e) {     log.error(e.getMessage(), e);     String message = e.getAllErrors().get(0).getDefaultMessage();     return AjaxResult.error(message); } /**  * 验证异常  */ @ExceptionHandler(MethodArgumentNotValidException.class) public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {     log.error(e.getMessage(), e);     String message = e.getBindingResult().getFieldError().getDefaultMessage();     return AjaxResult.error(message); } 复制代码

这里还有另外一个异常ConstraintViolationException也可以进行捕捉自定义验证异常,不过是在 javax.validation包中,而不是像上面两个异常在spring中,上面两个异常其实也不在一个包里。

业务异常

我们一般也会自定义一个业务异常,当逻辑上有问题时会使用这个异常向外抛出错误

/**  * 业务异常  */ @ExceptionHandler(ServiceException.class) public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) {     log.error(e.getMessage(), e);     Integer code = e.getCode();     return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); } 复制代码

系统异常

这一般是用来进行兜底的,如果其他的都拦不住的时候就要用系统异常来进行拦截了。

/**  * 系统异常  */ @ExceptionHandler(Exception.class) public AjaxResult handleException(Exception e, HttpServletRequest request) {     String requestURI = request.getRequestURI();     log.error("请求地址'{}',发生系统异常.", requestURI, e);     return AjaxResult.error(e.getMessage()); } 复制代码

多个异常调用顺序

AbstractHandlerMethodExceptionResolver 是处理异常的抽象基础类,它是对HandlerExceptionResolver 这个接口的实现,继承了AbstractHandlerExceptionResolver

image.png 处理位置是

image.png 中的doResolveHandlerMethodException

image.png 在获取getExceptionHandlerMethod这里会根据错误类型来找对应能处理的方法 image.png

@Nullable public Method resolveMethodByThrowable(Throwable exception) {    Method method = resolveMethodByExceptionType(exception.getClass());    if (method == null) {       Throwable cause = exception.getCause();       if (cause != null) {          method = resolveMethodByThrowable(cause);       }    }    return method; } @Nullable public Method resolveMethodByExceptionType(Class<? extends Throwable> exceptionType) {    Method method = this.exceptionLookupCache.get(exceptionType);    if (method == null) {       method = getMappedMethod(exceptionType);       this.exceptionLookupCache.put(exceptionType, method);    }    return (method != NO_MATCHING_EXCEPTION_HANDLER_METHOD ? method : null); } 复制代码

这里的重点是用getMappedMethod来使用ExceptionDepthComparator这个比较器来找到最接近的比较器对这个Throwable来进行处理。

image.png

image.png 可以看到在getDepth这里是使用了一个递归来查深度的,

多个@RestControllerAdvice加载顺序

如果我们引用的别的api包中已经有了@RestControllerAdvice,每次都调用了它的处理,我们想改为自己的,可以使用@Order(Ordered.HIGHEST_PRECEDENCE)注解,将我们的处理类提升,但是一般来说不要这样做,可能会将别人的处理类覆盖掉,所以一定要做的话一定要将我们的处理的Exception写的越细越好,这样不会影响原有逻辑,防止处理了别人的逻辑。


作者:临时营地
链接:https://juejin.cn/post/7029158877224501279


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐