SpringMVC实现全局异常处理器的经典案例

 更新时间:2025年03月26日 11:08:39   作者:凯酱  
文章介绍了如何使用@ControllerAdvice和相关注解实现SpringMVC的全局异常处理,通过统一的异常处理类和自定义业务异常类,可以将所有控制器的异常集中处理,并以JSON格式返回给前端,感兴趣的朋友一起看看吧

通过 @ControllerAdvice 注解,我们可以在一个地方对所有 @Controller 注解的控制器进行管理。
注解了 @ControllerAdvice 的类的方法可以使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 注解到方法上,这对所有注解了 @RequestMapping 的控制器内的方法都有效。

@ExceptionHandler:用于捕获所有控制器里面的异常,并进行处理。@InitBinder:用来设置 WebDataBinder,WebDataBinder 用来自动绑定前台请求参数到 Model 中。@ModelAttribute:@ModelAttribute 本来的作用是绑定键值对到 Model
里,此处是让全局的@RequestMapping 都能获得在此处设置的键值对。

本文使用 @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理。只要设计得当,就再也不用在 Controller 层进行 try-catch 了!

一、经典案例

需求:希望通过全局统一的异常处理将自定义错误码以json的形式发送给前端。
1、统一返回结果类 ApiResult
首先,定义一个统一结果返回类,最终需要将这个结果类的内容返回给前端。

package com.tao.smp.exception;
/**
 * Api统一的返回结果类
 */
public class ApiResult {
    /**
     * 结果码
     */
    private String code;
    /**
     * 结果码描述
     */
    private String msg;
    public ApiResult() {
    }
    public ApiResult(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }
    /**
     * 生成一个ApiResult对象, 并返回
     *
     * @param resultCode
     * @return
     */
    public static ApiResult of(ResultCode resultCode) {
        return new ApiResult(resultCode);
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    @Override
    public String toString() {
        return "ApiResult{" +
                "code='" + code + '\'' +
                ", msg='" + msg + '\'' +
                '}';
    }
}

2、错误码枚举类 ResultCode
有了 ApiResult ,接下来需要定义一个枚举类, 来包含所有自定义的结果码。

package com.tao.smp.exception;
/**
 * 错误码
 */
public enum ResultCode {
    /**
     * 成功
     */
    SUCCESS("0", "success"),
    /**
     * 未知错误
     */
    UNKNOWN_ERROR("0x10001", "unkonwn error"),
    /**
     * 用户名错误或不存在
     */
    USERNAME_ERROR("0x10002", "username error or does not exist"),
    /**
     * 密码错误
     */
    PASSWORD_ERROR("0x10003", "password error"),
    /**
     * 用户名不能为空
     */
    USERNAME_EMPTY("0x10004", "username can not be empty");
    /**
     * 结果码
     */
    private String code;
    /**
     * 结果码描述
     */
    private String msg;
    ResultCode(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public String getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
}

3、自定义业务异常类 BusinessRuntimeException
接下来需要定义我们自己的业务异常类,以后和业务相关的异常通通抛出这个异常类,我们将错误码枚举变量的值存于其中。

package com.tao.smp.exception;
/**
 * 自定义业务异常
 */
public class BusinessRuntimeException extends RuntimeException {
    /**
     * 结果码
     */
    private String code;
    /**
     * 结果码描述
     */
    private String msg;
    /**
     * 结果码枚举
     */
    private ResultCode resultCode;
    public BusinessRuntimeException(ResultCode resultCode) {
        super(resultCode.getMsg());
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.resultCode = resultCode;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public ResultCode getResultCode() {
        return resultCode;
    }
    public void setResultCode(ResultCode resultCode) {
        this.resultCode = resultCode;
    }
}

4、全局异常处理类 GlobalExceptionResolver

最后便是定义全局异常处理类。

