Spring Boot 2.X(十一):全局异常处理

前言

在 Java Web 系统开发中,不管是 Controller 层、Service 层还是 Dao 层,都有可能抛出异常。如果在每个方法中加上各种 try catch 的异常处理代码,那样会使代码非常繁琐。在Spring MVC 中,我们可以将所有类型的异常处理从各个单独的方法中解耦出来,进行异常信息的统一处理和维护。

在 Spring MVC 中全局异常捕获处理的解决方案通常有两种方式:

1.使用 @ControllerAdvice + @ExceptionHandler 注解进行全局的 Controller 层异常处理。

2.实现 org.springframework.webb.servlet.HandlerExceptionResolver 接口中的 resolveException 方法。

使用 @ControllerAdvice + @ExceptionHandler 注解

1.定义统一异常处理类

@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) {
        log.error("ExceptionHandler ===>" + e.getMessage());
        e.printStackTrace();
        // 这里可根据不同异常引起的类做不同处理方式
        String exceptionName = ClassUtils.getShortName(e.getClass());
        log.error("ExceptionHandler ===>" + exceptionName);
        ModelAndView mav = new ModelAndView();
        mav.addObject("stackTrace", e.getStackTrace());
        mav.addObject("errorMessage", e.getMessage());
        mav.addObject("url", req.getRequestURL());
        mav.setViewName("forward:/error/500");
        return mav;
    }
}

其中 @ExceptionHandler(value = Exception.class) 中的捕获异常 value 可以自定义,如下:

类型

描述

NullPointerException

当应用程序试图访问空对象时,则抛出该异常

SQLException

提供关于数据库访问错误或其他错误信息的异常

IndexOutOfBoundsException

指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出

NumberFormatException

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常

FileNotFoundException

当试图打开指定路径名表示的文件失败时,抛出此异常

IOException

当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类

ClassCastException

当试图将对象强制转换为不是实例的子类时,抛出该异常

ArrayStoreException

试图将错误类型的对象存储到一个对象数组时抛出的异常

IllegalArgumentException

抛出的异常表明向方法传递了一个不合法或不正确的参数

ArithmeticException

当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例

NegativeArraySizeException

如果应用程序试图创建大小为负的数组,则抛出该异常

NoSuchMethodException

无法找到某一特定方法时,抛出该异常

SecurityException

由安全管理器抛出的异常,指示存在安全侵犯

UnsupportedOperationException

当不支持请求的操作时,抛出该异常

RuntimeException

是那些可能在Java虚拟机正常运行期间抛出的异常的超类

当捕获到响应的异常类型时,会进入 defaultErrorHandler() 方法中的逻辑:把异常信息放入 model,跳转至 /error/500 请求URL。

2.异常信息展现

视图控制器配置

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 视图控制器配置
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {    
        registry.addViewController("/").setViewName("/index");//设置默认跳转视图为 /index
        registry.addViewController("/error/500").setViewName("/error/500");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);

    }

}

视图模板

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Exception</h1>
<h3 th:text="${url}"></h3>
<h3 th:text="${errorMessage}"></h3>
<p  th:each="line : ${stackTrace}" th:text="${line}">  </p>
</body>
</html>

3.测试异常类

@Controller
public class TestController {

    @GetMapping("/index")
    public String hello() {
        int x = 1 / 0;
        return "hello";
    }
}

4.运行测试

浏览器访问:http://127.0.0.1:8080/index

@ControllerAdvice 还能结合 @ModelAttribute 、@InitBinder 注解一起使用,实现全局数据绑定和全局数据预处理等功能。

实现 HandlerExceptionResolver 接口

1.定义统一异常处理类

