前言

在 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.测试运行

测试前先把 @ControllerAdvice 注释了。

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

示例代码

github

码云

非特殊说明,本文版权归 朝雾轻寒 所有,转载请注明出处.

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

原文地址:https://www.zwqh.top/article/info/20

如果文章对您有帮助,请扫码关注下我的公众号,文章持续更新中...

Spring Boot 2.X(十一):全局异常处理的更多相关文章

  1. Spring Boot 2 Webflux的全局异常处理

    https://www.jianshu.com/p/6f631f3e00b9 本文首先将会回顾Spring 5之前的SpringMVC异常处理机制,然后主要讲解Spring Boot 2 Webflu ...

  2. Spring Boot 系列教程6-全局异常处理

    @ControllerAdvice源码 package org.springframework.web.bind.annotation; import java.lang.annotation.Ann ...

  3. spring boot+自定义 AOP 实现全局校验

    最近公司重构项目,重构为最热的微服务框架 spring boot, 重构的时候遇到几个可以统一处理的问题,也是项目中经常遇到,列如:统一校验参数,统一捕获异常... 仅凭代码 去控制参数的校验,有时候 ...

  4. Spring Boot 统一返回结果及异常处理

    在 Spring Boot 构建电商基础秒杀项目 (三) 通用的返回对象 & 异常处理 基础上优化.调整 一.通用类 1.1 通用的返回对象 public class CommonReturn ...

  5. Spring Boot 知识笔记(全局异常)

    通过ControllerAdvice和ExceptionHandler捕获异常和错误信息,向前端返回json格式的状态码及异常描述信息. 1.新建一个Controller,抛出一个异常. packag ...

  6. 【Spring Boot学习之十一】整合mongoDB

    环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 参考: SpringBoot+Mongodb的使用

  7. Spring Boot系列教程十一: Mybatis使用分页插件PageHelper

    一.前言 上篇博客中介绍了spring boot集成mybatis的方法,基于上篇文章这里主要介绍如何使用分页插件PageHelper.在MyBatis中提供了拦截器接口,我们可以使用PageHelp ...

  8. Spring Boot 入门(十一):集成 WebSocket, 实时显示系统日志

    以前面的博客为基础,最近一篇为Spring Boot 入门(十):集成Redis哨兵模式,实现Mybatis二级缓存.本篇博客主要介绍了Spring Boot集成 Web Socket进行日志的推送, ...

  9. Spring Boot学习笔记(二)全局捕获异常处理

    非常简单只需要创建自己的异常处理类,加上两个注解,就可以了

随机推荐

  1. 控制执行流程之ForEach语法

    1.定义 : 一种更加简洁的for语法,用于数组和容器===>>>foreach,无需创建int类型变量对被访问项构建的序列进行计数. 2.经典应用:  对于数组的初始化,如果选用f ...

  2. 神奇的互换身体术--java的类型擦除

    故事背景 <互换身体>是由环球影业发行的喜剧电影,于2011年8月5日在美国上映.该片由大卫·道金执导,瑞安·雷诺兹.杰森·贝特曼.奥利维亚·王尔德等主演.该片讲述了一位居家好男人和一位蜂 ...

  3. .ssh/config 文件的解释算法及配置原则

    前言 SSH 是连接远程主机最常用的方式,尽管连接到耽搁主机的基本操作非常直接,但当你开始使用大量的远程系统时,这就会成为笨重和复杂的任务. 幸运的是,OpenSSH 允许您提供自定义的客户端连接选项 ...

  4. Gradle 梳理 - 插件

    Gradle 教程:第二部分,JAVA PROJECTS[翻译]   原文地址:http://rominirani.com/2014/07/28/gradle-tutorial-part-2-java ...

  5. Idea 配置Jrebel热部署

    虽说Idea自带热更新功能,但是一旦mapper更改,则不能及时更新,影响开发效率. 接下来,我们来配置Jrebel热更新,简单方便实用. 第一步:进入插件下载页面. 第二步:安装jrebel插件. ...

  6. 【转+】python为什么推荐使用多进程

    最近在看Python的多线程,经常我们会听到老手说:“Python下多线程是鸡肋,推荐使用多进程!”,但是为什么这么说呢?                要知其然,更要知其所以然.所以有了下面的深入研 ...

  7. SLES15SP1 AutoYast - PXE 技术

    由于最近在做几个Ceph项目,基本都是50个节点起,那我们在项目中经常使用PXE技术来实现系统自动化安装,提高效率,可能有会说PXE技术太老了没什么好了解,但我觉得的很实用,尤其在项目型工程中,通过P ...

  8. 夯实Java基础系列14:深入理解Java枚举类

    目录 初探枚举类 枚举类-语法 枚举类的具体使用 使用枚举类的注意事项 枚举类的实现原理 枚举类实战 实战一无参 实战二有一参 实战三有两参 枚举类总结 枚举 API 总结 参考文章 微信公众号 Ja ...

  9. IDEA 学习笔记之 Java项目开发深入学习(1)

    Java项目开发深入学习(1): 定义编译输出路径: 继承以上工程配置 重新定义新的项目编译路径 添加source目录:点击添加,再点击移除: 编译项目: 常用快捷键总结: Ctrl+Space 代码 ...

  10. IDEA 学习笔记之 Scala项目开发

    Scala项目开发: 由于直接下载Scala plugin太慢,老是中断,所以手动下载: https://plugins.jetbrains.com/ 手动安装Scala plugin: 新建Scal ...