十四、springboot全局处理异常(@ControllerAdvice + @ExceptionHandler)
1.@ControllerAdvice
1.场景一
在构建RestFul的今天,我们一般会限定好返回数据的格式比如:
{ "code": 0,
"data": {},
"msg": "操作成功" }
但有时却往往会产生一些bug。这时候就破坏了返回数据的一致性,导致调用者无法解析。所以我们常常会定义一个全局的异常拦截器。
2.场景二
对于与数据库相关的 Spring MVC 项目,我们通常会把 事务 配置在 Service层,当数据库操作失败时让 Service 层抛出运行时异常,Spring 事物管理器就会进行回滚。
如此一来,我们的 Controller 层就不得不进行 try-catch Service 层的异常,否则会返回一些不友好的错误信息到客户端。但是,Controller 层每个方法体都写一些模板化的 try-catch 的代码,很难看也难维护,特别是还需要对 Service 层的不同异常进行不同处理的时候。
@ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理,只要设计得当,就再也不用在 Controller 层进行 try-catch 了!而且,@Validated 校验器注解的异常,也可以一起处理,无需手动判断绑定校验结果 BindingResult/Errors 了
3.@ControllerAdvice的使用
1.注意
- 优点:将 Controller 层的异常和数据校验的异常进行统一处理,减少模板代码,减少编码量,提升扩展性和可维护性。
- 缺点:只能处理 Controller 层未捕获(往外抛)的异常,对于 Interceptor(拦截器)层的异常,Spring 框架层的异常,就无能为力了。
2.@ControllerAdvice
该注解是springMVC的注解
@ControllerAdvice
是一个@Component
,用于定义@ExceptionHandler
,@InitBinder
和@ModelAttribute
方法,适用于所有使用@RequestMapping
方法。Spring4之前,
@ControllerAdvice
在同一调度的Servlet中协助所有控制器。Spring4已经改变:@ControllerAdvice
支持配置控制器的子集,而默认的行为仍然可以利用。在Spring4中,
@ControllerAdvice
通过annotations()
,basePackageClasses()
,basePackages()
方法定制用于选择控制器子集。
不过据经验之谈,只有配合@ExceptionHandler
最有用,其它两个不常用。
3.使用
@ControllerAdvice 注解定义全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
}
@ExceptionHandler 注解声明异常处理方法
@ControllerAdvice
public class GlobalExceptionHandler { @ExceptionHandler(Exception.class)
@ResponseBody
String handleException(){
return "Exception Deal!";
}
}
方法 handleException() 就会处理所有 Controller 层抛出的 Exception 及其子类的异常,这是最基本的用法了。
被 @ExceptionHandler 注解的方法的参数列表里,还可以声明很多种类型的参数,详见文档。其原型如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler { /**
* Exceptions handled by the annotated method. If empty, will default to any
* exceptions listed in the method argument list.
*/
Class<? extends Throwable>[] value() default {}; }
如果 @ExceptionHandler 注解中未声明要处理的异常类型,则默认为参数列表中的异常类型。所以上面的写法,还可以写成这样:
@ControllerAdvice
public class GlobalExceptionHandler { @ExceptionHandler()
@ResponseBody
String handleException(Exception e){
return "Exception Deal! " + e.getMessage();
}
}
参数对象就是 Controller 层抛出的异常对象!
示例
package com.cmc.schedule.handler; import com.gionee.base.entity.JsonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import java.io.IOException; /**
* 异常拦截处理器
*
* @author chenmc
*/
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler { private static final String logExceptionFormat = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";
private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); //运行时异常
@ExceptionHandler(RuntimeException.class)
public String runtimeExceptionHandler(RuntimeException ex) {
return resultFormat(1, ex);
} //空指针异常
@ExceptionHandler(NullPointerException.class)
public String nullPointerExceptionHandler(NullPointerException ex) {
return resultFormat(2, ex);
} //类型转换异常
@ExceptionHandler(ClassCastException.class)
public String classCastExceptionHandler(ClassCastException ex) {
return resultFormat(3, ex);
} //IO异常
@ExceptionHandler(IOException.class)
public String iOExceptionHandler(IOException ex) {
return resultFormat(4, ex);
} //未知方法异常
@ExceptionHandler(NoSuchMethodException.class)
public String noSuchMethodExceptionHandler(NoSuchMethodException ex) {
return resultFormat(5, ex);
} //数组越界异常
@ExceptionHandler(IndexOutOfBoundsException.class)
public String indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
return resultFormat(6, ex);
} //400错误
@ExceptionHandler({HttpMessageNotReadableException.class})
public String requestNotReadable(HttpMessageNotReadableException ex) {
System.out.println("400..requestNotReadable");
return resultFormat(7, ex);
} //400错误
@ExceptionHandler({TypeMismatchException.class})
public String requestTypeMismatch(TypeMismatchException ex) {
System.out.println("400..TypeMismatchException");
return resultFormat(8, ex);
} //400错误
@ExceptionHandler({MissingServletRequestParameterException.class})
public String requestMissingServletRequest(MissingServletRequestParameterException ex) {
System.out.println("400..MissingServletRequest");
return resultFormat(9, ex);
} //405错误
@ExceptionHandler({HttpRequestMethodNotSupportedException.class})
public String request405(HttpRequestMethodNotSupportedException ex) {
return resultFormat(10, ex);
} //406错误
@ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
public String request406(HttpMediaTypeNotAcceptableException ex) {
System.out.println("406...");
return resultFormat(11, ex);
} //500错误
@ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
public String server500(RuntimeException ex) {
System.out.println("500...");
return resultFormat(12, ex);
} //栈溢出
@ExceptionHandler({StackOverflowError.class})
public String requestStackOverflow(StackOverflowError ex) {
return resultFormat(13, ex);
} //其他错误
@ExceptionHandler({Exception.class})
public String exception(Exception ex) {
return resultFormat(14, ex);
} private <T extends Throwable> String resultFormat(Integer code, T ex) {
ex.printStackTrace();
log.error(String.format(logExceptionFormat, code, ex.getMessage()));
return JsonResult.failed(code, ex.getMessage());
} }
注:
springboot中这样就可以了!!!
如果是springMVC配置文件中增加下面的配置
<!-- 处理异常 -->
<context:component-scan base-package="com.gionee.xo" use-default-filters="false">
<!-- base-package 如果多个,用“,”分隔 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<!--控制器增强,使一个Contoller成为全局的异常处理类,类中用@ExceptionHandler方法注解的方法可以处理所有Controller发生的异常-->
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>
参考:
https://blog.csdn.net/kinginblue/article/details/70186586
https://blog.csdn.net/u014044812/article/details/78219692
https://blog.csdn.net/w372426096/article/details/78429141
十四、springboot全局处理异常(@ControllerAdvice + @ExceptionHandler)的更多相关文章
- “全栈2019”Java异常第十四章:将异常输出到文本文件中
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- (转)springboot全局处理异常(@ControllerAdvice + @ExceptionHandler)
1.@ControllerAdvice 1.场景一 在构建RestFul的今天,我们一般会限定好返回数据的格式比如: { "code": 0, "data": ...
- spring boot 学习(十四)SpringBoot+Redis+SpringSession缓存之实战
SpringBoot + Redis +SpringSession 缓存之实战 前言 前几天,从师兄那儿了解到EhCache是进程内的缓存框架,虽然它已经提供了集群环境下的缓存同步策略,这种同步仍然需 ...
- 十四.spring-boot使用mybatis
在springMVC+spring中使用mybatis已经非常非常的灵活,但是需要配置很多的信息 一.创建maven web project 二.创建数据库表 三.在application.prope ...
- [十四]SpringBoot 之 Spring拦截器(HandlerInterceptor)
过滤器属于Servlet范畴的API,与spring 没什么关系. Web开发中,我们除了使用 Filter 来过滤请web求外,还可以使用Spring提供的HandlerInterceptor(拦截 ...
- @ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常==》记录
对于与数据库相关的 Spring MVC 项目,我们通常会把 事务 配置在 Service层,当数据库操作失败时让 Service 层抛出运行时异常,Spring 事物管理器就会进行回滚. 如此一来, ...
- @ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常
@ControllerAdvice 和 @ExceptionHandler 的区别 ExceptionHandler, 方法注解, 作用于 Controller 级别. ExceptionHandle ...
- 转:@ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常
继承 ResponseEntityExceptionHandler 类来实现针对 Rest 接口 的全局异常捕获,并且可以返回自定义格式: 复制代码 1 @Slf4j 2 @ControllerAdv ...
- Spring @ControllerAdvice @ExceptionHandler 全局处理异常
对于与数据库相关的 Spring MVC 项目,我们通常会把 事务 配置在 Service层,当数据库操作失败时让 Service 层抛出运行时异常,Spring 事物管理器就会进行回滚. 如此一来, ...
随机推荐
- 解决一起web 页面被劫持的案例
现象 江西客户手机端连接wifi打开URL,页面上显示淘宝店铺广告,使用手机移动网络打开正常,其他地区正常. 二. 处理过程 初步分析:3g.club项目使用了CDN,目前只有江西异常,其他地区无异常 ...
- Spring.NET依赖注入框架学习-- 泛型对象的创建和使用
Spring.NET依赖注入框架学习-- 泛型对象的创建和使用 泛型对象的创建方法和普通对象是一样的. 通过构造器创建泛型对象 下面是一个泛型类的代码: namespace GenericsPlay ...
- Android 性能分析工具 TraceView
官方地址 http://developer.android.com/tools/debugging/debugging-tracing.html 推荐:http://blog.csdn.net/inn ...
- Ubuntu 14.04 LTS 火狐浏览器中,鼠标选择文字被删除的解决办法
这篇文章主要介绍了Ubuntu 火狐浏览器中,鼠标选择文字被删除的解决办法,需要的朋友可以参考下在终端中输入命令: ibus-setup将 “在应用程序窗口中启用内嵌编辑模式“ 选项取消
- Matlab当中size() length()等函数讲解
在Matlab中: size:获取数组的行数和列数 length:数组长度(即行数或列数中的较大值) numel:元素总数. s=size(A): 当只有一个输出参数时,返回一个行向量,该行向量的第一 ...
- sencha touch 在安卓中横屏、竖屏切换 应用崩溃问题
答案来至于 Sencha Touch 交流 @周旭 这是由于横竖屏转换导致activity重跑onCreate方法导致的,有两种解决方案:1.横竖屏转换的时候不要重新跑onCreate方法,这个可以在 ...
- Linux上VNC 启动和关闭常见问题
0, 重设密码 [root@yqrh5u2 ~]# vncpasswd Password: Verify: [root@yqrh5u2 ~]# 1, ...
- vscode 使用sublime风格代码
Monokai 主题 One Dark Pro主题 vscode设置字体 "editor.fontFamily": "MONACO, Consolas, 'Couri ...
- zabbix监控日志文件
环境: 操作系统:centos 6.8 ,zabbix软件版本:zabbix 3.0.1 前提条件:zabbix客户端已经配置了主动模式,如何配置主动模式,请参考此文 监控日志keys 首先要了解k ...
- Gym - 101020H Weekend floyd+next_permutation
https://vjudge.net/problem/Gym-101020H 题意:正常读取方式给你一个图(双向的),然后给你f个点,让你找一条路从1到n的最短路,要求经过f个点(以任意顺序). 题解 ...