目录

@ExceptionHandler 局部异常处理

@ControllerAdvice 全局异常处理

@RestControllerAdvice 全局异常处理


@ExceptionHandler 局部异常处理

1、Spring 的 @ExceptionHandler 注解用于统一处理控制层(Controller)往外抛的异常。

@ExceptionHandler 注意事项
1)@ExceptionHandler 注解标注在方法上,此方法会统一处理同一  Controller 下其它 @RequestMapping 注解标注的方法抛出的异常
2)@ExceptionHandler 注解的属性的 value 值是一个 Class 类型的数组,表示处理哪些类型的异常,为空时表示处理所有异常。
3)@ExceptionHandler 标注的方法可以使用一个异常对象作为参数,比如 xx(Exception e) ,这个 e 就是实际抛出的异常
4)同一个  Controller 下可以多个 @ExceptionHandler,但是它们的 value 属性处理的异常不能相同,比如不能多个同时处理 NullPointerException 异常,虽然启动时不会报错,但是当真的抛出 NullPointerException 时,Spring 就会抛出异常,提示不能有模棱两可的配置项。
5)多个 @ExceptionHandler 方法时,比如方法1处理 NullPointerException 异常,方法2处理 RuntimeException 异常,当 @RequestMapping 标注的方法抛出异常时,会采用就近原则,比如抛出空指针异常时,则进入方法1,不会再走方法2。
6)当控制层 @RequestMapping 注解标注的方法自己 try-catch 捕获了异常,没有继续往外抛时,则不会再走 @ExceptionHandler 方法。
7)当业务层中捕获处理了某个 XxxException 异常,则控制层就不会再触发异常捕获,除非业务层继续往外抛。
8)业务层中如果 @Transactional 标注的方法中使用 try{}catch{}捕获处理了异常,则事务不再回滚,如果想让事务回滚,则必须继续往外抛,如:try{xxx}catch(Exception e){ throw new RuntimeException("xxx",e) }

9)当 @RequestMapping 标注的方法抛出异常时,进入 @ExceptionHandler 方法时,原 @RequestMapping 方法的返回值不会再走,而是会使用 @ExceptionHandler 方法的返回值,比如页面跳转,或者将数据返回给页面等等,而且两者的返回值类型可以不一致,比如原来是 Map,现在是 String。

10、@ExceptionHandler 方法的返回值是页面跳转还是直接返回给页面,取决于所在的类使用的是 @Controller 还是 @RestController,前者时 @ExceptionHandler 方法的返回值默认是页面跳转(除非 @ExceptionHandler 方法再加上 @ResponseBody 注解,此时就会直接返回给页面);后者时 @ExceptionHandler 方法返回值默认是直接返回给页面。

2、使用非常简单,下面直接上代码,模拟 XxxServiceImp 业务层抛出异常,然后在  XxxController 中统一处理异常:

