springboot实现全局异常处理的方法(住家饭系统)

 更新时间:2025年05月06日 10:22:56   作者:小小奶酪可笑可笑  
住家饭系统将异常类型分为客户端异常(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全局异常处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot中@Async异步,实现异步结果合并统一返回方式

    Springboot中@Async异步,实现异步结果合并统一返回方式

    这篇文章主要介绍了Springboot中@Async异步,实现异步结果合并统一返回方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • Java通过URL类下载图片的实例代码

    Java通过URL类下载图片的实例代码

    这篇文章主要介绍了Java通过URL类下载图片,文中结合实例代码补充介绍了java通过url获取图片文件的相关知识,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02
  • Java中如何编写一个数的n次方(幂运算)?

    Java中如何编写一个数的n次方(幂运算)?

    本文介绍了使用pow函数和自定义for循环计算幂的O(n)时间复杂度方法,然后重点讲解了快速幂算法的分治思想,以及从二进制角度的解释,包括如何通过位运算和循环迭代实现高效计算,给出了Java代码实现
    2024-07-07
  • 使用Java8实现观察者模式的方法(上)

    使用Java8实现观察者模式的方法(上)

    本文给大家介绍使用java8实现观察者模式的方法,涉及到java8观察者模式相关知识,对此感兴趣的朋友一起学习吧
    2016-02-02
  • Mybatis图文并茂讲解分页插件

    Mybatis图文并茂讲解分页插件

    使用过mybatis的人都知道,mybatis本身就很小且简单,sql写在xml里,统一管理和优化。缺点当然也有,比如我们使用过程中,要使用到分页,如果用最原始的方式的话,1.查询分页数据,2.获取分页长度,也就是说要使用到两个方法才能完成分页
    2022-07-07
  • Java学习教程之定时任务全家桶

    Java学习教程之定时任务全家桶

    这篇文章主要给大家介绍了关于Java学习教程之定时任务全家桶的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • SpringBoot项目@Async方法问题解决方案

    SpringBoot项目@Async方法问题解决方案

    这篇文章主要介绍了SpringBoot项目@Async方法问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Spring boot集成easy excel实现导入导出功能

    Spring boot集成easy excel实现导入导出功能

    这篇文章主要介绍了Spring boot集成easy excel实现导入导出操作,使用easyexcel,首先要引入easyexcel的maven依赖,具体的版本根据你的需求去设置,本文结合实例代码讲解的非常详细,需要的朋友可以参考下
    2024-05-05
  • Java解析pdf格式发票的代码实现

    Java解析pdf格式发票的代码实现

    为了减少用户工作量及误操作的可能性,需要实现用户上传PDF格式的发票,系统通过解析PDF文件获取发票内容,并直接将其写入表单,以下文章记录了功能实现的代码,需要的朋友可以参考下
    2024-08-08
  • Java如何比较两个对象并获取不相等的字段详解

    Java如何比较两个对象并获取不相等的字段详解

    这篇文章主要给大家介绍了关于Java如何比较两个对象并获取不相等的字段以及JAVA判断(获取)两个相同对象不同的数据的相关资料,文中通过实例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友可以参考下
    2021-11-11

最新评论