SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理

这篇具有很好参考价值的文章主要介绍了SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

场景

在编写Controller接口时,为避免接口因为未知的异常导致返回不友好的结果和提示。

如果不进行全局异常捕获则需要对每个接口进行try-catch或其他操作。

SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理 

可以对Controller进行全局的异常捕获和处理,一旦发生异常,则返回通用的500响应码与通用错误提示。

并将异常发生的具体的文件、类、方法、行数信息记录到日志。

@ControllerAdvice,是Spring3.2提供的新注解,它是一个Controller增强器,

可对controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理。

需要配合@ExceptionHandler使用。当将异常抛到controller时,可以对异常进行统一处理。

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

1、@RestControlAdvice是组合注解,由@ControllerAdvice和@ResponseBody组成。

SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理 

@ControllerAdvice 提供了多种指定Advice规则的定义方式,默认什么都不写,则是Advice所有Controller,

SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理

 文章来源地址https://www.toymoban.com/news/detail-445640.html

当然你也可以通过下列的方式指定规则。

通过basePackages指定只对哪些包路径下生效。

也可以通过指定注解来匹配,比如我自定了一个 @CustomAnnotation 注解,

我想匹配所有被这个注解修饰的 Controller, 可以这么写:@ControllerAdvice(annotations= {CustomAnnotation.class})

这里不做任何规则限制,对所有的controller生效。

2、新建全局异常捕获类,注意与启动类在同包路径下,不然不生效需要在启动类中指定包路径。

import com.badao.demo.common.AjaxResult;
import com.badao.demo.constant.Constants;
import com.badao.demo.constant.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//注意引入包的路径
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    public AjaxResult handleException(Exception e)
    {
        StackTraceElement stackTrace = e.getStackTrace()[0];
        String methodName = stackTrace.getMethodName();
        String fileName = stackTrace.getFileName();
        String className = stackTrace.getClassName();
        int lineNumber = stackTrace.getLineNumber();
        log.error("异常发生在文件{}的类{}中的方法{}的第{}行',异常信息:{}", fileName,className,methodName,lineNumber,e.getMessage());
        return AjaxResult.error(HttpStatus.ERROR, Constants.SERVER_ERROR);
    }
}

这里使用@ExceptionHandler(Exception.class)

对所有的Exception进行捕获,然后统一返回封装的AjaxResult结果类

import com.badao.demo.constant.HttpStatus;
import com.badao.demo.utils.StringUtils;

import java.util.HashMap;

/**
 * 操作消息提醒
 *
 */
public class AjaxResult extends HashMap<String, Object>
{
    private static final long serialVersionUID = 1L;

    /** 状态码 */
    public static final String CODE_TAG = "code";

    /** 返回内容 */
    public static final String MSG_TAG = "msg";

    /** 数据对象 */
    public static final String DATA_TAG = "data";

