[六字真言]4.叭.SpringMVC异常痛苦
“叭”,除畜生道劳役之苦;
在学过的三阶段的时候,我们对SpringMVC的异常处理,一直可以算是简单中透着暴力,不要不重视异常!真的很重要,不要让它处在尴尬的位置!
在二阶段或者说三阶段中,技术一方面其中我认为最关键的地方是MVC思想的理解,对MVC理解程度决定着你学习过程中的难易程度,虽然有点夸张!
例如,当我们产生了一个 非业务异常
,或者 非本业务可以处理的其他业务异常
,那么我们一般会一直往 上层抛
(或者适当包装后继续抛出)直到 控制层
[我们就是这么解决问题,不知道你是否还记得],之后,控制层进行异常日志记录然后响应用户错误页面和信息。
如果每个控制器都写一个异常处理未免也太多冗余了,好在强大的 Spring 给我们提供了很多种解决方案,这里介绍其中一种 @ControllerAdvice [个人认为目前最好的方案之一,XML方式的简单统一异常处理,这里就不说了]。
1. 为什么现在我才告诉你呢?
看该注解字面上的意思就是 控制器通知
。
Advice 是AOP中的概念,这里简单介绍下。
我们使用AOP切入某一目标方法,那么该方法在切面的角度看来可以有几个执行阶段:
- 目标方法调用前(before)- 前置通知
- 目标方法调用后(after)- 后置通知
- 目标方法返回后(after return)- 返回通知
- 目标方法调用前后(around)- 环绕通知
- 目标方法抛出异常时(throw)- 异常通知
是否还记得每种通知的特点呢?呵呵!忘记了吧!
去看笔记或者PPT吧!!!
当执行到某个阶段的时候都会有不同阶段类型 Advice 发出,然后你可以根据不同阶段类型的通知对切入点进行一些 增强处理
了。
在不改动原来代码的基础上,增加新的功能!
看看如何声明@ControllerAdvice
/**
* 全局异常处理器
* @author 胖先生
*
*/
@ControllerAdvice
public class GlobalExceptionHandler {
}
So Easy!标注完之后,该类就变成一个控制器通知处理器了,接着我们需要进行一些通知的处理。
解除痛苦
在该类中的方法上标注 @ExceptionHandler 可以将指定方法变成一个异常通知处理方法,处理的异常类型可使用参数指定。除了 @ExceptionHandler 之外还有其他的通知类型,具体可参阅官方文档,本文只以异常处理为例子,事实上运用最广泛的也就是异常处理而已了。
新增以下代码可以处理 HttpRequestMethodNotSupportedException
(HTTP方法不支持):
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
@ResponseBody
public Result<String> httpRequestMethodNotSupportedExceptionHandler(HttpServletRequest req, Exception e) throws Exception{
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
throw e;
// Otherwise setup and send the user to a default error-view.
// 这里你可以自由发挥,咱在这里给前端返回了一个错误提醒的Json
Result<String> result = new Result<>(false);
result.setError(HohistarExceptionReason.BIZ_10070);
return result;
}
新增以下代码可以处理 MethodArgumentNotValidException(Validator字段校验失败异常处理):
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public Result<String> methodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e) throws Exception{
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
throw e;
BindingResult bindingResult = e.getBindingResult();
// Otherwise setup and send the user to a default error-view.
Result<String> result = new Result<>(false);
FieldError firstError = bindingResult.getFieldErrors().get(0);
result.setError(HohistarExceptionReason.BIZ_10074, firstError.getField(), firstError.getDefaultMessage());
return result;
}
如果要成功捕获 MethodArgumentNotValidException
,在控制器方法上就不能定义 BindingResult
参数接收校验结果,不然如果校验失败 Spring
是不会抛出 MethodArgumentNotValidException
异常的,自然而然在我们的 GlobalExceptionHandler
就无法处理了。
一个都不放过
如果你要捕获任何漏网之异常,你可以新增以下暴力的代码:
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result<String> defaultExceptionHandler(HttpServletRequest req, Exception e) throws Exception {
// If the exception is annotated with @ResponseStatus rethrow it and let
// the framework handle it - like the OrderNotFoundException example
// at the start of this post.
// AnnotationUtils is a Spring Framework utility class.
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
throw e;
String throwClassName = e.getStackTrace()[0].getClassName();
Logger logger = getLogger(throwClassName);
logger.error("GlobalExceptionHandler catch a Server Exception: ", e);
// Otherwise setup and send the user to a default error-view.
Result<String> result = new Result<>(false);
if(BeanUtils.isNotEmpty(this.defaultExceptionReason)){
result.setError(HohistarExceptionReason.valueOf(this.defaultExceptionReason));
} else {
result.setError(HohistarExceptionReason.INTL_20001);
}
return result;
}
在 GlobalExceptionHandler
中可以有多个 @ExceptionHandler
标注的方法,如果控制器中抛出了一个异常,而且没有匹配任何其他类型的异常处理方法,那么上方的方法将会被通知执行, 保证从控制器抛出的异常一定会受到处理
。
大部分代码来自官方文档:这里大部分摘抄Spring官方手册
[六字真言]4.叭.SpringMVC异常痛苦的更多相关文章
- [六字真言]6.吽.SpringMVC中上传大小异常填坑
最近在讲课的时候,遇到了关于上传文件过大的时候浏览器无法响应的问题,配置了捕获异常,有的学生浏览器好使,有的学生浏览器不好用!莫名其妙! MaxUploadSizeExceededException进 ...
- [六字真言]2.嘛.异常定制和通用.md
幻世当空 恩怨休怀 舍悟离迷 六尘不改 且怒且悲且狂哉! 最近一直在循环的一首歌! 丰富自己,比取悦他人更有力量.种下梧桐树,引得凤凰来.你若盛开,蝴蝶自来! 言归正传! 言归正传! 不要去大包大揽 ...
- [六字真言]5.咪.功力不足,学习前端JavaScript异常
A Guide to Proper Error Handling in JavaScript 这是关于JavaScript中异常处理的故事.如果你相信 墨菲定律 ,那么任何事情都可能出错,不,一定会出 ...
- 七字真言解读TCP三次握手
三次握手所谓的"三次握手"即对每次发送的数据量是怎样跟踪进行协商使的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送.接收完毕后何时撤消联系,并建立虚连接. 一.七 ...
- springMVC 异常
springMVC 异常 0.依赖(不只是本次案例所需) <?xml version="1.0" encoding="UTF-8"?> <p ...
- SpringMVC异常的处理机制
SpringMVC异常的处理机制 处理流程图 其本质还是把异常交给SpringMVC框架来处理 系统的dao.service.controller出现异常都通过throws Exception向上抛出 ...
- SpringMVC异常处理器
本节内容: 异常处理思路 自定义异常类 自定义异常处理器 异常处理器配置 错误页面 异常测试 springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异 ...
- springMVC异常&&重定向&&转发
SpringMVC核心技术---转发和重定向 当处理器对请求处理完毕后,向其他资源进行跳转时,有两种跳转方式:请求转发与重定向.而根据要跳转的资源类型,又可分为两类:跳转到页面与跳转到其他处理器.对于 ...
- SSM-SpringMVC-26:SpringMVC异常骇级之自定义异常注解版
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 注解的方法实现异常解析,话不多说,直接搞起,和以前一样的习惯,和上篇博客一样的代码放后面,不一样的在前面 案 ...
随机推荐
- Flutter - 创建侧滑菜单(不使用navigatior,仅改变content)
之前写过一篇文章,Flutter - 创建横跨所有页面的侧滑菜单.这个里面中使用了Navigator.of(context).push来导航到新的页面. 这次介绍一种不使用导航,仅仅改变content ...
- ReactJS实用技巧(2):从新人大坑——表单组件来看State
不太清楚有多少初学React的同学和博主当时一样,在看完React的生命周期.数据流之后觉得已经上手了,甩开文档啪啪啪的开始敲了起来.结果...居然被一个input标签给教做人了. 故事是这样的:首先 ...
- bower配置私服nexus3
内容来自 https://help.sonatype.com/repomanager3/bower-repositories#BowerRepositories-BrowsingBowerReposi ...
- PAT甲题题解-1033. To Fill or Not to Fill (25)-模拟
模拟先说一下例子,最后为方便起见,在目的地安增加一个费用为0的加油站0 1 2 3 4 5 6 7 87.1 7.0 7.2 6.85 7.5 7.0 7.3 6.0 00 150 200 300 4 ...
- 作业要求20160901 从edu.cnblogs.com中抄过来的,备忘
[已完成] 杨贵福 发布于 2016-09-01 21:51 开通技术博客,博客园 cnblogs 关注 杨贵福 younggift,回贴 "构建之法东北师大站,继续 2016秋" ...
- Linux内核分析作业四
扒开系统调用的三层皮 一.用户态.内核态和中断 一般现代CPU都有几种不同的指令级别 在高级别执行级别下,代码可以执行特权指令,访问任意的物理地址,称之为内核态 在相应的低指令执行级别下,代码的掌控范 ...
- Office处理
1.NPOI:一个开源项目,不需要安装Microsoft Office,支持对Office 97-2003,2007文件格式,功能比较强大. http://npoi.codeplex.com/ 2.a ...
- [菜鸟]HTTP 与 HTTPS 的区别
HTTP 与 HTTPS 的区别 分类 编程技术 基本概念 HTTP(HyperText Transfer Protocol:超文本传输协议)是一种用于分布式.协作式和超媒体信息系统的应用层协议. 简 ...
- [专贴]Xshell 以及 shell 的快捷键
Ctrl + a 切换到命令行开始Ctrl + e 切换到命令行末尾Ctrl + l 清除屏幕内容Ctrl + u 清除光标之前的内容Ctrl + k 清除光标之后的内容Ctrl + h 类似于退格键 ...
- 在laravel中,使用DB查询数据库后,返回的对象,可以用下面的办法变为数组
$nodes = Db::table('account')->orderBy('sort', 'asc')->orderBy('id' ,'asc')->get()->map( ...