在Spring 3.2中,新增了@ControllerAdvice、@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping、@PostMapping, @GetMapping注解中。
接下来我将通过代码展示如何使用这些注解,以及处理异常。

注解的介绍

先定义一个ControllerAdvice。代码如下:

需要注意的是使用@ExceptionHandler注解传入的参数可以一个数组,且使用该注解时,传入的参数不能相同,也就是不能使用两个@ExceptionHandler去处理同一个异常。如果传入参数相同,则初始化ExceptionHandler时会失败。

/**
* @author Lensen
* @desc
* @since 2018/10/5 11:01
*/
@ControllerAdvice
public class MyExceptionHandler { /**
* 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
* @param binder
*/
@InitBinder
public void initWebBinder(WebDataBinder binder){
//对日期的统一处理
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
//添加对数据的校验
//binder.setValidator();
} /**
* 把值绑定到Model中,使全局@RequestMapping可以获取到该值
* @param model
*/
@ModelAttribute
public 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;
// }
}

对于@ControllerAdvice注解,我们来看看源码的定义:

我们可以传递basePackage,声明的类(是一个数组)指定的Annotation参数,具体参考:spring framework doc

@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 {};
}

异常的处理

编写自定义异常类

Spring 对于 RuntimeException类的异常才会进行事务回滚,所以我们一般自定义异常都继承该异常类。

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;
}
}

编写全局异常处理类

/**
* @author Lensen
* @desc
* @since 2018/10/5 11:01
*/
@ControllerAdvice("com.developlee.errorhandle")
public class MyExceptionHandler { /**
* 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
* @param binder
*/
@InitBinder
public void initWebBinder(WebDataBinder binder){ } /**
* 把值绑定到Model中,使全局@RequestMapping可以获取到该值
* @param model
*/
@ModelAttribute
public 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。 

参考

https://yq.aliyun.com/articles/647428

SpringBoot - @ControllerAdvice 处理异常的更多相关文章

  1. Springboot项目中异常拦截设计与处理

    背景: 项目运行过程中会出现各种各样的问题,常见的有以下几种情况: 业务流程分析疏漏,对业务流程的反向操作.边界分析设计不充分 调用外部服务.调用外部系统出现的超时.错误.返回值与预期不符 外部资源连 ...

  2. @ControllerAdvice 拦截异常并统一处理(转载)

    在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler.@InitBinder.@ModelAttribute,并应用到所有@Requ ...

  3. (入门SpringBoot)SpringBoot配置全局异常(五)

    Spring的全局异常,用于捕获程序员没有捕获的异常.具体请看下面代码: 1.ControllerAdvice拦截异常,统一处理.通过Spring的AOP来管理. @ControllerAdvicep ...

  4. @ControllerAdvice全局异常拦截

    @ControllerAdvice 拦截异常并统一处理 在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler.@InitBinder ...

  5. (转)springboot全局处理异常(@ControllerAdvice + @ExceptionHandler)

    1.@ControllerAdvice 1.场景一 在构建RestFul的今天,我们一般会限定好返回数据的格式比如: { "code": 0, "data": ...

  6. 十四、springboot全局处理异常(@ControllerAdvice + @ExceptionHandler)

    1.@ControllerAdvice 1.场景一 在构建RestFul的今天,我们一般会限定好返回数据的格式比如: { "code": 0, "data": ...

  7. [spring-boot] ControllerAdvice异常类

    package com.example.demo.exception; import org.springframework.web.bind.annotation.ControllerAdvice; ...

  8. SpringBoot 之 @ControllerAdvice 拦截异常并统一处理

    在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler.@InitBinder.@ModelAttribute,并应用到所有@Requ ...

  9. (办公)springboot配置全局异常

    项目用到了springboot,本来很高兴,但是项目里什么东西都没有,验证,全局异常这些都需要自己区配置.最近springboot用的还是蛮多的,我还是做事情,把经验发表一下.全局统一的异常,首先异常 ...

随机推荐

  1. jquery 弹出框效果

    html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...

  2. ubuntu oracle数据库18c安装

    一.官网下载linux两个zip包 二.byqKx8a2tWcgBHb

  3. python 字符串中替换字符

    今天本来打算写个程序,替换字符串中固定的一个字符:将<全部替换成回车'\n' 于是,我写成这样 s='sdjj<ddd<denj,>' for x in s: if x=='& ...

  4. Halo(二)

    @Conditional 满足条件给容器注册Bean(在配置类 @Configuration 的类和方法上配置) 需要实现Condition接口, 实现matches方法 public class L ...

  5. boost库:字符串处理

    使用boost库的字符串处理之前,需要进行区域设置.类:std::locale,每个C++程序自动拥有一个此类的实例,不能直接访问全局区域设置. 全局区域设置可以使用类std::locale中的静态函 ...

  6. boost库:智能指针

    1. C98里的智能指针 std::auto_ptr ,本质上是一个普通的指针,通过地址来访问你一个动态分配的对象,初始化时需要传递一个由new操作符返回的对象地址. std::auto_ptr的析构 ...

  7. java中循环删除list中元素的方法

    重点哈 印象中循环删除list中的元素使用for循环的方式是有问题的,但是可以使用增强的for循环,然后今天在使用时发现报错了,然后去科普了一下,再然后发现这是一个误区.下面就来讲一讲..伸手党可直接 ...

  8. Tomcat负载均衡图片显示不正常解决方法

    在部署一个Tomcat玩玩的时候,发现在做nginx负载均衡时,网站显示不正常,图片会变得很大.测试了半天都没成功,最后查找资料,才发现Tomcat负载均衡时Session处理有问题,Session是 ...

  9. AcWing 229. 新NIM游戏 (线性基+博弈论)打卡

    题目:https://www.acwing.com/problem/content/description/231/ 题意:给出n堆石子,然后第一回合,A玩家可以随便拿多少堆石子,第二回合B玩家随便拿 ...

  10. Android代码学习--点击事件的几种写法

    由来:常规的写法参见<写一个apk>,每次点击按钮,按钮先查找文本框等元素,然后再操作,其实查找操作是很费时的操作,因此将该定义放到Activity的onCreate中:Oncreate只 ...