  • 通过 @ControllerAdvice 指定该类为 Controller 增强类。
  • 通过 @ExceptionHandler 自定捕获的异常类型。
  • 通过 @ResponseBody 返回 json 到前端。

注意一点:被@ControllerAdvice注解的全局异常处理类也是一个 Controller ,我们需要配置扫描路径,确保能够扫描到这个Controller。

package com.tao.smp.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
 * 全局Controller层异常处理类
 */
@ControllerAdvice
public class GlobalExceptionResolver {
    private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionResolver.class);
    /**
     * 处理所有不可知异常
     *
     * @param e 异常
     * @return json结果
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ApiResult handleException(Exception e) {
        // 打印异常堆栈信息
        LOG.error(e.getMessage(), e);
        return ApiResult.of(ResultCode.UNKNOWN_ERROR);
    }
    /**
     * 处理所有业务异常
     *
     * @param e 业务异常
     * @return json结果
     */
    @ExceptionHandler(BusinessRuntimeException.class)
    @ResponseBody
    public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) {
        // 不打印异常堆栈信息
        LOG.error(e.getMsg());
        return ApiResult.of(e.getResultCode());
    }
}

二、测试

1、测试 TestController

package com.tao.smp.controller;
import com.tao.smp.exception.BusinessRuntimeException;
import com.tao.smp.exception.ResultCode;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
 * 测试异常的抛出
 */
@Controller
@RequestMapping("/")
public class TestController {
    /**
     * 测试返回异常信息
     * @return
     */
    @GetMapping("/exception")
    public String returnExceptionInfo() {
        if (1 != 2) {
            // 用户民错误或不存在异常
            throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR);
        }
        return "success";
    }
}

到此这篇关于SpringMVC实现全局异常处理器的文章就介绍到这了,更多相关SpringMVC全局异常处理器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 二叉树遍历的常用方法

    Java 二叉树遍历的常用方法

    二叉树的遍历可以说是解决二叉树问题的基础。我们常用的遍历方式无外乎就四种 前序遍历、中序遍历、后续遍历、层次遍历 这四种。
    2021-05-05
  • Spring Boot 实现https ssl免密登录(X.509 pki登录)

    Spring Boot 实现https ssl免密登录(X.509 pki登录)

    这篇文章主要介绍了Spring Boot 实现https ssl免密登录(X.509 pki登录),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java实现常见的排序算法代码实例

    Java实现常见的排序算法代码实例

    这篇文章主要介绍了Java实现常见的排序算法代码实例,按照思路实现了以下几个排序算法(冒泡排序、直接插入排序、直接选择排序、快速排序),方便日后用到,特此记录一下,需要的朋友可以参考下
    2023-11-11
  • Java 图片复制功能实现过程解析

    Java 图片复制功能实现过程解析

    这篇文章主要介绍了Java 图片复制功能实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • SpringBoot整合Mybatis-Plus+Druid实现多数据源配置功能

    SpringBoot整合Mybatis-Plus+Druid实现多数据源配置功能

    本文主要讲解springboot +mybatisplus + druid 实现多数据源配置功能以及一些必要的准备及代码说明,具有一定的参考价值,感兴趣的小伙伴可以借鉴一下
    2023-06-06
  • Java实现SHA-1算法实例

    Java实现SHA-1算法实例

    这篇文章主要介绍了Java实现SHA-1算法,实例分析了java实现SHA-1算法的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • Java实现发送邮件功能时碰到的坑

    Java实现发送邮件功能时碰到的坑

    之前用163邮箱发邮件时明明是成功的,但是使用中国移动自己的邮箱时,无论如何在linux服务器中都发送不成功。下面小编给大家说下我是怎么解决的,一起看下吧
    2016-06-06
  • Spring整合多数据源实现动态切换的实例讲解

    Spring整合多数据源实现动态切换的实例讲解

    下面小编就为大家带来一篇Spring整合多数据源实现动态切换的实例讲解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • java 验证用户是否已经登录与实现自动登录方法详解

    java 验证用户是否已经登录与实现自动登录方法详解

    本文主要介绍了java 验证用户是否已经登录与实现自动登录的方法。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • java中CompleteFuture与Future的区别小结

    java中CompleteFuture与Future的区别小结

    本文主要介绍了java中CompleteFuture与Future的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-12-12

最新评论