SpringBoot 之 @ControllerAdvice 拦截异常并统一处理
在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。参考:@ControllerAdvice 文档
一、介绍
创建 MyControllerAdvice,并添加 @ControllerAdvice注解。
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 | package com.sam.demo.controller; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; /** * controller 增强器 * @author sam * @since 2017/7/17 */ @ControllerAdvice public class MyControllerAdvice { /** * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 * @param binder */ @InitBinder public void initBinder(WebDataBinder binder) {} /** * 把值绑定到Model中,使全局@RequestMapping可以获取到该值 * @param model */ @ModelAttribute public void addAttributes(Model model) { model.addAttribute( "author" , "Magical Sam" ); } /** * 全局异常捕捉处理 * @param ex * @return */ @ResponseBody @ExceptionHandler (value = Exception. class ) public Map errorHandler(Exception ex) { Map map = new HashMap(); map.put( "code" , 100 ); map.put( "msg" , ex.getMessage()); return map; } } |
启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping 注解的方法上。
@ModelAttribute:在Model上设置的值,对于所有被 @RequestMapping 注解的方法中,都可以通过 ModelMap 获取,如下:
1 2 3 4 5 6 7 8 9 10 11 | @RequestMapping ( "/home" ) public String home(ModelMap modelMap) { System.out.println(modelMap.get( "author" )); } //或者 通过@ModelAttribute获取 @RequestMapping ( "/home" ) public String home( @ModelAttribute ( "author" ) String author) { System.out.println(author); } |
@ExceptionHandler 拦截了异常,我们可以通过该注解实现自定义异常处理。其中,@ExceptionHandler 配置的 value 指定需要拦截的异常类型,上面拦截了 Exception.class 这种异常。
二、自定义异常处理(全局异常处理)
spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,下面自定义异常处理,提供友好展示。
1、编写自定义异常类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package com.sam.demo.custom; /** * @author sam * @since 2017/7/17 */ public class MyException extends RuntimeException { public MyException(String code, String msg) { this .code = code; this .msg = msg; } private String code; private String msg; // getter & setter } |
注:spring 对于 RuntimeException 异常才会进行事务回滚。
2、编写全局异常处理类
创建 MyControllerAdvice.java,如下:
package com.sam.demo.controller; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; /** * controller 增强器 * * @author sam * @since 2017/7/17 */ @ControllerAdvice public class MyControllerAdvice { /** * 全局异常捕捉处理 * @param ex * @return */ @ResponseBody @ExceptionHandler(value = Exception.class) public Map errorHandler(Exception ex) { Map map = new HashMap(); map.put("code", 100); map.put("msg", ex.getMessage()); return map; } /** * 拦截捕捉自定义异常 MyException.class * @param ex * @return */ @ResponseBody @ExceptionHandler(value = MyException.class) public Map myErrorHandler(MyException ex) { Map map = new HashMap(); map.put("code", ex.getCode()); map.put("msg", ex.getMsg()); return map; } }
3、controller中抛出异常进行测试。
@RequestMapping("/home") public String home() throws Exception { // throw new Exception("Sam 错误"); throw new MyException("101", "Sam 错误"); }
启动应用,访问:http://localhost:8080/home ,正常显示以下json内容,证明自定义异常已经成功被拦截。
1 | { "msg" : "Sam 错误" , "code" : "101" } |
* 如果不需要返回json数据,而要渲染某个页面模板返回给浏览器,那么MyControllerAdvice中可以这么实现:
1 2 3 4 5 6 7 8 | @ExceptionHandler (value = MyException. class ) public ModelAndView myErrorHandler(MyException ex) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "error" ); modelAndView.addObject( "code" , ex.getCode()); modelAndView.addObject( "msg" , ex.getMsg()); return modelAndView; } |
在 templates 目录下,添加 error.ftl(这里使用freemarker) 进行渲染:
1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>错误页面</title> </head> <body> <h1>${code}</h1> <h1>${msg}</h1> </body> </html> |
重启应用,http://localhost:8080/home 显示自定的错误页面内容。
补充:如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody。
分类:
SpringBoot
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架