    /**
     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
     */
    public AjaxResult()
    {
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     *
     * @param code 状态码
     * @param msg 返回内容
     */
    public AjaxResult(int code, String msg)
    {
        super.put(CODE_TAG, code);
        super.put(MSG_TAG, msg);
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     *
     * @param code 状态码
     * @param msg 返回内容
     * @param data 数据对象
     */
    public AjaxResult(int code, String msg, Object data)
    {
        super.put(CODE_TAG, code);
        super.put(MSG_TAG, msg);
        if (StringUtils.isNotNull(data))
        {
            super.put(DATA_TAG, data);
        }
    }

    /**
     * 返回成功消息
     *
     * @return 成功消息
     */
    public static AjaxResult success()
    {
        return AjaxResult.success("操作成功");
    }

    /**
     * 返回成功数据
     *
     * @return 成功消息
     */
    public static AjaxResult success(Object data)
    {
        return AjaxResult.success("操作成功", data);
    }

    /**
     * 返回成功消息
     *
     * @param msg 返回内容
     * @return 成功消息
     */
    public static AjaxResult success(String msg)
    {
        return AjaxResult.success(msg, null);
    }

    /**
     * 返回成功消息
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 成功消息
     */
    public static AjaxResult success(String msg, Object data)
    {
        return new AjaxResult(HttpStatus.SUCCESS, msg, data);
    }

    /**
     * 返回错误消息
     *
     * @return
     */
    public static AjaxResult error()
    {
        return AjaxResult.error("操作失败");
    }

    /**
     * 返回错误消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */
    public static AjaxResult error(String msg)
    {
        return AjaxResult.error(msg, null);
    }

    /**
     * 返回错误消息
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static AjaxResult error(String msg, Object data)
    {
        return new AjaxResult(HttpStatus.ERROR, msg, data);
    }

    /**
     * 返回错误消息
     *
     * @param code 状态码
     * @param msg 返回内容
     * @return 警告消息
     */
    public static AjaxResult error(int code, String msg)
    {
        return new AjaxResult(code, msg, null);
    }
}

然后状态码和提示消息是封装的常量类

状态码常量类

public class HttpStatus
{
    /**
     * 操作成功
     */
    public static final int SUCCESS = 200;

    /**
     * 对象创建成功
     */
    public static final int CREATED = 201;

    /**
     * 请求已经被接受
     */
    public static final int ACCEPTED = 202;

    /**
     * 操作已经执行成功,但是没有返回数据
     */
    public static final int NO_CONTENT = 204;

    /**
     * 资源已被移除
     */
    public static final int MOVED_PERM = 301;

    /**
     * 重定向
     */
    public static final int SEE_OTHER = 303;

    /**
     * 资源没有被修改
     */
    public static final int NOT_MODIFIED = 304;

    /**
     * 参数列表错误(缺少,格式不匹配)
     */
    public static final int BAD_REQUEST = 400;

    /**
     * 未授权
     */
    public static final int UNAUTHORIZED = 401;

    /**
     * 访问受限,授权过期
     */
    public static final int FORBIDDEN = 403;

    /**
     * 资源,服务未找到
     */
    public static final int NOT_FOUND = 404;

    /**
     * 不允许的http方法
     */
    public static final int BAD_METHOD = 405;

    /**
     * 资源冲突,或者资源被锁
     */
    public static final int CONFLICT = 409;

    /**
     * 不支持的数据,媒体类型
     */
    public static final int UNSUPPORTED_TYPE = 415;

    /**
     * 系统内部错误
     */
    public static final int ERROR = 500;

    /**
     * 接口未实现
     */
    public static final int NOT_IMPLEMENTED = 501;
}

消息常量类

public class Constants {
    //请求响应常量
    public static final String NO_API_CODE = "请求码不能为空";
    public static final String ILLEGAL_API_CODE = "请求码不存在";
    public static final String SERVER_ERROR = "服务器内部错误,请联系管理员!";
    public static final String CALL_TOO_OFEN = "请求太频繁";
}

然后将异常发生的具体信息记录到日志中,异常的信息来源可以打断点获取和自定义需要获取的内容

SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理

 

2、这里是对Exception类型进行通配,如果需要对指定的异常类型或者自定义类型就行捕获,还可以

import com.badao.demo.common.AjaxResult;
import com.badao.demo.constant.Constants;
import com.badao.demo.constant.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//注意引入包的路径
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    public AjaxResult handleException(Exception e)
    {
        StackTraceElement stackTrace = e.getStackTrace()[0];
        String methodName = stackTrace.getMethodName();
        String fileName = stackTrace.getFileName();
        String className = stackTrace.getClassName();
        int lineNumber = stackTrace.getLineNumber();
        log.error("异常发生在文件{}的类{}中的方法{}的第{}行',异常信息:{}", fileName,className,methodName,lineNumber,e.getMessage());
        return AjaxResult.error(HttpStatus.ERROR, Constants.SERVER_ERROR);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AjaxResult handleBindException(BindException e) {
        log.error(e.getMessage(), e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        return AjaxResult.error(HttpStatus.BAD_REQUEST, message);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
    {
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return AjaxResult.error(message);
    }
}

这里注意引入包的路径,不然会出现不生效的情况。

这块还可参考

SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定枚举类型中):

SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定枚举类型中)_霸道流氓气质的博客-CSDN博客

3、测试效果

手动编写一个除零异常并将controller中的try-catch去掉

SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理

 

接口统一响应,在日志中记录到具体信息

SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理

 

到了这里,关于SpringBoot中@ControllerAdvice/@RestControlAdvice+@ExceptionHandler实现全局异常捕获与处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring专题】「技术原理」从源码角度去深入分析关于Spring的异常处理ExceptionHandler的实现原理

    ExceptionHandler是Spring框架提供的一个注解,用于处理应用程序中的异常。当应用程序中发生异常时,ExceptionHandler将优先地拦截异常并处理它,然后将处理结果返回到前端。该注解可用于类级别和方法级别,以捕获不同级别的异常。 在Spring中使用ExceptionHandler非常简单,只需在需

    2023年04月09日
    浏览(45)
  • @ControllerAdvice 注解使用及原理探究

    最近在新项目的开发过程中,遇到了个问题,需要将一些异常的业务流程返回给前端,需要提供给前端不同的响应码,前端再在次基础上做提示语言的国际化适配。这些异常流程涉及业务层和控制层的各个地方,如果每个地方都写一些重复代码显得很冗余。 然后查询解决方案

    2024年02月14日
    浏览(65)
  • @ControllerAdvice注解使用及原理探究 | 京东物流技术团队

    最近在新项目的开发过程中,遇到了个问题,需要将一些异常的业务流程返回给前端,需要提供给前端不同的响应码,前端再在次基础上做提示语言的国际化适配。这些异常流程涉及业务层和控制层的各个地方,如果每个地方都写一些重复代码显得很冗余。 然后查询解决方案

    2024年02月14日
    浏览(50)
  • Caused by: java.lang.ClassNotFoundException: org.apache.maven.exception.ExceptionHandler 的解决办法

    出现这个问题,是由于开发环境迁移,在迁移的过程中操作不规范导致的, 由一台开发服务器,迁移至另外一台开发服务器时,启动失败, 错误提示:“  Exception in thread \\\"main\\\" java.lang.NoClassDefFoundError: org/apache/maven/exception/ExceptionHandler ” 具体内容如下:  如下图: 关于这个

    2024年02月04日
    浏览(52)
  • 【Spring Boot统一功能处理】统一异常处理,统一的返回格式,@ControllerAdvice简单分析,即将走进SSM项目的大门! ! !

    前言: 大家好,我是 良辰丫 ,在上一篇文章中我们已经学习了一些统一功能处理的相关知识,今天我们继续深入学习这些知识,主要学习统一异常处理,统一的返回格式,@ControllerAdvice简单分析.💌💌💌 🧑个人主页:良辰针不戳 📖所属专栏:javaEE进阶篇之框架学习 🍎励志语句:生

    2024年02月16日
    浏览(42)
  • 【SpringBoot】SpringBoot实现投票系统代码

    由于投票系统的代码量较大,且有很多细节需要注意,因此不能在这里完整地给出代码。但是,下面是一个简单的SpringBoot投票系统的代码框架,为您提供一个参考,您可以在此基础上进行开发和完善。 创建一个名为\\\"VotingSystem\\\"的SpringBoot项目 在pom.xml文件中添加需要的依赖:

    2024年02月10日
    浏览(36)
  • 【SpringBoot】springboot实现全局异常捕获

    为什么要做异常处理: 原因有三: 1、将系统产生的全部异常统一捕获处理。 2、自定义异常需要由全局异常来捕获。 3、JSR303规范的validator参数校验器、参数校验不通过、本身无法使用try…catch 其实对于前后端分离的项目做异常处理是很有必要的 在不出异常的情况下,后端

    2024年02月12日
    浏览(43)
  • SpringBoot进阶-SpringBoot如何实现配置文件脱敏

    SpringBoot进阶-SpringBoot如何实现配置文件脱敏? SpringBoot集成jasypt配置信息加密以及采坑 在很多开发场景中我们的SpringBoot应用是被打包成了一个Jar文件来使用的,利用解压缩工具可以将这个Jar包解压出来并且在对应的配置路径下找到数据库的访问地址以及数据库的登录密码等等

    2024年02月08日
    浏览(40)
  • 【SpringBoot】83、SpringBoot集成Quartz实现调度日志收集

    1、Quartz简介 Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB 作业预构 建,JavaMail 及

    2024年02月11日
    浏览(60)
  • 玩转SpringBoot:SpringBoot的几种定时任务实现方式

    在现代软件开发中,定时任务是一种常见的需求,用于执行周期性的任务或在特定的时间点执行任务。这些任务可能涉及数据同步、数据备份、报表生成、缓存刷新等方面,对系统的稳定性和可靠性有着重要的影响。 Spring Boot 提供了强大且简单的定时任务功能,使开发人员能

    2024年03月09日
    浏览(85)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包