springboot实现全局异常处理的方法(住家饭系统)
作者:小小奶酪可笑可笑
住家饭系统将异常类型分为客户端异常(ClientException),系统异常(ServiceException),远程调用异常(RemoteException),本文给大家介绍springboot实现全局异常处理的方法,感兴趣的朋友一起看看吧
在实际项目开发中,定义全局异常处理至关重要通过全局异常处理器(使@ControllerAdvice和@ExceptionHandler注解),可以集中捕获和处理各种异常,避免在每个控制器方法中重复编写异常处理代码。
住家饭系统将异常类型分为客户端异常(ClientException),系统异常(ServiceException),远程调用异常(RemoteException)。类结构图如下:

我们需先定义一个抽象异常类 AbstractException ,该抽象类继承自 RuntimeException 类,通过该类约束异常类行为。
/**
* 抽象项目中的三类异常,客户端异常、服务端异常和远程服务调用异常
*/
@Data
public abstract class AbstractException extends RuntimeException{
public final String errorCode;
public final String errorMsg;
public AbstractException(String errorMsg, Throwable throwable, IErrorCode errorCode) {
super(errorMsg, throwable);
this.errorCode = errorCode.code();
this.errorMsg = Optional.ofNullable(StringUtils.hasLength(errorMsg) ? errorMsg : null).orElse(errorCode.msg());
}
}接着在分别定义客户端异常、服务端异常和远程调用异常类。
public class ClientException extends AbstractException{
public ClientException (IErrorCode errorCode) {
super(null, null, errorCode);
}
public ClientException(IErrorCode errorCode, String errorMsg) {
super(errorMsg, null, errorCode);
}
public ClientException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}
@Override
public String toString() {
return "ClientException{" +
"code='" + errorCode + "'," +
"message='" + errorMsg + "'" +
'}';
}
}public class ServiceException extends AbstractException{
public ServiceException(String message) {
this(message, null, BaseErrorCode.SERVICE_ERROR);
}
public ServiceException(IErrorCode errorCode) {
this(null, errorCode);
}
public ServiceException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}
public ServiceException(String message, Throwable throwable, IErrorCode errorCode) {
super(Optional.ofNullable(message).orElse(errorCode.msg()), throwable, errorCode);
}
@Override
public String toString() {
return "ServiceException{" +
"code='" + errorCode + "'," +
"message='" + errorMsg + "'" +
'}';
}
}public class RemoteException extends AbstractException{
public RemoteException(String errorMsg, Throwable throwable, IErrorCode errorCode) {
super(errorMsg, throwable, errorCode);
}
@Override
public String toString() {
return "RemoteException{" +
"code='" + errorCode + "'," +
"message='" + errorMsg + "'" +
'}';
}
}这样,我们就完成了对三大基本异常类的定义。接下来我们需要通过springboot提供的@ControllerAdvice和@ExceptionHandler注解来实现全局异常拦截并处理。我们需定义一个GlobalExceptionHandler类,在该类中分别对参数验证异常、应用内抛出的异常和最顶级的Throwable异常进行处理。
Component("globalExceptionHandlerByAdmin")
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 拦截参数验证异常
*/
@SneakyThrows
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result validExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
FieldError firstFieldError = CollectionUtil.getFirst(bindingResult.getFieldErrors());
String exceptionStr = Optional.ofNullable(firstFieldError)
.map(FieldError::getDefaultMessage)
.orElse(StrUtil.EMPTY);
log.error("[{}] {} [ex] {}", request.getMethod(), getUrl(request), exceptionStr);
return Results.failure(BaseErrorCode.CLIENT_ERROR.code(), exceptionStr);
}
/**
* 拦截应用内抛出的异常
*/
@ExceptionHandler(value = {AbstractException.class})
public Result abstractException(HttpServletRequest request, AbstractException ex) {
if (ex.getCause() != null) {
log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex.toString(), ex.getCause());
return Results.failure(ex);
}
log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex.toString());
return Results.failure(ex);
}
/**
* 拦截未捕获异常
*/
@ExceptionHandler(value = Throwable.class)
public Result defaultErrorHandler(HttpServletRequest request, Throwable throwable) {
log.error("[{}] {} ", request.getMethod(), getUrl(request), throwable);
if (Objects.equals(throwable.getClass().getSuperclass().getSimpleName(), AbstractException.class.getSimpleName())) {
String errorCode = ReflectUtil.getFieldValue(throwable, "errorCode").toString();
String errorMessage = ReflectUtil.getFieldValue(throwable, "errorMessage").toString();
return Results.failure(errorCode, errorMessage);
}
return Results.failure();
}
private String getUrl(HttpServletRequest request) {
if (StringUtils.isEmpty(request.getQueryString())) {
return request.getRequestURL().toString();
}
return request.getRequestURL().toString() + "?" + request.getQueryString();
}
}今后,我们在项目里抛出的所有异常,都可以被 GlobalExceptionHandler 类捕获并进行相应的处理。
public void register(UserRegisterReqDTO requestParam) {
if(ObjectUtils.isEmpty(requestParam)) throw new ClientException(CLIENT_ERROR);
if (hasUserName(requestParam.getUsername())) {
throw new ServiceException(USER_NAME_EXIST);
}
try {
int inserted = baseMapper.insert(BeanUtil.toBean(requestParam, UserDao.class));
if (inserted <= 0) {
throw new ClientException(USER_SAVE_ERROR);
}
} catch (DuplicateKeyException ex) {
throw new ServiceException(USER_EXIST);
}
}到此这篇关于springboot实现全局异常处理的文章就介绍到这了,更多相关springboot全局异常处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
