SpringBoot 全局异常拦截捕获处理
本篇文章主要介绍的是SpringBoot项目进行全局异常的处理。
SpringBoot的项目已经对有一定的异常处理了,但是对于我们开发者而言可能就不太合适了,因此我们需要对这些异常进行统一的捕获并处理。SpringBoot 中有一个ControllerAdvice的注解,使用该注解表示开启了全局异常的捕获,我们只需在自定义一个方法使用ExceptionHandler注解然后定义捕获异常的类型即可对这些捕获的异常进行统一的处理。
首先定义一个基础的接口类,自定义的错误描述枚举类需实现该接口
public interface BaseErrorInfoInterface {
/**
* 错误码
*/
String getCode();
/**
* 错误描述
*/
String getMsg();
}
然后我们这里在自定义一个枚举类,并实现该接口。
public enum ExceptionEnum implements BaseErrorInfoInterface {
SUCCESS("200", "请求成功"),
BODY_NOT_MATCH("400", "请求的数据格式不符"),
NUMBER_FORMAT_ERROR("401", "类型转换异常"),
CLASS_NOT_FOUND_ERROR("402", "类不存在异常"),
NO_SUCH_METHOD_ERROR("403", "方法未找到异常"),
NOT_FOUND("404", "未找到该资源"),
CLASS_CIRCULARITY_ERROR("405", "类循环依赖异常"),
ILLEGAL_ACCESS_ERROR("406", "违法访问异常"),
VIRTUAL_MACHINE_ERROR("407", "虚拟机错误"),
SERVER_ERROR("500", "服务器异常"),
SERVER_BUSY("503", "服务器正忙,请稍后再试");
/**
* 错误码
*/
private String code;
/**
* 错误描述
*/
private String msg;
ExceptionEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String getCode() {
return code;
}
@Override
public String getMsg() {
return msg;
}
}
自定义一个异常类,用于处理我们发生的业务异常
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
protected String errorCode;
/**
* 错误信息
*/
protected String errorMsg;
public BizException() {
super();
}
public BizException(BaseErrorInfoInterface errorInfoInterface) {
super(errorInfoInterface.getCode());
this.errorCode = errorInfoInterface.getCode();
this.errorMsg = errorInfoInterface.getMsg();
}
public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
super(errorInfoInterface.getCode(), cause);
this.errorCode = errorInfoInterface.getCode();
this.errorMsg = errorInfoInterface.getMsg();
}
public BizException(String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg) {
super(errorCode);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg, Throwable cause) {
super(errorCode, cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
@Override
public String toString() {
return "BizException{" +
"errorCode='" + errorCode + '\'' +
", errorMsg='" + errorMsg + '\'' +
'}';
}
@Override
public String getMessage() {
return errorMsg;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}
定义一下数据的响应格式
public class Response {
protected String code;
protected String message;
protected Object data;
public Response() {
}
public Response(String code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
public Response(BaseErrorInfoInterface errorInfo) {
this.code = errorInfo.getCode();
this.message = errorInfo.getMsg();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/**
* 成功
*/
public static Response success() {
return success(null);
}
/**
* 成功
*/
public static Response success(Object data) {
return success(ExceptionEnum.SUCCESS.getMsg(), data);
}
/**
* 成功
*/
public static Response success(String message, Object data) {
return new Response(ExceptionEnum.SUCCESS.getCode(), message, data);
}
/**
* 失败
*/
public static Response error(BaseErrorInfoInterface errorInfo) {
Response rb = new Response();
rb.setCode(errorInfo.getCode());
rb.setMessage(errorInfo.getMsg());
rb.setData(null);
return rb;
}
/**
* 失败
*/
public static Response error(String code, String message) {
Response rb = new Response();
rb.setCode(code);
rb.setMessage(message);
rb.setData(null);
return rb;
}
/**
* 失败
*/
public static Response error(String message) {
Response rb = new Response();
rb.setCode("-100");
rb.setMessage(message);
rb.setData(null);
return rb;
}
@Override
public String toString() {
return JSONObject.toJSONString(this);
}
}
自定义全局异常处理类
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理自定义的业务异常
*/
@ExceptionHandler(value = BizException.class)
@ResponseBody
public Response bizExceptionHandler(HttpServletRequest req, BizException e) {
log.error("发生业务异常!原因是:{}", e.getErrorMsg());
return Response.error(e.getErrorCode(), e.getErrorMsg());
}
/**
* 处理空指针的异常
*/
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, NullPointerException e) {
log.error("发生空指针异常!原因是:", e);
return Response.error(ExceptionEnum.BODY_NOT_MATCH);
}
/**
* 类型转换异常
*/
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, NumberFormatException e) {
log.error("字符串转换为数字异常:", e);
return Response.error(ExceptionEnum.NUMBER_FORMAT_ERROR);
}
/**
* 指定的类不存在异常
*/
@ExceptionHandler(value = ClassNotFoundException.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, ClassNotFoundException e) {
log.error("指定的类不存在异常:", e);
return Response.error(ExceptionEnum.CLASS_NOT_FOUND_ERROR);
}
/**
* 方法未找到异常
*/
@ExceptionHandler(value = NoSuchMethodException.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, NoSuchMethodException e) {
log.error("方法未找到异常:", e);
return Response.error(ExceptionEnum.NO_SUCH_METHOD_ERROR);
}
/**
* 类循环依赖异常
*/
@ExceptionHandler(value = ClassCircularityError.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, ClassCircularityError e) {
log.error("类循环依赖异常:", e);
return Response.error(ExceptionEnum.CLASS_CIRCULARITY_ERROR);
}
/**
* 违法访问异常
* 当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常
*/
@ExceptionHandler(value = IllegalAccessError.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, IllegalAccessError e) {
log.error("违法访问异常:", e);
return Response.error(ExceptionEnum.ILLEGAL_ACCESS_ERROR);
}
/**
* 虚拟机错误
* 用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况
*/
@ExceptionHandler(value = VirtualMachineError.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, VirtualMachineError e) {
log.error("虚拟机错误:", e);
return Response.error(ExceptionEnum.VIRTUAL_MACHINE_ERROR);
}
/**
* 处理其他异常
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Response exceptionHandler(HttpServletRequest req, Exception e) {
log.error("服务器异常:", e);
return Response.error(ExceptionEnum.SERVER_ERROR);
}
}
下面编写一个测试类
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
/**
* 测试
*/
@PostMapping("/test1")
public Response test1(@RequestParam("parm1") String parm1,
@RequestParam("parm2") String parm2) {
log.info("测试参数:{}", parm1);
log.info("测试参数:{}", parm2);
List<TCommonDict> dictAll = dictMapper.selectAll();
return Response.success(dictAll);
}
@GetMapping("/test2")
public Response test2(@RequestParam("parm1") String parm1,
@RequestParam("parm2") String parm2) {
System.out.println("如果parm1为空就手动抛出一个自定义的异常");
if (StringUtils.isEmpty(parm1)) {
throw new BizException(ExceptionEnum.BODY_NOT_MATCH.getCode(), "参数parm1不能为空!");
}
return Response.success();
}
@GetMapping("/test3")
public Response test3(@RequestParam("parm1") String parm1,
@RequestParam("parm2") String parm2) {
System.out.println("这里故意造成一个空指针的异常,并且不进行处理");
parm1 = null;
parm1.equals("111");
return Response.success();
}
@GetMapping("/test4")
public Response test4(@RequestParam("parm1") String parm1,
@RequestParam("parm2") String parm2) {
System.out.println("这里故意造成一个string转换integer异常");
Integer.parseInt(parm1);
return Response.success();
}
}
下面是i调用接口出现的异常
至此 springboot整合 全局异常处理完毕