IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring 中的全局异常处理(实用) -> 正文阅读

[Java知识库]Spring 中的全局异常处理(实用)

相信大家在平时写代码的时候都使用过 try catch 来处理异常,特别是在前端调用的后端接口中,如果我们没做异常处理,后端直接返回错误信息给前端,前端直接把程序员才看懂的错误信息展示给了用户,想必会造成很不好的用户体验。

为了防止发生这种情况,我们就需要在后端接口中 try catch 处理好异常,将更友好的错误信息返回给用户,比如:服务器内部异常、校验异常等等。而我们一个个的在接口中加上 try catch 有些麻烦,此时我们就可以使用全局异常处理机制

@ControllerAdvice 注解实现全局异常处理

在 Spring 3.2 中,新增了@ControllerAdvice@RestControllerAdvice 注解。这两个注解的功能呢其实是一样的。区别就像 @Controller@RestController 之间的区别。

@ControllerAdvice 作用:

  1. 全局异常处理
  2. 全局数据绑定
  3. 全局数据预处理

@ControllerAdvice 用法:

  1. @ExceptionHandler 注解标注的方法:用于捕获 Controller 中抛出的不同类型的异常,从而达到异常全局处理的目的;
  2. @InitBinder 注解标注的方法:用于请求中注册自定义参数的解析,从而达到自定义请求参数格式的目的;
  3. @ModelAttribute 注解标注的方法:表示此方法会在执行目标 Controller 方法之前执行 。

全局异常处理具体用法:

今天呐,我们主要来探讨的是 @ControllerAdvice 结合 @ExceptionHandler 注解用于全局异常的处理。

至于 @ControllerAdvice 的其他作用,本文不做探讨。有兴趣的小伙伴可以自己学习下。

代码实现:

创建一个 GlobalExceptionHandler 类,添加上 @RestControllerAdvice 注解

/**
 * 全局异常处理器
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 基础异常
     */
    @ExceptionHandler(BaseException.class)
    public AjaxResult baseException(BaseException e)
    {
        return AjaxResult.error(e.getCode(),e.getDefaultMessage());
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(CustomException.class)
    public AjaxResult businessException(CustomException e)
    {
        if (StringUtils.isNull(e.getCode()))
        {
            return AjaxResult.error(e.getMessage());
        }
        return AjaxResult.error(e.getCode(), e.getMessage());
    }

    /**
     * 其他异常
     */
    @ExceptionHandler(Exception.class)
    public AjaxResult handleException(Exception e)
    {
        log.error(e.getMessage(), e);
        return AjaxResult.error(HttpStatus.ERROR,"系统内部错误");
    }

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

    /**
     * 权限异常
     */
    @ExceptionHandler(PreAuthorizeException.class)
    public AjaxResult preAuthorizeException(PreAuthorizeException e)
    {
        return AjaxResult.error("没有权限,请联系管理员授权");
    }
}

在该类中,可以定义多个方法,不同的方法处理不同的异常,例如你还可以定义专门处理空指针的方法、专门处理数组越界的方法等等。Controller 中的不同的异常就会进入这个类中的对应异常的方法中。

来看一下我们自定义的BaseException异常:

/**
 * 基础异常
 */
public class BaseException extends RuntimeException
{
    private static final long serialVersionUID = 1L;

    /**
     * 所属模块
     */
    private String module;

    /**
     * 错误码
     */
    private String code = HttpStatus.ERROR;

    /**
     * 错误码对应的参数
     */
    private Object[] args;

    /**
     * 错误消息
     */
    private String defaultMessage;

    public BaseException(String module, String code, Object[] args, String defaultMessage)
    {
        this.module = module;
        this.code = code;
        this.args = args;
        this.defaultMessage = defaultMessage;
    }

    public BaseException(String module, String code, Object[] args)
    {
        this(module, code, args, null);
    }

    public BaseException(String code, String defaultMessage)
    {
        this(null, code, null, defaultMessage);
    }

    public BaseException(String code, Object[] args)
    {
        this(null, code, args, null);
    }

    public BaseException(String defaultMessage)
    {
        this(null, HttpStatus.ERROR, null, defaultMessage);
    }

    public String getModule()
    {
        return module;
    }

    public String getCode()
    {
        return code;
    }

    public Object[] getArgs()
    {
        return args;
    }

    public String getDefaultMessage()
    {
        return defaultMessage;
    }
}

再贴出 AjaxResult.java 的代码(来自开源项目若依管理系统):

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(String code, String msg)
    {
        super.put(CODE_TAG, code);
        super.put(MSG_TAG, msg);
    }

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

    /**
     * 方便链式调用
     *
     * @param key
     * @param value
     * @return
     */
    @Override
    public AjaxResult put(String key, Object value)
    {
        super.put(key, value);
        return this;
    }

    /**
     * 返回成功消息
     *
     * @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(HttpStatus.ERROR, msg);
    }

    /**
     * 返回错误消息
     *
     * @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(String code, String msg)
    {
        return new AjaxResult(code, msg, null);
    }

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

总结

除了使用 @ControllerAdvice 之外,还可以通过实现 HandlerExceptionResolver接口类实现全局异常处理机制。这里就不在叙述了,感兴趣的小伙伴自己去查。

基于 @ControllerAdvice 实现,我们平时写代码的时候,就会在 Service 层抛出异常到 Controller 层,而不是直接 try catch 处理。如果自己 try catch 处理了,那么就不会再进入到 GlobalExceptionHandler 类中了。

当然除了返回规范的错误信息给用户,你也可以在 GlobalExceptionHandler 方法中做其他的工作,比如异常统计什么的。

还有一点想要写一下:

在 service 方法里面如果对异常进行了捕获并处理的话,该事务是不会进行回滚的,@Transactional会失效

或者在 catch 语句中最后增加 throw new RuntimeException() 语句,以便让 aop 捕获异常再去回滚。

又或者在 catch 语句中增加下面代码来手动回滚:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-30 15:28:34  更:2021-11-30 15:31:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:16:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码