/*** 员工控制层。演示 @ExceptionHandler 注解统一处理控制层异常** @author wangMaoXiong* @version 1.0* @date 2020/8/20 19:32*/
@RestController(value = "handlerEmpController")
public class EmpController {private static Logger logger = LoggerFactory.getLogger(EmpController.class);@Resource(name = "handlerEmpServiceImpl")private EmpServiceImpl empServiceImpl;/*** 根据员工id查询员工数据* http:localhost:8080/handler/emp/findEmpById?empId=2000** @param empId* @return*/@GetMapping(value = "handler/emp/findEmpById")public Map<String, Object> findEmpById(@RequestParam Integer empId) {Map<String, Object> resultData = new HashMap<>(4);System.out.println("进入员工控制层:【" + empId + "】");// 如果自己 try-catch 捕获了异常,没有继续往外抛时,则不会再走 @ExceptionHandler 方法捕获异常。Map<String, Object> emp = empServiceImpl.findEmpById(empId);resultData.put("code", 200);resultData.put("data", emp);return resultData;}/*** ExceptionHandler:异常处理注解,只有一个 value 属性,用于捕获特定的异常类型,为空时表示捕获所有异常** @param ex :目标方法实际抛出的异常对象* @return :原 @RequestMapping 方法的返回值不会再走,而是会使用 @ExceptionHandler 方法的返回值,* 比如页面跳转,或者将数据返回给页面等等,而且两者的返回值类型可以不一致,比如原来是 Map,现在是 String。*/@ExceptionHandler(value = {NumberFormatException.class})public Map<String, Object> numberFormatException(Exception ex) {System.out.println("控制层抛出异常=" + ex.getMessage());// 1、使用日志框架记录日志信息logger.error(ex.getMessage(), ex);// 2、实际生产中,后台通常会使用统一的数据对象返回给页面,比如状态码,错误消息,数据对象等,这里使用 Map 代替Map<String, Object> resultData = new HashMap<>(4);resultData.put("code", 500);resultData.put("msg", ex.getMessage());resultData.put("data", null);return resultData;}/*** ExceptionHandler:异常处理注解,只有一个 value 属性,用于捕获特定的异常类型,为空时表示捕获所有异常** @param ex :目标方法实际抛出的异常对象* @return :原 @RequestMapping 方法的返回值不会再走,而是会使用 @ExceptionHandler 方法的返回值,* 比如页面跳转,或者将数据返回给页面等等,而且两者的返回值类型可以不一致,比如原来是 Map,现在是 String。*/@ExceptionHandler()public Map<String, Object> exceptionHandler(Exception ex) {System.out.println("控制层抛出异常:" + ex.getMessage());// 1、使用日志框架记录日志信息logger.error(ex.getMessage(), ex);// 2、实际生产中,后台通常会使用统一的数据对象返回给页面,比如状态码,错误消息,数据对象等,这里使用 Map 代替Map<String, Object> resultData = new HashMap<>(4);resultData.put("code", 500);resultData.put("msg", "服务器忙!");resultData.put("data", null);return resultData;}}

https://gitee.com/wangmx1993/h2-smil/blob/master/src/main/java/com/wmx/exception/handler/

@ControllerAdvice 全局异常处理

1、控制层(@RestController、@Controller)里面直接使用 @ExceptionHandler 的好处是直观、优先级高,缺点是每个控制层都需要写 @ExceptionHandler 方法。

2、@ControllerAdvice + @ExceptionHandler  注解组合是全局异常处理,@ControllerAdvice 可以标注在类、接口、注解、枚举上,表示为整个应用下的 @controller 控制器给出建议/忠告,@ExceptionHandler 标注在 @ControllerAdvice 类下的方法上。

3、默认情况下 @ControllerAdvice 中的 @ExceptionHandler  方法全局应用于所有控制器(@RestController、@Controller)。

4、如下所示:新建一个类,类上加上 @ControllerAdvice 注解,然后加上 @ExceptionHandler 异常处理方法,则可以为整个应用的控制器全局处理异常,其它控制器可以无需再处理异常。

/*** 全局异常处理。* 1、@ControllerAdvice 表示为应用下所有的控制器给出建议,类中提供 @ExceptionHandler 异常处理方法,* 所以组合起来就是为整个应用下的所有控制器给出全局异常处理建议。* 2、如同 @RestController 注解组合了 @Controller 与 @ResponseBody 注解一样,@RestControllerAdvice* 也组合了 @ControllerAdvice 与 @ResponseBody 注解* 3、所以 @ControllerAdvice 中的  @ExceptionHandler 方法返回默认是做页面跳转,加上 @ResponseBody 才会直接返回给页面* 而 @RestControllerAdvice 中的 @ExceptionHandler 方法则默认是返回给页面。** @author wangMaoXiong* @version 1.0* @date 2020/8/22 17:27*/
@ControllerAdvice
public class GlobalExceptionHandler {private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);/*** ExceptionHandler:异常处理注解,只有一个 value 属性,用于捕获特定的异常类型,为空时表示捕获所有异常* ExceptionHandler 异常处理方法的返回值是做页面跳转还是直接返回给页面,取决于所在的类使用的是 ControllerAdvice 注解还是 RestControllerAdvice 注解,* ControllerAdvice 时 ExceptionHandler 方法的返回值默认是页面跳转(除非 ExceptionHandler 方法再加上 @ResponseBody 注解,此时就会直接返回给页面);* RestControllerAdvice 时 @ExceptionHandler 方法返回值默认是直接返回给页面。** @param ex :目标方法实际抛出的异常对象* @return :原 @RequestMapping 方法的返回值不会再走,而是会使用 @ExceptionHandler 方法的返回值,* 比如页面跳转,或者将数据返回给页面等等,而且两者的返回值类型可以不一致,比如原来是 Map,现在是 String。*/@ExceptionHandler(value = {NumberFormatException.class})@ResponseBodypublic Map<String, Object> numberFormatException(Exception ex) {System.out.println("控制层异常=" + ex.getMessage());// 1、使用日志框架记录日志信息logger.error(ex.getMessage(), ex);// 2、实际生产中,后台通常会使用统一的数据对象返回给页面,比如状态码,错误消息,数据对象等,这里使用 Map 代替Map<String, Object> resultData = new HashMap<>(4);resultData.put("code", 500);resultData.put("data", null);resultData.put("msg", ex.getMessage());return resultData;}/*** ExceptionHandler:异常处理注解,只有一个 value 属性,用于捕获特定的异常类型,为空时表示捕获所有异常* ExceptionHandler 异常处理方法的返回值是做页面跳转还是直接返回给页面,取决于所在的类使用的是 ControllerAdvice 注解还是 RestControllerAdvice 注解,* ControllerAdvice 时 ExceptionHandler 方法的返回值默认是页面跳转(除非 ExceptionHandler 方法再加上 @ResponseBody 注解,此时就会直接返回给页面);* RestControllerAdvice 时 @ExceptionHandler 方法返回值默认是直接返回给页面。** @param ex :目标方法实际抛出的异常对象* @return :原 @RequestMapping 方法的返回值不会再走,而是会使用 @ExceptionHandler 方法的返回值,* 比如页面跳转,或者将数据返回给页面等等,而且两者的返回值类型可以不一致,比如原来是 Map,现在是 String。*/@ExceptionHandler()@ResponseBodypublic Map<String, Object> exceptionHandler(Exception ex) {System.out.println("控制层异常:" + ex.getMessage());// 1、使用日志框架记录日志信息logger.error(ex.getMessage(), ex);// 2、实际生产中,后台通常会使用统一的数据对象返回给页面,比如状态码,错误消息,数据对象等,这里使用 Map 代替Map<String, Object> resultData = new HashMap<>(4);resultData.put("msg", "服务器忙!");resultData.put("code", 500);resultData.put("data", null);return resultData;}
}

https://gitee.com/wangmx1993/h2-smil/blob/master/src/main/java/com/wmx/exception/advice/

@RestControllerAdvice 全局异常处理

1、@ControllerAdvice 表示为应用下所有的控制器给出建议,类中提供 @ExceptionHandler 异常处理方法, 所以组合起来就是为整个应用下的所有控制器(@RestController、@Controller)给出全局异常处理建议。

2、如同 @RestController 注解组合了 @Controller 与 @ResponseBody 注解一样,@RestControllerAdvice 则组合了 @ControllerAdvice 与 @ResponseBody 注解。

3、所以 @ControllerAdvice 中的  @ExceptionHandler 方法返回值默认是做页面跳转,加上 @ResponseBody 才会直接返回给页面,而 @RestControllerAdvice 中的 @ExceptionHandler 方法则默认是返回给页面。

4、编码与上面的 @ControllerAdvice  + @ExceptionHandler 完全一样,区别仅仅在于 @ExceptionHandler 异常处理方法的返回值是做页面跳转还是返回给页面。

5、异常处理优先级:

1)如果控制器中的方法自己 try-catch 处理了异常,则无论是本类中的 @ExceptionHandler 还是全局的 @ExceptionHandler 都不会再执行;
2)就近原则:控制器中的 @ExceptionHandler 异常处理方法优先级高于全局的 @ControllerAdvice、@RestControllerAdvice

