前言
全局异常处理可以帮助我们拦截接口的报错,返回调用方友好的提示,提高了用户体验的同时,还为我们排查异常提供了便利。
那么如何定义一个全局异常处理呢?它又是怎样帮助我们处理异常,并返回友好提示的呢?咱们肺部哆嗦,直接开搞!
注解说明
本次我们需要用到两个核心注解:
1、@ControllerAdvice
:此注解是从Spring3.2版本开始新增的,顾名思义,它是一个控制器增强通知,官方解释说可以与@ExceptionHandler
、@InitBinder
、@ModelAttribute
注解组合使用
而默认情况下,此方法应用于所有控制器中,如果想定制化作用于部分控制器,可以使用basePackageClasses
、basePackages
属性来框定包的范围
此注解还有一个兄弟@RestControllerAdvice
,查看源码可以知道,它是@ControllerAdvice
+@ResponseBody
的组合注解,新增于Spring4.3版本
2、@ExceptionHandler
:此注解从名字上看也能知道就是一个异常处理器(见名知意了属于是),用于处理指定类的特定异常。我们可以通过设置它的value属性,来指定处理的异常类型
准备工作
所谓的准备工作就是定义一下接口统一返回,和自定义异常。这在项目开发中很常见,这里就简单的贴一下代码内容
首先就是接口统一返回:这在每个人的项目中都会有自己的定义,但都大同小异,这边简单的封装一下
然后就是自定义异常:这边同样的简单封装一个,项目中可以根据不同的业务,定义不同的异常类型
到此,准备工作就已完成,接下来就是主角:全局异常处理类
全局异常处理器
第一步就是创建一个全局异常处理类,并加上@RestControllerAdvice
注解,Spring版本低于4.3的可以用@ControllerAdvice
+@ResponseBody
的组合注解,如果版本低于3.2的朋友,那建议升级一下版本
接下来就是定义异常处理,要用到@ExceptionHandler
注解
这里在注解中指定作用的异常类型为我们准备工作中自定义的异常,然后将异常信息封装成统一接口返回,msg为错误提示:可用于前端展示,detail则为错误描述:可方便接口错误排查定位
而其他异常类型,我们统一用Exception
概括。这里将异常的堆栈信息,拼接成字符串,放在detail中,方便排查异常,而msg则可以根据不同项目的业务来定义友好提示
到这一步,一个简单的全局异常处理类就算完成。完整代码如下:
package com.jorkeycloud.integration.exception;
import com.jorkeycloud.integration.entity.dto.ResultBody;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Arrays;
/**
* @author Jorkey
* @version v1.0
**/
@Slf4j
@RestControllerAdvice
public class WebGlobalExceptionHandler {
public WebGlobalExceptionHandler() {
log.info("new instance {}", WebGlobalExceptionHandler.class.getName());
}
@ExceptionHandler(SysException.class)
public ResultBody<?> sysException(SysException e) {
log.error(e.getMessage(), e);
Integer code = 500;
String msg = "系统走神了~";
String detail = null;
SysError sysError = e.getError();
if (sysError != null) {
if (sysError.getMessage() != null) {
msg = sysError.getMessage();
}
detail = sysError.getDetails();
}
return ResultBody.error(code, msg, detail);
}
@ExceptionHandler(Exception.class)
public ResultBody<?> handleException(Exception e) {
log.error(e.getMessage(), e);
Integer code = 500;
String msg = "系统走神了~";
String detail = null;
StringBuilder errorString = new StringBuilder(e.toString());
Arrays.stream(e.getStackTrace()).forEach(item -> {
errorString.append("。 ").append(item.getFileName()).append(": ").append(item.getMethodName())
.append(": ").append(item.getLineNumber());
});
if (errorString.length() > 0) {
detail = errorString.toString();
}
return ResultBody.error(code, msg, detail);
}
}
结果展示
写一个接口来模拟异常
然后用postman来调用接口,结果分别如下:
第一个异常只有提示,没有描述
第二个异常有提示,也有描述
第三个,主动抛出运行时异常
第四个,空指针异常
第五个,by zero异常
最后,成功返回
以上就是本次全局异常处理的全部内容,有疑问或者有更好方案的话,可以评论区讨论一下共同进步呀。
如果觉得写的不错,不妨点个赞支持一下~~