SpringBoot - @ControllerAdvice 处理异常
在Spring 3.2中,新增了@ControllerAdvice、@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping、@PostMapping, @GetMapping注解中。
接下来我将通过代码展示如何使用这些注解,以及处理异常。
注解的介绍
先定义一个ControllerAdvice。代码如下:
需要注意的是使用@ExceptionHandler注解传入的参数可以一个数组,且使用该注解时,传入的参数不能相同,也就是不能使用两个@ExceptionHandler去处理同一个异常。如果传入参数相同,则初始化ExceptionHandler时会失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | /** * @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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @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类的异常才会进行事务回滚,所以我们一般自定义异常都继承该异常类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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; } } |
编写全局异常处理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /** * @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中抛出自定义异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /** * @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.返回报文为:
1 | { "msg" : "系统发生500异常!The Attribute" , "code" : 500 } |
可见我们的@InitBinder和@ModelAttribute注解生效。且自定义异常被成功拦截。如果全部异常处理都返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody。@RestControllerAdvice在注解上已经添加了@ResponseBody。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?