SpringBoot系列: Spring支持的异常处理方式
===================================
视图函数返回 status code 的方式
===================================
Spring 有一个专门的枚举类型 HttpStatus, 比如 HttpStatus.NOT_FOUND
1. 视图函数返回 ResponseEntity 类型的对象.
2. 在 exception 类加注解 @ResponseStatus, 一旦视图函数抛出这个异常, Spring 就会自动返回设定的 status code.
3. 在视图函数上加 @ResponseStatus, 只要该函数没有报异常, Spring 就会自动返回设定的 status code.
===================================
方式一: 在业务 Controller 内部增加异常视图函数
===================================
在我们的 Controller 类中专门加一个或几个处理异常的视图函数, 这些异常处理视图需要加 @ExceptionHandler 注解.
将 @ExceptionHandler 注解的加到异常视图函数上, 也可以将 @ResponseStatus 注解一起加上. 异常视图函数的参数和普通视图函数的参数不一样, 能传入 Exception/HttpServletRequest/HttpServletResponse/HttpSession/Principle 等参数, 但是不能传入 Model 之类的参数, 视图方法的返回类型可以是: void/String 或 ModelAndView.
该方式缺点是: 这种异常处理仅仅在本 controller 有效, 不太好做到通用的异常处理. 当然也可设计一个通用的 Controller base 类, 在 base 类中加上异常处理视图函数, 所有业务 controller 都继承这个基类.
===================================
方式二: 实现一个基于 HandlerExceptionResolver 接口的 bean
===================================
在 Spring Web 项目中, 如果我们的 bean 实现了 HandlerExceptionResolver 接口, 一旦某个 controller 抛出异常, 这个 bean 会截获并处理异常.
该方法的缺点是: 不太好返回具体的报错内容.
一般情况下, 我们的 bean 并不直接实现 HandlerExceptionResolver 接口, 而是继承 SimpleMappingExceptionResolver 类.
通常做法是, 我们先自定义一个 SimpleMappingExceptionResolver 子类, 实现 doResolveException() 方法, 然后在 Mvc Configruation 配置类中, 声明一个名为 simpleMappingExceptionResolver 的 bean. 之所以继承 SimpleMappingExceptionResolver 类, 是因为它已经实现了很多有用的功能, 我们直接使用即可, 比如:
1. 设定 exception 和 view 视图的 mapping 关系等
2. 设置缺省的异常处理视图名
3. 异常 log 功能 (需启用)
除了 SimpleMappingExceptionResolver 类之外, Spring 还有其他几个 HandlerExceptionResolver 实现类, 作用分别是:
1. ExceptionHandlerExceptionResolver, 用来截获标注 @ExceptionHandler 注解的视图函数异常, @ExceptionHandler 加在专门的异常处理视图函数上.
2. ResponseStatusExceptionResolver, 用来截获和 @ResponseStatus 注解相关的异常, @ResponseStatus 可以加在 Exception 类或视图函数上.
3. DefaultHandlerExceptionResolver, 用来截获标准的 Spring exception, 并将异常转成相应 Http status code, 比如 404 等.
===================================
方式三: 使用 @ControllerAdvice 注解声明一个异常处理类
===================================
@ControllerAdvice 是 Spring 3.2 之后引入的. 在一个业务 controller 抛出异常后, @ControllerAdvice 标注的类会截获该异常. @ControllerAdvice 还有一个兄弟 @RestControllerAdvice 注解.
@ControllerAdvice 标注在类上, 具体异常视图函数仍然通过加 @ExceptionHandler 注解声明的, 该视图函数能传入 Exception/HttpServletRequest/HttpServletResponse/HttpSession/Principle 等参数, 但是不能传入 Model 之类的参数, 视图方法的返回类型可以是: void/String 或 ModelAndView.
@ControllerAdvice 优点有:
1. @ControllerAdvice 处理机制能接管所有 controller 类的异常, 更容易实现全局统一的异常处理.
2. 可以自由组合不同的 Exception 的异常处理视图.
3. 异常视图函数可以用 @ResponseStatus 注解指定返回码. 视图函数返回类型可以是 void/String 或 ModelAndView, 所以很容易返回报错内容.
4. 我们 @ControllerAdvice 注解类最好继承至 ResponseEntityExceptionHandler, 该 ResponseEntityExceptionHandler 类已经内置了很多标准异常的异常处理视图, 所以我们不需要再关心标准异常的处理, 只需要关心和业务相关的异常即可.
===================================
Spring Boot 默认的出错处理
===================================
Spring MVC 没有提供缺省的 fall-back 出错页, 而 Spring Boot 默认情况下就有很完善的报错处理机制, 一旦视图函数报错, Spring boot 先看有没有映射 /error 路径的视图, 有的话渲染该视图, 没有的话, 会展现 "Whitelabel Error Page", 该页面能显示出 Status code 和详细的报错信息. 如果是 Restful 请求的话, Whitelabel 报错也是 json 格式的反馈.
比如:
$> curl -H "Accept: application/json" http://localhost:8080/no-such-page
返回是:
{"timestamp":"2018-04-11T05:56:03.845+0000","status":404,"error":"Not Found","message":"No message available","path":"/no-such-page"}
默认缺省的异常处理路径是 /error, 也可以通过 server.error.path 属性修改.
Spring Boot 之所以有一个 whitelabel error页面, 是因为 Spring Boot 会注入一个 BasicErrorController 用来处理异常, 相关的 application 属性有:
server.error.include-exception=false # Include the "exception" attribute.
server.error.include-stacktrace=never # When to include a "stacktrace" attribute.
server.error.path=/error # Path of the error controller.
server.error.whitelabel.enabled=true # Whether to enable the default error page displayed in browsers in case of a server error.
如果缺省的 whitelabel 页面不能满足需求, 可以简单定制 page 页, 在 resources 目录下, 新建一个 error.html 模板文件, 在文件中, 可以使用下面的变量.
${timestamp} 、 ${path} 、 ${error} 、 ${status} 、 ${message} 、 ${exception}、 ${trace}
比如要对 404 访问做日志, 我们可以仿造 BasicErrorController 写一个自己的 ErrorController 类. Spring boot 会自动这个 ErrorController 实例代替缺省的 ErrorController.
===================================
推荐的做法:
===================================
1. 在一个项目中, 仅使用一种异常处理方法, 不要组合使用, 因为有可能和我们的预期不一致.
2. 推荐使用全局性的异常处理, 而不是 Controller 级别的异常处理; 推荐 @ControllerAdvice, 而不是基于 HandlerExceptionResolver 接口的 bean.
3. @ControllerAdvice 注解类最好继承至 ResponseEntityExceptionHandler, 该 ResponseEntityExceptionHandler 类已经内置了很多标准异常的异常处理视图, 所以我们不需要再关心标准异常的处理, 只需要关心和业务相关的异常即可.
需要说明的是, 只有进入 Controller 的异常, @ControllerAdvice 才能捕获, 对于拦截器的异常和 url写错这类404 这样的异常, 是捕获不到的, 当然一般情况下我们也没有必要处理这些异常, 如果一定要对 404 访问做日志, 我们可以仿造 BasicErrorController 写一个自己的 ErrorController 类.
下面是一个简单的示意代码:
@ControllerAdvice
class GlobalExceptionHandler extends ResponseEntityExceptionHandler { // 针对不同的异常, 定义其处理视图函数
// some view functions // 对应 uncaughted 异常, 使用下面这个视图函数来兜底
public static final String DEFAULT_ERROR_VIEW = "error";
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, HttpServletResponse rep, Exception e) throws Exception {
//针对 500 错误, 需要记录 error 日志.
logger.error(e.getMessage(),e);
if (req.getHeader("Accept").contains("application/json"))
{
//write json to HttpServletResponse
return null;
}
else{
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}
}
===================================
参考:
===================================
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
https://blog.csdn.net/aiyaya_/article/details/78725755
http://blog.didispace.com/springbootexception/
https://blog.csdn.net/chinrui/article/details/71036544
http://tengj.top/2018/05/16/springboot13/
SpringBoot系列: Spring支持的异常处理方式的更多相关文章
- SpringBoot系列之集成Dubbo的方式
SpringBoot系列之集成Dubbo的方式 本博客介绍Springboot框架集成Dubbo实现微服务的3种常用方式,对于Dubbo知识不是很熟悉的,请先学习我上一篇博客:SpringBoot系列 ...
- SpringBoot系列: Spring项目异常处理最佳实践
===================================自定义异常类===================================稍具规模的项目, 一般都要自定义一组异常类, 这 ...
- SpringBoot系列-整合Mybatis(注解方式)
目录 一.常用注解说明 二.实战 三.测试 四.注意事项 上一篇文章<SpringBoot系列-整合Mybatis(XML配置方式)>介绍了XML配置方式整合的过程,本文介绍下Spring ...
- SpringBoot系列: Spring MVC视图方法的补充
SpringMVC 视图方法的参数, 已经在这个文章中写得非常清楚了, 链接为 https://www.cnblogs.com/morethink/p/8028664.html 这篇文章做一些补充. ...
- [SpringBoot系列]--Spring Hibernate search 注解实现(未测试)
1.maven项目pom.xml加入依赖 <dependency> <groupId>org.hibernate</groupId> <artifactId& ...
- SpringBoot系列随笔 - BootJar的启动方式
前言 写完maven的加密插件后,尝试在boot启动时的类加载过程中编写解密代码时,发现了一个平常没有注意的地方. 那就是boot-jar的启动方式与我们平常编写的可执行jar是存在很大差别的. 所以 ...
- SpringBoot系列之学习教程汇总
对应SpringBoot系列博客专栏,例子代码,本博客不定时更新 一.配置篇 SpringBoot系列之@PropertySource读取yaml文件 >> source down ...
- SpringBoot系列之从入门到精通系列教程
对应SpringBoot系列博客专栏,例子代码,本博客不定时更新 Spring框架:作为JavaEE框架领域的一款重要的开源框架,在企业应用开发中有着很重要的作用,同时Spring框架及其子框架很多, ...
- SpringBoot系列: RestTemplate 快速入门
====================================相关的文章====================================SpringBoot系列: 与Spring R ...
随机推荐
- jquery-插件iCheck 使用
这是一个兼容多种浏览器的插件 官网:http://icheck.fronteed.com/ 官方给出了很多的例子,我说一个使用的问题. 使用的时候,要放到window..load的外部. 页面html ...
- Eclipse安装Gradle插件
1.window下安装Gradle见https://www.cnblogs.com/felixzh/p/9203271.html2.eclipse中依次打开help>Install new so ...
- 洛谷P2243 电路维修
题目地址 转化为图论问题 对于每个交叉点(X,Y)抽象成节点.与它相邻的四个点中,可以直接连线的边权为0,否则边权为1. 用死了的SPFA解决图论问题. #include <cstring> ...
- https进行配置以及http跳转到https配置
https配置: nginx配置 server { listen 443; server_name localhost; ssl on; root html; index index.html ind ...
- A. Points in Segments(cf a题, 水题)
没什么好说的 #include<iostream> using namespace std; ], x, y,n, m, ans; int main(){ cin>>n> ...
- CentOS 7 minimal配置网络连接及net-tools安装
在Virtual Box中安装好CentOS 7的minimal后,第一件事就是设置网络访问. 首先需要用 nmtui 命令进入 Network Manager,如下: 选择 Edit a conne ...
- Linux 实例常用内核网络参数介绍与常见问题处理
本文总结了常见的 Linux 内核参数及相关问题.修改内核参数前,您需要: 从实际需要出发,最好有相关数据的支撑,不建议随意调整内核参数. 了解参数的具体作用,且注意同类型或版本环境的内核参数可能有所 ...
- Java高级篇(四)——反射
之前写到了设计模式的代理模式,因为下一篇动态代理等内容需要用到反射的知识,所以在之前Java篇的基础上再写一篇有关反射的内容,还是以实际的程序为主,了解反射是做什么的.应该怎么用. 一.什么是反射 反 ...
- adb.exe 已停止工作 解决
netstat -aon|findstr 5037tasklist /fi "PID eq 10388"TASKKILL /F /IM PPAdbServer.exe
- Bean的自动装配
再说自动装配之前,我们先聊一聊什么是手动装配. 手动装配就是我们在先前讲的那些,要自己给定属性,然后赋值 Spring IOC容器可以自动装配Bean,需要做的仅仅实在<bean>的aut ...