精通Spring Boot —— 第十五篇:使用@ControllerAdvice处理异常
在Spring 3.2中,新增了@ControllerAdvice、@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping、@PostMapping, @GetMapping注解中。
接下来我将通过代码展示如何使用这些注解,以及处理异常。
1.注解的介绍
先定义一个ControllerAdvice。代码如下
/*** @author Lensen* @desc* @since 2018/10/5 11:01*/
@ControllerAdvice
public class MyExceptionHandler {/*** 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器* @param binder*/@InitBinderpublic void initWebBinder(WebDataBinder binder){//对日期的统一处理binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));//添加对数据的校验//binder.setValidator();}/*** 把值绑定到Model中,使全局@RequestMapping可以获取到该值* @param model*/@ModelAttributepublic void addAttribute(Model model) {model.addAttribute("attribute", "The Attribute");}/*** 捕获CustomException* @param e* @return json格式类型*/@ResponseBody@ExceptionHandler({CustomException.class}) //指定拦截异常的类型@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //自定义浏览器返回状态码public Map<String, Object> customExceptionHandler(CustomException e) {Map<String, Object> map = new HashMap<>();map.put("code", e.getCode());map.put("msg", e.getMsg());return map;}/*** 捕获CustomException* @param e* @return 视图*/
// @ExceptionHandler({CustomException.class})
// public ModelAndView customModelAndViewExceptionHandler(CustomException e) {
// Map<String, Object> map = new HashMap<>();
// map.put("code", e.getCode());
// map.put("msg", e.getMsg());
// ModelAndView modelAndView = new ModelAndView();
// modelAndView.setViewName("error");
// modelAndView.addObject(map);
// return modelAndView;
// }
}
需要注意的是使用@ExceptionHandler注解传入的参数可以一个数组,且使用该注解时,传入的参数不能相同,也就是不能使用两个@ExceptionHandler去处理同一个异常。如果传入参数相同,则初始化ExceptionHandler时会失败。
对于@ControllerAdvice注解,我们来看看源码的定义:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};Class<?>[] basePackageClasses() default {};Class<?>[] assignableTypes() default {};Class<? extends Annotation>[] annotations() default {};
}
我们可以传递basePackage,声明的类(是一个数组)指定的Annotation参数,具体参考:spring framework doc
2.异常的处理
编写自定义异常类
package com.developlee.errorhandle.exception;/*** @author Lensen* @desc 自定义异常类* @since 2018/10/5 11:04*/
public class CustomException extends RuntimeException {private long code;private String msg;public CustomException(Long code, String msg){this.code = code;this.msg = msg;}public long getCode() {return code;}public void setCode(long code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}
Spring 对于 RuntimeException类的异常才会进行事务回滚,所以我们一般自定义异常都继承该异常类。
编写全局异常处理类
/*** @author Lensen* @desc* @since 2018/10/5 11:01*/
@ControllerAdvice("com.developlee.errorhandle")
public class MyExceptionHandler {/*** 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器* @param binder*/@InitBinderpublic void initWebBinder(WebDataBinder binder){}/*** 把值绑定到Model中,使全局@RequestMapping可以获取到该值* @param model*/@ModelAttributepublic void addAttribute(Model model) {model.addAttribute("attribute", "The Attribute");}/*** 捕获CustomException* @param e* @return json格式类型*/@ResponseBody@ExceptionHandler({CustomException.class}) //指定拦截异常的类型@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //自定义浏览器返回状态码public Map<String, Object> customExceptionHandler(CustomException e) {Map<String, Object> map = new HashMap<>();map.put("code", e.getCode());map.put("msg", e.getMsg());return map;}/*** 捕获CustomException* @param e* @return 视图*/
// @ExceptionHandler({CustomException.class})
// public ModelAndView customModelAndViewExceptionHandler(CustomException e) {
// Map<String, Object> map = new HashMap<>();
// map.put("code", e.getCode());
// map.put("msg", e.getMsg());
// ModelAndView modelAndView = new ModelAndView();
// modelAndView.setViewName("error");
// modelAndView.addObject(map);
// return modelAndView;
// }
}
测试
在controller中抛出自定义异常
/*** @author Lensen* @desc* @since 2018/10/5 11:00*/
@Controller
public class DemoController {/*** 关于@ModelAttribute,* 可以使用ModelMap以及@ModelAttribute()来获取参数值。*/ @GetMapping("/one")public String testError(ModelMap modelMap ) {throw new CustomException(500L, "系统发生500异常!" + modelMap.get("attribute"));}@GetMapping("/two")public String testTwo(@ModelAttribute("attribute") String attribute) {throw new CustomException(500L, "系统发生500异常!" + attribute);}
}
启动应用,范围localhost:8080/one.返回报文为:
{"msg":"系统发生500异常!The Attribute","code":500}
可见我们的@InitBinder和@ModelAttribute注解生效。且自定义异常被成功拦截。如果全部异常处理都返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody。@RestControllerAdvice在注解上已经添加了@ResponseBody。
最后,以上示例代码可在我的github.com中找到。
我的个人公众号:developlee的潇洒人生。
关注了也不一定更新,更新就不得了了。
相关文章:
架构设计之分布式文件系统
1:类图 2:数据结构 create table TBCOFILE ( FILEID INTEGER not null, FILETIME DATE, TYPE VARCHAR2(10), USERID INTEGER, IP VARCHAR2(20), APPTYPE INTEGER default 0) 3:开发步骤 1:从数据库申…

1029 Median
1. 开始测试点3和6答案错误,原因是没有考虑到,给的两个数列有可能长度相差很大,某个数列还没到中位数,就结束了。 2. 这题的底子是用two pointers按照非递减的顺序合并两个数列,无非是再确定一下中间那个数的下标&…

理解系统底层的概念是多么重要
理解系统底层的概念是多么重要 ——趋势科技邹飞评《程序员的自我修养》 关于《程序员的自我修养》这本书,最初是在和博文的周筠老师MSN上谈起,当时听周老师提及这本书是一本关于链接和装载等系统软件知识的书籍,当时就很感兴趣,因…

session删除
删除一个session值: session_unset(变量); session_destroy(变量); 删除一个cookie: 注意第二个参数中手册中的说明是: Cookie 必须用和设定时的同样的参数才能删除。如果其值一个空字符串,或者是 FALSE,并且其它的参数…

Android学习路线
Android学习路线 第一阶段:Java面向对象编程 1.Java基本数据类型与表达式,分支循环。 2.String和StringBuffer的使用、正则表达式。 3.面向对象的抽象,封装,继承,多态,类与对象,对象初始化和回…

1048 Find Coins(two pointers解法)
1. 很典型的双指针的应用,将数组按照非降排列,两个指针从一头一尾开始包抄,若等于(等于要放在第一个)则返回结果结束程序,小于则左指针右移,大于则右指针左移。 2. 起初还担心,如果…

TCP/IP 协议理解
TCP/IP 协议(Transmission Control Protocol / internet Protocol),因特网互联协议,又名网络通讯协议。通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数…

Webhint开源了一种代码检查工具
Webhint项目提供了一种用于检查代码的可访问性、性能和安全的开源检查(Linting)工具。在创建Web站点和应用中,有越来越多的细节问题亟待完善。为此,Webhint力图帮助开发人员标记这些细节。\\Webhint以命令行接口(CLI&a…

SHAREPOINT爬网设置
F:\2009年\MOSS档案 http://share:30088/default.aspx 进入管理中心 共享服务管理-SharedServices1-搜索设置-内容源和爬网计划-本地 Office SharePoint Server 网站-下拉- -编辑-爬网计划-完全(增量)爬网-创建计划 - 对该内容源启动完全爬网-勾选上。 一、 爬网设置ÿ…

1093 Count PAT‘s
这题出现在“活用递推”专题下面,所谓递推就是这一步的结果和上一步的结果有直接联系。对于本题来说,从左到右,记到当前位置,一共出现的P的个数,如果当前位置是P,则个数就是上一位的加1,否则等于…

拜托,面试别再问我时间复杂度了!!!
最烦面试官问,“为什么XX算法的时间复杂度是OO”,今后,不再惧怕这类问题。 快速排序分为这么几步: 第一步,先做一次partition; partition使用第一个元素tarr[low]为哨兵,把数组分成了两个半区&a…

C#和JavaScript的简单互交
转自:http://cgxcn.blog.163.com/blog/static/132312422009426112558831/ 1.asp.net呼叫js Response.Write("<script languagejavascript>"); Response.Write("alert(登峰欢迎您 );" ); …

读阮一峰对《javascript语言精粹》的笔记,我有疑问。
《javascript语言精粹》是一本很棒的书籍,其中作者在附录列出了12种他所认为的javascript语言中的糟粕。 我最近开始跟读前端前辈的博客,其中读到了阮一峰的《12种不宜使用的Javascript语法》,有一个疑问: 文如下: 9. …

1008 Elevator
思路如下:用一个整型数组存楼层,0号元素为0(开始停在0层),每读入一个元素,和上一个比较,更大说明是上升,总时长加上楼层差*6,反之说明是下降,总时长加上楼层差*4。最后再管停留时间&…

软件安全性能測试(转载)
近来,在我负责的公司某软件产品的最后測试工作,经常被问到这样一个问题:在做測试过程中,我们的软件产品在安全性方面考虑了多少?应该怎样測评一个软件究竟有多安全? 这个软件因为涉及客户商业上重要的…

org.springframework.data.redis 一次连接获取特定key所有k-v(pipeline)
2019独角兽企业重金招聘Python工程师标准>>> 当我们需要一次性获取在redis中以hash方式存储的所有key-value时,我们可以使用下面的方式来获取。 public void testGetMore() throws IOException {RedisCallback<List<Object>> pipelineCallba…

[网络应用]Flash中鼠标手势及Ctrl+T问题{Firefox}
想说这个问题很久了,也是对Flash的一点点小小的不满。 当你在浏览youku,56,Youtube,土豆,Kou6上的视频时,是不是会发现你的CtrlT命令不凑效了。 当你在打开一个Flash全站时,或者鼠标焦点在一个令…

(C++)一行代码递归实现辗转相除法
定理:两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。 int gcd(int a,int b){return !b?a:gcd(b,a%b); } 这里递归边界是 gcd(a,0)a; 递归式是 gcd(a,b)gcd(b,a%b);

【C#】Web页面传值小结-
1. 使用QueryString变量 QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中。如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法。但是对于传递数组或对象的话,就不能用这个方法了…

分享:用promise封装ajax
用promise封装ajaxvar ajaxOptions {url: url,method: GET,async: true,data: null,dataType: text, } function ajax(protoOptions) {var options {};for(var i in ajaxOptions){options[i] protoOptions[i] || ajaxOptions[i];}return new Promise(function(resolve, reje…

1049 Counting Ones
1. 这一题起初我用递归的方式,还写了一个数整数有多少个1的函数,OneNum[i] OneNum[i-1]countOne(i);毫不意外地出现了段错误,也就是递归调用的次数太多。 2. 看了参考书,得到了思路上的启发: 给定一个数12ÿ…

Oracle:递归查询(树形结构数据)
今天要做一个查询功能:查询某用户所属部门,且包含该部门的所有上级部门信息。偶然找到了一个方法,特意来做个笔记。分享给和我一样的菜鸟,哈哈 查询子节点 1 select * 2 from d_arc_dep 3 start with depid 100000 4 connect b…

FIN_WAIT_2
来自转载:http://blog.sina.com.cn/s/blog_8e5d24890102w9yi.html 上图对排除和定位网络或系统故障时大有帮助,但是怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻地认识,不能只…

网页制作知识:XHTML 和 DOCTYPE 切换
为 Web页指定 DOCTYPE 会影响浏览器呈现页的方式。Internet Explorer、Mozilla Firefox 和 Opera 全都支持一种名为“DOCTYPE 切换”(也叫“DOCTYPE 嗅探”)的功能。 引入 DOCTYPE 切换的目的是使浏览器能够正确地呈现符合标准的 Web 站点以及旧式 Web 站…

1003 我要通过!
1. 总体思路是自己先写写,看看哪些字符串符合,找出规律,然后根据测试用例来矫正。 2. 用到了递推的方法,我使用countA[maxn]数组存放截至当前位置一共出现的A的个数。 3. 正确的字符串满足的条件是:P之前A的个数P和T…

微信电视来了 微信遥控传屏弹幕统统有
据证券时报消息,腾讯携手康佳推微信电视,具有微信传屏、微信弹幕、微信遥控等基于腾讯微信平台的电视功能。想了吧?别急,11月5日,微信互联电视将在康佳全国终端门店全部上线。微信电视2.0版将新增语音搜索、节目单分享…

机器学习-线性回归LinearRegression
概述 今天要说一下机器学习中大多数书籍第一个讲的(有的可能是KNN)模型-线性回归。说起线性回归,首先要介绍一下机器学习中的两个常见的问题:回归任务和分类任务。那什么是回归任务和分类任务呢?简单的来说,…

使用Windows的SHFileOperation外壳函数实现文件操作
在Windows的shellapi文件中定义了一个名为SHFileOperation()的外壳函数,用它可以实现各种文件操作,如文件的拷贝、删除、移动等,该函数使用起来非常简单,它只有一个指向SHFILEOPSTRUCT结构的参数。使用SHFi…

(C++)寻找1-100以内所有素数,复杂度为O(nsqrt(n))与O(nloglogn)的两种方法
注意:1既不是质数也不是合数,2是质数。 1. 复杂度为O(nsqrt(n)) 原理:先写一个判断整数是否为素数的函数,其复杂度为sqrt(n),其原理是对于一个数n,如果它有除了1和自身之外的因子,那么这个因子…

这样就算会了PHP么?-10
关于基本的文件读写内容: <?phpecho "readfile function:<br>";readfile("tm.txt");echo "<br>";echo "file function:<br>";$f_arr file("tm.txt");foreach ($f_arr as $cont) {echo $c…