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)(转)的更多相关文章

  1. SpringBoot详解

    1.Hello,World! 1.1.SpringBoot简介 回顾什么是Spring Spring是一个开源框架,2003 年兴起的一个轻量级的Java 开发框架,作者:Rod Johnson . ...

  2. SpringBoot详解(一)——

    https://www.cnblogs.com/lifullmoon/p/14957771.html https://www.cnblogs.com/lifullmoon/p/14957751.htm ...

  3. SPRINGBOOT注解最全详解(

    #     SPRINGBOOT注解最全详解(整合超详细版本)          使用注解的优势:               1.采用纯java代码,不在需要配置繁杂的xml文件           ...

  4. Springboot 整合 Dubbo/ZooKeeper 详解 SOA 案例

    摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!   “看看星空,会觉得自己很渺小,可能我们在宇宙中从来就是一个偶然.所以,无论什么事情,仔细想一 ...

  5. Springboot启动源码详解

    我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static voi ...

  6. springboot配置详解

    springboot配置详解 Author:SimpleWu properteis文件属性参考大全 springboot默认加载配置 SpringBoot使用两种全局的配置文件,全局配置文件可以对一些 ...

  7. spring-boot(五) RabbitMQ详解 定时任务

    学习文章来自:springboot(八):RabbitMQ详解 springboot(九):定时任务 RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分 ...

  8. Springboot@Configuration和@Bean详解

    Springboot@Configuration和@Bean详解 一.@Configuration @Target({ElementType.TYPE}) @Retention(RetentionPo ...

  9. [转]application.properties详解 --springBoot配置文件

    本文转载:http://blog.csdn.net/lpfsuperman/article/details/78287265###; # spring boot application.propert ...

随机推荐

  1. Java—System类入门学习

    第三阶段 JAVA常见对象的学习 System类 System类包含一些有用的字段和方法,他不能被实例化 //用于垃圾回收 public static void gc() //终止正在运行的java虚 ...

  2. spring mvc 的配置 及interceptor filter listener servlet 配置

    创建 三个类 分别实现 Filter  ServletContextListener  HttpServlet 在springboot 启动类中@bean加入 2 ,实现 ServletContext ...

  3. quartz报错 org.quartz.impl.StdSchedulerFactory.

    quartz任务执行报错 Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFa ...

  4. 13.lsof恢复删除的文件

    [root@temp ~]# lsof -p 5643COMMAND  PID   USER   FD   TYPE DEVICE  SIZE/OFF    NODE NAMEoracle  5643 ...

  5. python爬取信息并保存至csv

    import csv import requests from bs4 import BeautifulSoup res=requests.get('http://books.toscrape.com ...

  6. 在生产环境中使用Compose 【翻译】

    在生产环境中使用Compose 在开发环境中使用Compose定义你的应用,可以使用此定义在不同的环境,(如 CI.暂存和生产)中运行应用程序. 部署应用程序的最简单方法是在单个服务器上运行该应用程序 ...

  7. python 比对PDF文件

    基本思路: 1.读取pdf内容,存放到不同的 list 2.比较 list 的相似度 ------------------------ 实现------------------------- 1.PD ...

  8. vue中的键盘事件

    @keydown(键盘按下时触发),@keypress(键盘按住时触发),@keyup(键盘弹起) 获取按键的键码 e.keyCode @keyup.13     按回车键 @keyup.enter ...

  9. net core体系-Xamarin-2概要(lignshi)

    通过本套课程的学习,各位学员能够对Xamarin有一个比较清楚的认识,掌握Xamarin常用功能的使用方法,能够比较熟练的使用Xamarin进行App(移动应用)的开发,能够比较轻松.快速地投入项目当 ...

  10. loj 2292「THUSC 2016」成绩单

    loj 看着就很区间dp,所以考虑求\(f_{i,j}\)表示区间\([i,j]\)的答案.注意到贡献答案的方式是每次选一个连续段,拿走后剩下的段拼起来继续段,所以转移就考虑从最后一次选的方法转移过来 ...