springboot项目异常捕捉实例

实现思路

  1. 使用@RestControllerAdvice注解,定义系统全局异常捕捉类,捕捉系统全局异常
  2. 继承RuntimeException类,定义业务异常类,用于业务打断

异常捕捉演示

  1. 下载源代码,github源码链接
  2. 项目启动,调用/test/exception接口
  • 自定义异常
    在这里插入图片描述
  • 全局异常捕捉
    在这里插入图片描述

关键业务代码

  1. 系统全局异常捕捉
/**
 * 系统全局异常捕捉
 */
@Slf4j
@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(ErrorCodeException.class)
    @ResponseBody
    public ResultBean handleErrorCodeException(ErrorCodeException e) {

        Integer code = e.getErrorCode();
        String msg = e.getMessage();

        // 外部传入了消息描述,这个地方就不再覆盖了
        if (!StringUtils.hasLength(msg)) {
            msg = "服务器正忙,请稍后重试。";
        }

        if (e instanceof BusinessException) {
            log.info("Business exception : msg {} : code {}", msg, code);
        } else {
            log.error("ErrorCodeException exception : msg {}", msg, e);
        }

        return ResultBean.error(code, msg);
    }

    /**
     * 空指针
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public ResultBean nullPointerException(NullPointerException e) {
        log.error("发生空指针异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 类型强制转换异常
     */
    @ExceptionHandler(value = ClassCastException.class)
    @ResponseBody
    public ResultBean classCastException(ClassCastException e) {
        log.error("类型强制转换异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 数组下标越界异常
     */
    @ExceptionHandler(value = ArrayIndexOutOfBoundsException.class)
    @ResponseBody
    public ResultBean arrayIndexOutOfBoundsException(ArrayIndexOutOfBoundsException e) {
        log.error("数组下标越界异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 字符串转换为数字异常
     */
    @ExceptionHandler(value = NumberFormatException.class)
    @ResponseBody
    public ResultBean numberFormatException(NumberFormatException e) {
        log.error("字符串转换为数字异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 输入输出异常
     */
    @ExceptionHandler(value = IOException.class)
    @ResponseBody
    public ResultBean IOException(IOException e) {
        log.error("输入输出异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 方法未找到异常
     */
    @ExceptionHandler(value = NoSuchMethodException.class)
    @ResponseBody
    public ResultBean noSuchMethodException(NoSuchMethodException e) {
        log.error("方法未找到异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(value = SystemException.class)
    @ResponseBody
    public ResultBean systemException(SystemException e) {
        log.error("系统异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 非法参数异常
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    @ResponseBody
    public ResultBean IllegalArgumentException(IllegalArgumentException e) {
        log.error("非法参数异常!原因是:", e);
        return ResultBean.error(HttpStatus.BAD_REQUEST.value(), e.toString());
    }

    /**
     * 不支持的操作异常
     */
    @ExceptionHandler(value = UnsupportedOperationException.class)
    @ResponseBody
    public ResultBean unsupportedOperationException(UnsupportedOperationException e) {
        log.error("不支持的操作异常!原因是:", e);
        return ResultBean.error(HttpStatus.BAD_REQUEST.value(), e.toString());
    }

    /**
     * 操作数据库异常
     */
    @ExceptionHandler(value = SQLException.class)
    @ResponseBody
    public ResultBean sqlException(SQLException e) {
        log.error("操作数据库异常!原因是:", e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 参数校验失败
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public ResultBean handlerConstraintViolationException(BindException e) {
        log.warn(e.getMessage(), e);

        if (!e.getAllErrors().isEmpty()) {
            String msg = e.getAllErrors().get(0).getDefaultMessage();
            return ResultBean.error(HttpStatus.BAD_REQUEST.value(), msg);
        } else {
            return ResultBean.error(HttpStatus.BAD_REQUEST.value(), e.toString());
        }

    }

    /**
     * 方法参数无效异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResultBean handlerArgumentNotValidException(MethodArgumentNotValidException e) {
        log.warn(e.getMessage(), e);

        if (!e.getBindingResult().getAllErrors().isEmpty()) {
            String msg = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
            return ResultBean.error(HttpStatus.BAD_REQUEST.value(), msg);

        } else {
            return ResultBean.error(HttpStatus.BAD_REQUEST.value(), e.toString());
        }
    }

    /**
     * Internal Server Error 500
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResultBean handlerException(Exception e) {
        log.error(e.getMessage(), e);
        return ResultBean.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.toString());
    }

    /**
     * 404异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ResponseBody
    public ResultBean noHandlerFoundException(NoHandlerFoundException e) {
        return ResultBean.error(HttpStatus.NOT_FOUND.value(),  e.toString());
    }
}

本文定义了常见的全局异常,有兴趣的小伙伴,可以根据业务增加其他的异常。

  1. 业务异常类,用于业务打断
/**
 * 业务异常类,只用于业务打断
 */
public class BusinessException extends ErrorCodeException {

    private static final long serialVersionUID = -45155154531465551L;

    public BusinessException(Integer businessErrorCode) {
        super(businessErrorCode);
    }

    public BusinessException(Integer businessErrorCode, String message, Throwable cause) {
        super(businessErrorCode, message, cause);
    }

    public BusinessException(Integer businessErrorCode, String message) {
        super(businessErrorCode, message);
    }

    public BusinessException(Integer businessErrorCode, Throwable cause) {
        super(businessErrorCode, cause);
    }

    public BusinessException(Integer businessErrorCode, String message, Object result) {
        super(businessErrorCode, message, result);
    }

    public BusinessException(ResultCode resultCode) {
        this(resultCode.getCode(), resultCode.getMsg());
    }

    public BusinessException(ResultCode resultCode, Throwable cause) {
        this(resultCode.getCode(), resultCode.getMsg(), cause);
    }

    public static void throwException(ResultCode resultCode) {
        throw new BusinessException(resultCode);
    }

    public static void throwException(ResultCode resultCode,Throwable cause) {
        throw new BusinessException(resultCode, cause);
    }

    @Override
    public String getMessage() {
        return super.getMessage();
    }
}

/**
 * 含错误码的异常类
*/
public class ErrorCodeException extends RuntimeException {

	private static final long serialVersionUID = -21116129021561225L;

	// 错误码
	private Integer errorCode;

	// 异常结果返回
	private Object result;

	public ErrorCodeException(Integer errorCode) {
		this(errorCode, null, null);
	}

	public ErrorCodeException(Integer errorCode, String message) {
		this(errorCode, message, null);
	}

	public ErrorCodeException(Integer errorCode, Throwable cause) {
		this(errorCode, null, cause);
	}

	public ErrorCodeException(Integer errorCode, String message, Throwable cause) {
		super(message, cause);
		this.errorCode = errorCode;
	}

	public ErrorCodeException(Integer errorCode, String message,Object result) {
		super(message);
		this.errorCode = errorCode;
		this.result = result;
	}


	public Integer getErrorCode() {
		return errorCode;
	}

	@Override
	public String getMessage() {
		return super.getMessage();
	}

	public Object getResult(){
		return this.result;
	}
}
  1. 异常捕捉测试类
@Service
public class TestServiceImpl implements TestService {

    @Override
    public ResultBean test(int type) {

        if (1 == type) {
            throw new BusinessException(ResultCode.INTERNAL_SERVER_ERROR);
        } else if (2 == type) {
            int a = 1 / 0;
        } else if (3 == type) {
            Integer[] arr = {1, 2};
            int a = arr[2];
        } else if (4 == type) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            int a = list.get(2);
        } else if (5 == type) {
            String a = "12.5662";
            Integer b = Integer.parseInt(a);
        } else if (6 == type) {
            Map<String, Object> map = null;
            map.size();
        } else if (7 == type) {
            String a = "hello world";
            Map map = JSON.parseObject(a, Map.class);
        } else if (8 == type) {
            List<String> list = null;
            list.contains("a");
        } else if (9 == type) {
            Integer[] arr = new Integer[1];
            arr[0] = 1;
            arr[1] = 2;
        } else {
            int a = 1 + 1;
        }

        return ResultBean.success();
    }
}