===================================
视图函数返回 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支持的异常处理方式的更多相关文章

  1. SpringBoot系列之集成Dubbo的方式

    SpringBoot系列之集成Dubbo的方式 本博客介绍Springboot框架集成Dubbo实现微服务的3种常用方式,对于Dubbo知识不是很熟悉的,请先学习我上一篇博客:SpringBoot系列 ...

  2. SpringBoot系列: Spring项目异常处理最佳实践

    ===================================自定义异常类===================================稍具规模的项目, 一般都要自定义一组异常类, 这 ...

  3. SpringBoot系列-整合Mybatis(注解方式)

    目录 一.常用注解说明 二.实战 三.测试 四.注意事项 上一篇文章<SpringBoot系列-整合Mybatis(XML配置方式)>介绍了XML配置方式整合的过程,本文介绍下Spring ...

  4. SpringBoot系列: Spring MVC视图方法的补充

    SpringMVC 视图方法的参数, 已经在这个文章中写得非常清楚了, 链接为 https://www.cnblogs.com/morethink/p/8028664.html 这篇文章做一些补充. ...

  5. [SpringBoot系列]--Spring Hibernate search 注解实现(未测试)

    1.maven项目pom.xml加入依赖 <dependency> <groupId>org.hibernate</groupId> <artifactId& ...

  6. SpringBoot系列随笔 - BootJar的启动方式

    前言 写完maven的加密插件后,尝试在boot启动时的类加载过程中编写解密代码时,发现了一个平常没有注意的地方. 那就是boot-jar的启动方式与我们平常编写的可执行jar是存在很大差别的. 所以 ...

  7. SpringBoot系列之学习教程汇总

    对应SpringBoot系列博客专栏,例子代码,本博客不定时更新 一.配置篇 SpringBoot系列之@PropertySource读取yaml文件     >> source down ...

  8. SpringBoot系列之从入门到精通系列教程

    对应SpringBoot系列博客专栏,例子代码,本博客不定时更新 Spring框架:作为JavaEE框架领域的一款重要的开源框架,在企业应用开发中有着很重要的作用,同时Spring框架及其子框架很多, ...

  9. SpringBoot系列: RestTemplate 快速入门

    ====================================相关的文章====================================SpringBoot系列: 与Spring R ...

随机推荐

  1. docker swarm的常用操作

    1. 说明 本文档针对docker swarm操作. 针对的系统是以一个本地的测试系统为例.其中机器信息如下,172.16.1.13作为docker swarm的管理机. 本地测试的机器列表信息: 主 ...

  2. pymongo 一篇文章搞定

    一 安装 pip install pymongo 二 python连接mongodb数据库的前提 确保pymongo安装完毕 mongodb数据库的服务器端(mongod)必须处于启动状态 三 连接m ...

  3. spring boot +mybatis(通过properties配置) 集成

    注:日常学习记录贴,下面描述的有误解的话请指出,大家一同学习. 因为我公司现在用的是postgresql数据库,所以我也用postgresql进行测试 一.前言 1.Spring boot 会默认读取 ...

  4. ElasticSearch(九):elasticsearch-head插件安装

    安装node 安装elasticsearch-head需要node.js的支持. 下载最新的node.js,下载地址:https://nodejs.org/en/download/ 将下载后的安装包放 ...

  5. Linux:Day12(下) 进程、任务计划

    vmstat命令: vmstat [options] [delay [ count]] procs: r:等待运行的进程的个数: b:处于不可中断睡眠态的进程个数:(被阻塞的队列的长度): memor ...

  6. 前端——jQuery

    初识jQuery 什么是jQuery? jQuery就是JavaScript和Query,是辅助JavaScript开发的库,应用广泛,形成了行业标准.它对DOM操作做了很好的封装,我们可以用jQue ...

  7. Text Mining and Analytics WEEK1

    第一周目标 解释自然语言处理中的一些基本概念 解释不同的方式来表示文本数据 解释的两种基本的词联想以及如何从文本数据挖掘聚合关系 尝试回答以下问题 为了理解一个自然语言句子,计算机必须做些什么? 什么 ...

  8. vue style标签中使用less

    只需要下载相应的包即可:(前提是使用vue-cli搭建的项目) 1.安装less依赖,npm install less less-loader --save 2.即可在相应的vue文件中使用less操 ...

  9. KeyError: 'Spider not found: test'

    Error Msg: File "c:\python36\lib\site-packages\scrapy\cmdline.py", line 157, in _run_comma ...

  10. Codeforces Round #546 (Div. 2)-D - Nastya Is Buying Lunch

    这道题,神仙贪心题... 题意就是我给出数的顺序,并给出多个交换,每个只能用于相邻交换,问最后一个元素,最多能往前交换多少步. 我们考虑这样一个问题,如果一个这数和a[n]发生交换,那么这个数作为后面 ...