SpringBoot全局异常捕获及自定义异常

1. 新建ApiResult作为通用返回对象

// package vo
@Data
public class ApiResult<T> implements Serializable
{
	/**
	 * 状态码
	 */
	private Integer code;
	/**
	 * 错误码
	 */
	private String errorCode;
	/**
	 * 错误描述
	 */
	private String errorDesc;
	/**
	 * 数据
	 */
	private T data;

	public ApiResult(Integer code, String errorCode, String errorDesc, T data) {
		this.code = code;
		this.errorCode = errorCode;
		this.errorDesc = errorDesc;
		this.data = data;
	}


	public static <T> ApiResult<T> success() {
		return new ApiResult<T>(0, null, null, null);
	}

	public static <T> ApiResult<T> success(T data) {
		return new ApiResult<T>(0, null, null, data);
	}

	public static <T> ApiResult<T> error(String errorCode, String errorDesc) {
		return new ApiResult<T>(1, errorCode, errorDesc, null);
	}

	public static <T> ApiResult<T> error(String errorCode, String errorDesc, T data) {
		return new ApiResult<T>(1, errorCode, errorDesc, data);
	}
}

2. 新建错误枚举类

// package exception
public enum CommonErrorEnum
{	// 10000通用错误
	UNKNOWN_ERROR("BYSJ-10001","未知错误"),
	PARAMETER_VALIDATION_ERROR("BYSJ-10002","参数不合法"),
	ADD_FAIL("BYSJ-10004","添加失败"),
	DELETE_FAIL("BYSJ-10005","删除失败"),
	UPDATE_FAIL("BYSJ-10006","更新失败"),
	FIND_FAIL("BYSJ-10007","资源不存在"),
	;

    // 错误码
	private String errorCode;
    // 错误描述
	private String errorDesc;

	CommonErrorEnum(String errorCode, String errorDesc) {
		this.errorCode = errorCode;
		this.errorDesc = errorDesc;
	}

	public String getErrorCode() {
		return errorCode;
	}

	public String getErrorDesc() {
		return errorDesc;
	}
    
    // 自定义错误描述
    public CommonErrorEnum setErrorDesc(String errorDesc) {
        this.errorDesc = errorDesc;
        return this;
    }

	public BusinessException getBusinessException(){
		return new BusinessException(this);
	}
}

3. 自定义异常类

// package exception
class BusinessException extends RuntimeException
{
	private CommonErrorEnum commonErrorEnum;

	BusinessException(CommonErrorEnum commonErrorEnum) {
		super();
		this.commonErrorEnum = commonErrorEnum;
	}

	String getErrorCode() {
		return commonErrorEnum.getErrorCode();
	}

	String getErrorDesc() {
		return commonErrorEnum.getErrorDesc();
	}
}

自定义异常继承RuntimeException而不是Exception是因为运行时异常不需要捕获,也不需要做对应处理。具体继承谁还是根据业务来,这里不多概述。

4. 新建全局异常类

// package exception
@RestControllerAdvice(basePackages = "com.hbue.bysj.*", annotations = Controller.class)
public class GlobalExceptionHandler
{
	/**
	 * 捕获业务异常
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(BusinessException.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult handleBusinessException(Exception ex) {
		BusinessException businessException = (BusinessException)ex;
		return ApiResult.error(businessException.getErrorCode(), businessException.getErrorDesc());
	}

	/**
	 * 捕获其他异常
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(Exception.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult handleException(Exception ex) {
		ex.printStackTrace();
		return ApiResult.error(CommonErrorEnum.UNKNOWN_ERROR.getErrorCode(), CommonErrorEnum.UNKNOWN_ERROR.getErrorDesc());
	}
}

全局异常类中可以捕获多种异常,并做对应的处理,建议分开写,不要直接用Exception为条件捕获所有异常,然后再使用instanceof来判断具体的异常类型。


补充:对于某些不处于Controller层的异常,例如文件尺寸过大异常,就不能被Controller捕获器捕获,可以用下面的方法捕获:

@RestControllerAdvice
public class FileSizeExceptionHandler
{
	// 设定上传大小3MB 超出大小捕获异常MaxUploadSizeExceededException
	@ExceptionHandler(MaxUploadSizeExceededException.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult handleMaxUploadSizeExceededException() {
		return ApiResult.error(CommonErrorEnum.FILE_SIZE_ERROR.getErrorCode(), CommonErrorEnum.FILE_SIZE_ERROR.getErrorDesc());
	}
}

5. 抛出异常方式

例如想在Service层要抛出一个ADD_FAIL异常,应该这么写:

throw CommonErrorEnum.ADD_FAIL.getBusinessException();

而不是:

throw new BusinessException(CommonErrorEnum.ADD_FAIL);

第一种写法的好处是开发者能更注重产生的异常类型,而不用在乎抛出具体什么异常。

如果想抛出个ADD_FAIL异常,但不想使用ADD_FAIL对应的提示信息怎么办?

throw CommonErrorEnum.ADD_FAIL.setErrorDesc("添加用户信息失败").getBusinessException();

假设现在有多种自定义异常,异常枚举类中就可以这么写:

public BusinessException getBusinessException() {
	return new BusinessException(this);
}

// throw CommonErrorEnum.SQL_ASYCN_ERROR.getSqlException();
public SqlException getSqlException() {
	return new SqlException(this);
}

...

6. 总结

后端任何地方抛出异常,被全局异常捕获后,就会封装成一个携带有errorCodeerrorDescApiResult给前端,http状态码保证是正常的(200)。

然后前端就能通过ApiResult.code来判断接口是否调用成功,并做相应处理。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值