6、@RestControllerAdvice 默认全局应用于所有控制器(@RestController、@Controller),与自己放置的位置无关,如果只想对部分包路径下的控制器进行应用,则可以使用它的属性进行指定。

7、控制器方法自己 try-catch 处理了异常,则全局 @ExceptionHandler 异常处理方法不会再执行.

8、控制器方法自己 try-catch 处理了异常,但是继续往外抛异常,则全局 @ExceptionHandler 异常处理方法会捕获执行。

String[] basePackages() 应用于指定包及其子包,如 @ControllerAdvice(basePackages="org.my.pkg")
String[] value() basePackages 属性的别名,提供更加简洁的写法
Class<? extends Annotation>[] annotations() 凡是标记了其中任何一个注解的控制器都进行统一管理
/*** 系统全局异常处理** @author wangMaoXiong* @version 1.0* @date 2021/12/28 15:03*/
@RestControllerAdvice
public class CommonExceptionHandler {private static final Logger log = LoggerFactory.getLogger(CommonExceptionHandler.class);/*** 1、@Validated 对 RequestBody DTO 参数校验未通过时会抛出 MethodArgumentNotValidException 异常。* @param ex* @return*/@ExceptionHandler({MethodArgumentNotValidException.class})@ResponseStatus(HttpStatus.OK)public ResultData<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {log.error(ex.getMessage(), ex);BindingResult bindingResult = ex.getBindingResult();StringBuilder sb = new StringBuilder();//遍历校验未通过的字段与错误信息.for (FieldError fieldError : bindingResult.getFieldErrors()) {sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");}if (sb.length() > 0) {sb.delete(sb.lastIndexOf(","), sb.length());} else {sb.append(ex.getMessage());}//封装后的效果如:password:长度需要在6和18之间, userName:不能为nullString msg = sb.toString();return new ResultData<>(ResultCode.PARAM_IS_FAIL.getCode(), msg, null);}/*** 1、@Validated 对 RequestParam、PathVariable 传参校验未通过时,会抛出 ConstraintViolationException 异常。* @param ex* @return*/@ExceptionHandler({ConstraintViolationException.class})@ResponseStatus(HttpStatus.OK)public ResultData<Object> handleConstraintViolationException(ConstraintViolationException ex) {log.error(ex.getMessage(), ex);return new ResultData<>(ResultCode.PARAM_IS_FAIL.getCode(), ex.getMessage(), null);}/*** 对没有具体捕获的异常统一捕获处理* @param ex* @return*/@ExceptionHandler()@ResponseStatus(HttpStatus.OK)public ResultData<Object> handleException(Exception ex) {log.error(ex.getMessage(), ex);return new ResultData<>(ResultCode.FAIL, null);}
}

src/main/java/com/wmx/wmxredis/exceotion/CommonExceptionHandler.java · 汪少棠/wmx-redis - Gitee.com

Spring MVC @ExceptionHandler、@ControllerAdvice、@RestControllerAdvice 统一异常处理相关推荐