@Component
public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver {

    private Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        Exception e = new Exception();
        //处理 UndeclaredThrowableException
        if (ex instanceof UndeclaredThrowableException) {
            e = (Exception) ((UndeclaredThrowableException) ex).getUndeclaredThrowable();
        } else {
            e = ex;
        }
        e.printStackTrace();
        //这里可以根据不同异常引起的类做不同处理方式
        String exceptionName = ClassUtils.getShortName(e.getClass());
        if(exceptionName.equals("ArrayIndexOutOfBoundsException")) {
            log.error("GlobalHandlerExceptionResolver resolveException ===>" + exceptionName);
            ModelAndView mav = new ModelAndView();
            mav.addObject("stackTrace", e.getStackTrace());
            mav.addObject("exceptionName", exceptionName);
            mav.addObject("errorMessage", e.getMessage());
            mav.addObject("url", request.getRequestURL());
            mav.setViewName("forward:/error/500");
            return mav;
        }
        return null;
    }

}

UndeclaredThrowableException 异常通常是在 RPC 接口调用场景或者使用 JDK 动态代理的场景时发生。如果不预先处理转换,测试捕获到的异常则为 UndeclaredThrowableException,而不是真实的异常对象。

2.异常信息展现 同上

3.测试异常类

@Controller
public class TestController {

    @GetMapping("/test")
    public String test() {
        String[] ss = new String[] { "1", "2" };
        System.out.print(ss[2]);
        return "hello";
    }

}

4.测试运行

浏览器访问:http://127.0.0.1:8080/test

本文分享自微信公众号 - 朝雾轻寒的博客(zwqh_blog)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户5521492的专栏

SpringMVC 工作原理

DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。

7230
来自专栏用户5521492的专栏

SpringBoot 实战 (十二) | 整合 thymeleaf

如题,今天介绍 Thymeleaf ,并整合 Thymeleaf 开发一个简陋版的学生信息管理系统。

8720
来自专栏Java编程指南

如何阅读Spring源码

因为不断有朋友,或留言,或私信,问我Spring源码阅读问题。我本有心回答,但奈何这是一个非三言两语能说清出的事。所以就决定写一篇小文,来分享下我的浅薄经验。

10130
来自专栏用户5521492的专栏

Spring Boot 与 MVC 的区别

常常有读者问我,Spring、SpringMVC、SpringBoot 有啥区别?在我的理解中,我觉得 Spring 是基础,是核心;SpringMVC 是一个...

10120
来自专栏咖啡拿铁

优雅的处理你的Java异常

本文仅按照业务系统开发角度描述异常的一些处理看法.不涉及java的异常基础知识,可以自行查阅 《Java核心技术 卷I》 和 《java编程思想》 可以得到更多...

11220
来自专栏用户5521492的专栏

Spring MVC 复盘 | 工作原理及配置详解

https://mp.weixin.qq.com/s/z-fhmDa9iBwSG6OJx1x5hw

7240
来自专栏大内老A

[ASP.NET Core 3框架揭秘] 依赖注入:IoC模式

正如我们在《依赖注入:控制反转》提到过的,很多人将IoC理解为一种“面向对象的设计模式”,实际上IoC不仅与面向对象没有必然的联系,它自身甚至算不上是一种设计模...

10250
来自专栏PowerBI战友联盟

这是不是 PowerBI 原生作图的最高境界 - 案例:对比积累分析图

如果让分析师去做一些高信息含量的图表,那该图一定位列其中,因为企业几乎都是是目标(结果)导向的,对此,KPI的达成就是关键的信息了。

20320
来自专栏云鼎实验室的专栏

“高危”!腾讯发现云虚拟化平台逃逸漏洞

随着云技术的快速发展和迭代更新,各行各业都在“云”中快速成长,安全性显得尤为重要。而云时代软硬件的“云交互”,对安全来说也意味着新的挑战。 近日,腾讯Blad...

16140
来自专栏大内老A

[ASP.NET Core 3框架揭秘] 依赖注入:控制反转

ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入、文件系统、配置选项和诊断日志等。这些框架不仅仅是支撑ASP.NET Core...

8330

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励