springboot 详解RestControllerAdvice(ControllerAdvice)(转)
springboot 详解RestControllerAdvice(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 {};
}
作为特化@Component,允许通过类路径扫描自动检测实现类。
它通常用于定义@ExceptionHandler, @InitBinder 和 @ModelAttribute 适用于所有@RequestMapping方法的方法。
annotations(),basePackageClasses(), basePackages()或它的别名value() 可以被指定,以限定控制器,以协助的特定子集。当应用多个选择器时,应用OR逻辑 - 意味着所选的控制器应匹配至少一个选择器。
默认行为(即,如果没有任何选择器使用),带@ControllerAdvice注释的类将协助所有已知的控制器。
背景
当我们定义了一个自定义返回参数格式时,希望得到统一的返回,如果在运行时发现了异常,也希望将异常统一返回。如
期望返回格式:
{
"msg": "success",
"code": 500,
"success": false,
"message": "id不能为空!"
}
抛出异常格式:
{
"timestamp": "2019-04-01T07:17:38.619+0000",
"status": 500,
"error": "Internal Server Error",
"message": "id不能为空!",
"path": "/api/myInfo"
}
如何让我们的异常得到期望的返回格式,这里就需要用到了@ControllerAdvice或者RestControllerAdvice(如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody。)。下面看一个demo。
准备工作
1.创建一个UnionExceptionHandler类,定义全局异常捕捉处理。
package com.honghh.bootfirst.exception; import com.honghh.bootfirst.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RestControllerAdvice; /**
* ClassName: UnionExceptionHandler
* Description:
*
* @author honghh
* @date 2019/04/01 10:03
*/
@Slf4j
@RestControllerAdvice
public class UnionExceptionHandler { /**
* 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
*
* @param binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
log.info("binder.getFieldDefaultPrefix {}",binder.getFieldDefaultPrefix());
log.info("binder.getFieldMarkerPrefix {}",binder.getFieldMarkerPrefix());
}
/**
* 把值绑定到Model中,使全局@RequestMapping可以获取到该值
* @param model
*/
@ModelAttribute
public void addAttributes(Model model) {
model.addAttribute("author", "harry");
}
/**
* Description : 全局异常捕捉处理
* Group :
*
* @author honghh
* @date 2019/4/1 0001 10:34
* @param ex
* @return
*/
@ExceptionHandler(RRException.class)
public R apiExceptionHandler(RRException ex) {
log.error("ApiException 异常抛出:{}", ex);
return R.fail(ex);
}
/**
* Description : 针对某个异常捕捉处理
* Group :
*
* @author honghh
* @date 2019/4/1 0001 10:34
* @param ex
* @return
*/
@ExceptionHandler(SSException.class)
public R apiExceptionHandler(SSException ex) {
log.error("ApiException 异常抛出:{}", ex);
return R.fail(ex);
}
}
启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 @RequestMapping 注解的方法上。
@ModelAttribute:在Model上设置的值,对于所有被 @RequestMapping 注解的方法中,都可以通过 ModelMap 获取
2.创建一个RRException 自定义异常。
package com.honghh.bootfirst.exception;
/**
* 自定义异常
*
* @author harry
* @date 2018-07-20 16:30
*/
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L; private String msg;
private int code = 500; public RRException(String msg) {
super(msg);
this.msg = msg;
} public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
} public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
} public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} }
3.写一个RequestMapping方法,抛出异常进行测试。[spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,下面自定义异常处理,提供友好展示。
@GetMapping("myInfo")
public R myInfo(@RequestParam Integer id) {
if (id == null) {
throw new RRException("id不能为空!");
}
MyInfo myInfo = myInfoService.getById(id);
return R.ok().put("myInfo", myInfo);
}
//启动应用,访问:http://127.0.0.1:8080/api/myInfo?id= ,正常显示以下json内容,证明自定义异常已经成功被拦截。
{
"msg": "success",
"code": 500,
"success": false,
"message": "id不能为空!"
}
代码获取
https://gitee.com/honghh/boot-demo.git
参考文献
https://docs.spring.io/spring-framework/docs/5.0.0.M1/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
————————————————
版权声明:本文为CSDN博主「AH_HH」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35098526/article/details/88949425
springboot 详解RestControllerAdvice(ControllerAdvice)(转)的更多相关文章
- SpringBoot详解
1.Hello,World! 1.1.SpringBoot简介 回顾什么是Spring Spring是一个开源框架,2003 年兴起的一个轻量级的Java 开发框架,作者:Rod Johnson . ...
- SpringBoot详解(一)——
https://www.cnblogs.com/lifullmoon/p/14957771.html https://www.cnblogs.com/lifullmoon/p/14957751.htm ...
- SPRINGBOOT注解最全详解(
# SPRINGBOOT注解最全详解(整合超详细版本) 使用注解的优势: 1.采用纯java代码,不在需要配置繁杂的xml文件 ...
- Springboot 整合 Dubbo/ZooKeeper 详解 SOA 案例
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “看看星空,会觉得自己很渺小,可能我们在宇宙中从来就是一个偶然.所以,无论什么事情,仔细想一 ...
- Springboot启动源码详解
我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static voi ...
- springboot配置详解
springboot配置详解 Author:SimpleWu properteis文件属性参考大全 springboot默认加载配置 SpringBoot使用两种全局的配置文件,全局配置文件可以对一些 ...
- spring-boot(五) RabbitMQ详解 定时任务
学习文章来自:springboot(八):RabbitMQ详解 springboot(九):定时任务 RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分 ...
- Springboot@Configuration和@Bean详解
Springboot@Configuration和@Bean详解 一.@Configuration @Target({ElementType.TYPE}) @Retention(RetentionPo ...
- [转]application.properties详解 --springBoot配置文件
本文转载:http://blog.csdn.net/lpfsuperman/article/details/78287265###; # spring boot application.propert ...
随机推荐
- Python非递归实现二叉树的后续遍历
leetcode 145. Binary Tree Postorder Traversal 思路一: 使用一个栈stack保存经过的根结点,另一个栈flag保存每个结点的右子树是否遍历: 如果根结点存 ...
- (一)使用 mybatis 的缘由
目录 传统代码操作数据库的存在的问题 mybatis 的解决之道 传统代码操作数据库的存在的问题 数据库连接,在使用数据库时,创建数据库连接,在不用的时候,就会立即释放掉连接:这样当下次使用的又会创建 ...
- 剑指offer46:圆圈中最后剩下的数字(链表,递归)
1 题目描述 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随 ...
- 汉诺塔递推HDU2064
题意: 移动木头盘不能a到c,必须a到b到c. 问你移动次数. 假设将n层塔从A经B挪到C需要f[n]步.那么具体的移动过程可以这样看:将上面n-1层从A经B挪到C需要f[n-1]步,再将第n层从A挪 ...
- 【Python基础】12_Python中的容器类型公共方法
1.Python中的内置函数 注:比较两个值,使用 <. >. == 2.切片 注:字典是一个无序集合,不能切片 3.运算符 字典中的in .not in 对字段操作时,只能判断字典的k ...
- 嵌入式linux第一阶段笔记
1.虚拟网络编辑器(vm):三种模式:(VMnet0)桥接模式(vm和windows公用同个网络(同个物理端口)),(VMnet1)仅主机模式,(VMnet8)NAT模式(vm连接一个虚拟的路由(WA ...
- Memcache与Redis有什么区别?
Redis 和 Memcache 都是基于内存的数据存储系统.Memcached是高性能分布式内存缓存服务,其本质上就是一个内存key-value数据库.Redis是一个开源的key-value存储系 ...
- java方法可变参数研究
1 问题引出 (1)缘由 最近在研究如何在项目中引入Redis缓存,于是遇到可变参数这个疑惑点,之前没有好好研究过,为了避免项目后期出现问题. (2)项目相关技术 SpringBoot Redis K ...
- NOIP2009-2018简要题解
口胡警告 NOIP2009 潜伏者 模拟 Hankson 的趣味题 对四个数\(a_0,a_1,b_0,b_1\)分解质因数,结果序列分别记为\(\{p1^{b1}\},\{p2^{b2}\},\{p ...
- Innosetup设置控制面版中的名称显示和图标
//设置控制面板中程序图标UninstallDisplayIcon={app}\logo.ico //设置控制面板中程序的名称Uninstallable=yesUninstallDisplayName ...