  1. Spring 3.2 @ControllerAdvice批注的异常处理

    不久前,我写了一个博客,概述了如何将Spring示例代码升级到3.2版,并演示了其中的一些小"陷阱". 从那以后,我一直在仔细阅读Spring 3.2的新功能列表,尽管它不包含任何 ...

  2. Spring MVC中@ControllerAdvice注解实现全局异常拦截

    Spring MVC中@ControllerAdvice注解实现全局异常拦截 参考文章: (1)Spring MVC中@ControllerAdvice注解实现全局异常拦截 (2)https://ww ...

  3. Spring MVC重定向和转发及异常处理

    SpringMVC核心技术---转发和重定向 当处理器对请求处理完毕后,向其他资源进行跳转时,有两种跳转方式:请求转发与重定向.而根据要跳转的资源类型,又可分为两类:跳转到页面与跳转到其他处理器. 对 ...

  4. Spring Mvc 数据回显、异常处理、文件上传、json交互、ResTful、拦截器的使用(高级三)

    1,数据回显 SpringMvc包含三种数据回显机制 第一种:对于简单数据类型,如:Integer.String.Float等使用Model将传入的参数再放到request域实现显示. (回顾jsp四 ...

  5. Spring MVC学习(8)—HandlerInterceptor处理器拦截器机制全解

    基于最新Spring 5.x,详细介绍了Spring MVC的HandlerInterceptor处理器拦截器机制,以及它的一系列拦截方法. 本次我们来学习Sring MVC的HandlerInter ...

  6. Spring MVC之异常处理

    2019独角兽企业重金招聘Python工程师标准>>> Spring MVC之异常处理 Spring MVC提供了几种异常处理的方法: 对于每个异常类的处理 对于每个@Control ...

  7. Spring 中的统一异常处理

    在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的. 因此,肯定需要在Controller捕获所有异常,并且做适当处理,返回给前端一个友好的错误码. 不过 ...

  8. Spring MVC异常统一处理(异常信息的国际化,日志记录)

    JAVA EE项目中,不管是对底层的数据操作,还是业务层的处理过程,还是控制层的处理,都不可避免的会遇到各种可预知的(业务异常主动抛出).不可预知的异常需要处理.一般dao层.service层的异常都 ...

  9. Spring Boot统一异常处理的拦截指南

    通常我们在Spring Boot中设置的统一异常处理只能处理Controller抛出的异常.有些请求还没到Controller就出异常了,而这些异常不能被统一异常捕获,例如Servlet容器的某些异常 ...

  10. Java中级篇——Spring MVC 是什么(附加响应状态代码列举)

    1.关于springMVC 基于Spring框架,主要解决后端服务器接受客户端服务器接受客户提交的请求,并给予响应相关的问题.的框架 目录 1.关于springMVC 基于Spring框架,主要解决后 ...

最新文章

  1. Linux C编程--打开和关闭流
  2. linux git hudson,如何使用SSH密钥配置Hudson和git插件
  3. Mysql字符集之utf8和utf8mb4的使用问题
  4. 求一个整数的阶乘结果中后缀0的个数
  5. 三星s7不能运行java_在调试模式下启动时Android应用程序崩溃
  6. [转]flash在C#中的应用
  7. c语言 和 运算顺序,二 如何学习C语言的运算符和运算顺序
  8. 1078 Hashing (25 分) 解决冲突采用正向增加的二次探查法
  9. UI 自动化框架对比2
  10. ubuntu编译libjpeg-turbo
  11. KALI利用MS17-010漏洞入侵
  12. vue+vant开发app打包apk
  13. 有序回归: Ordinal Regression的理解
  14. 基于whisper模型的在线添加视频字幕网站(持续更新)
  15. 只需5步,新手小白如何创建实用的在线员工手册?
  16. 2021年完美解决Gradle下载慢的问题(Android Studio)
  17. 密码学-密钥管理与分发
  18. call和calling的用法_call和called的区别和用法
  19. Revit建模助手独门绝技,一阳指给构件“ 元素上色 ”
  20. 一文让你吃透!图解 pandas 透视表、交叉表!

热门文章

  1. java学习:jdbc连接示例
  2. 基于内容的图像检索技术:从特征到检索
  3. python实现原始字典数据中键值互换得到新的字典数据
  4. python数值计算库Numpy学习之—np.linalg.norm(求范数)
  5. jQuery(3)——如何绑定事件
  6. 重定向与请求转发的区别
  7. return 0在c语言中是什么意思_单次T+0与蓝筹股试点T+0制度是什么意思,两者有何区别?...
  8. 证明独立集合问题是NP-complete
  9. C++ 多线程 同时读取同一个vector 线程安全 吗
  10. ubuntu docker-compose: command not found