当前位置: 首页 > news >正文

SpringMVC-异常处理

目录

HandlerExceptionResolver接口

使用注解实现异常分类管理(@ControllerAdvice 和 @ExceptionHandler)

使用 @ControllerAdvice 对不同的 Controller 分别捕获异常并处理


HandlerExceptionResolver接口

  • 在SpringMVC中,提供了一个全局异常处理器,用于对系统中出现的异常进行统一处理
  • 在一般的系统中,DAO层、Service层及Controller层出现异常都以“throws Exception”的形式向上层抛出,最后都会由SpringMVC的前端控制器(DispatcherServlet)统一交给全局异常处理器进行异常处理
  • 在SpringMVC中提供的HandlerExceptionResolver接口可以实现全局异常处理器
  • Spring MVC接口HandlerExceptionResolver用于抽象一个异常解析器
  • 这种异常解析器被用于分析请求处理器Handler映射或者执行过程中的异常,将这些异常转换成其他形式展示给用户

  • 可以看到,HandlerExceptionResolver接口中定义了一个名为resolveException的方法,该方法主要用于处理Controller中的异常
  • 参数“Exception ex”即为Controller或其下层抛出的异常
  • 参数“Object handler”就是处理器适配器要执行的Handler对象
  • resolveException方法的返回值类型是ModelAndView,也就是说,可以通过这个返回值来设置发送异常时的显示页面

  • 典型的做法是转换成一个错误视图,或者返回某个HTTP状态码给请求端
  • 使用HandlerExceptionResolver实现全局异常处理器;当抛出异常后,要有相应的符合用户体验的友好界面显示异常
  • 综合实例:
  • (1)创建自定义异常类,名称为OperationException

  • 注意:
  • Spring管理的事务,无论是声明式事务还是注解式事务默认是在抛出运行异常(RuntimeException异常)时,才会被Spring框架捕获到然后回滚
  • 该自定义异常类继承的是RuntimeException类,因为一般项目的Service层逻辑都会使用Spring提供的事务管理,当Service层需要抛出自定义异常时,如果该自定义异常继承的是Exception类,则Spring提供的事务管理将会失效,所以这里的自定义异常类继承的是RuntimeException类,这样才不会使Spring提供的事务管理失效
  • (2)创建全局异常处理器OperationExceptionResolver类,该类实现HandlerExceptionResolver接口,并且实现resolveException方法

  • (3)创建名称为error.jsp的页面,符合用户体验的友好界面,用于显示异常信息

  • Spring MVC 为HandlerExceptionResolver提供了四个实现类

(1)ExceptionHandlerExceptionResolver

  • 找到使用@ExceptionHandler注解的ServletInvocableHandlerMethod并调用,基于其执行结果构建ModelAndView

(2)SimpleMappingExceptionResolver

  • 映射异常类名到视图名称,处理时使用此映射关系构建ModelAndView,或者使用缺省视图

(3)ResponseStatusExceptionResolver

  • 如果异常是ResponseStatusException或者使用了注解@ResponseStatus,则利用这些信息将异常翻译成HTTP状态字调用相应的sendError,返回空ModelAndView
  • 注意:该异常解析器会递归检查异常的cause异常

(4)DefaultHandlerExceptionResolver

  • Spring MVC缺省异常处理器,解析时将标准MVC异常翻译成HTTP状态字调用相应对象的方法#sendError,返回一个空ModelAndView对象(注意:不是null)

使用注解实现异常分类管理(@ControllerAdvice 和 @ExceptionHandler)

  • 引言:
  • 在开发中,我们会有如下的场景:某个接口中,存在一些业务异常
  • 例如用户输入的参数校验失败、用户名密码不存在等
  • 当触发这些业务异常时,我们需要抛出这些自定义的业务异常,并对其进行处理
  • 一般我们要把这些异常信息的状态码和异常描述,友好地返回给调用者,调用者则利用状态码等信息判断异常的具体情况
  • 过去,我们可能需要在 controller 层通过 try/catch 处理
  • 首先 catch 自定义异常,然后 catch 其它异常
  • 对于不同的异常,我们需要在 catch 的同时封装将要返回的对象
  • 然而,这么做的弊端就是代码会变得冗长
  • 每个接口都需要做 try/catch 处理,而且一旦需要调整,所有的接口都需要修改一遍,非常不利于代码的维护,如下段代码所示:

  • 那么,有没有什么方法可以简便地处理这些异常信息呢?
  • 答案是肯定的
  • Spring 3.2 中,新增了 @ControllerAdvice 注解,可以用于定义 @ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有 @RequestMapping 中
  • 简单来说就是,可以通过 @ControllerAdvice 注解配置一个全局异常处理类,来统一处理 controller 层中的异常,于此同时 controller 中可以不用再写 try/catch,这使得代码既整洁又便于维护

  • 综合实例:定义自定义异常
  • (1)自定义业务异常类

  • (2)@ControllerAdvice + @ExceptionHandler 配置全局异常处理类

@ControllerAdvice

  • 类型:类注解;定义该类为全局异常处理类

@ExceptionHandler

  • 类型:方法注解;定义该方法为异常处理方法
  • value 的值为需要处理的异常类的 class 文件

  • 这样,就可以对不同的异常进行统一处理了
  • 通常,为了使 controller 中不再使用任何 try/catch,也可以在 GlobalExceptionHandler 中对 Exception 做统一处理
  • 这样其他没有用 @ExceptionHandler 配置的异常就都会统一被处理
  • 遇到异常时抛出异常即可
  • 在业务中,遇到业务异常的地方,直接使用 throw 抛出对应的业务异常即可
  • 例如:


注意:

  • 不一定必须在 controller 层本身抛出异常才能被 GlobalExceptionHandler 处理,只要异常最后是从 contoller 层抛出去的就可以被全局异常处理器处理
  • 异步方法中的异常不会被全局异常处理
  • 抛出的异常如果被代码内的 try/catch 捕获了,就不会被 GlobalExceptionHandler 处理了

优点:

  • 减少代码冗余,代码便于维护

缺点:

  • 只能处理 controller 层抛出的异常,对例如 Interceptor(拦截器)层的异常、定时任务中的异常、异步方法中的异常,不会进行处理

使用 @ControllerAdvice 对不同的 Controller 分别捕获异常并处理

  • 引言
  • 上文介绍了如何在 SpringBoot 工程中对 Controller 配置全局异常处理
  • 后来在实际工程中,又有了如下需求:有些接口在发生异常时,需要持久化错误信息,而有的接口则不需要
  • 如果使用了全局异常处理,那每次发生了异常,还需要判断是哪个接口发生的异常,进而选择是否持久化错误日志
  • 那能不能对全局异常进行配置,对不同类型的接口使用不同的全局异常进行处理呢?
  • 经过查阅文档发现,Spring 提供了对 @ControllerAdvice 注解的配置,我们可以通过配置 @ControllerAdvice 指定拦截范围
  • @ControllerAdvice 指定 Controller 范围
  • 根据 API,我们可以看到注解 @ControllerAdvice 有如下几种配置:

(1)basePackages

  • basePackages:指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理
  • 其中上面两种等价于 basePackages

(2)basePackageClasses

  • basePackageClasses:是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理

(3)assignableTypes

  • assignableTypes:指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理

(4)annotations

  • annotations:指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理

  • 例子
  • 这里用 assignableTypes 配置指定的 Controller 进行测试

(1)创建三个 Controller

  • 其中,BusinessException 是自定义的异常类

(2)创建两个全局异常处理类

(3)分别调用接口,查看错误日志

  • (1)调用 localhost:8080/test1

  • 返回:GlobalExceptionHandler1 服务错误

  • 即 MyController1 异常被 GlobalExceptionHandler1 全局异常类捕获

  • (2)调用 localhost:8080/test2

  • 返回:GlobalExceptionHandler2 服务错误

  • 即 MyController2 异常被 GlobalExceptionHandler2 全局异常类捕获

  • (3)调用 localhost:8080/test3

  • 返回:

  • 即 MyController3 异常没有被全局异常捕获

相关文章:

  • Golang 中如何实现 Set
  • ARM day7 day8 UART串口、PWM蜂鸣器、WDT看门狗、ADC数模转换
  • 电脑加固态硬盘有什么好处
  • Google的guava缓存学习使用
  • vue创建组件和使用
  • 去除 inline-block 元素间间距的方法
  • c语言不定参数
  • html+css+javascript实现贪吃蛇游戏
  • C++高级编程——STL:list容器、set容器和map容器
  • Pytest基础
  • [pytorch入门] 6. 神经网络
  • 小程序样例3:根据日历创建待办事项
  • 数灵通丨可以实现抖音引流微信小程序了
  • 腾讯云短信开发
  • css中>>>、/deep/、::v-deep的作用和区别,element-ui自定义样式
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • IDEA常用插件整理
  • Java 23种设计模式 之单例模式 7种实现方式
  • Java应用性能调优
  • Magento 1.x 中文订单打印乱码
  • Median of Two Sorted Arrays
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 仿天猫超市收藏抛物线动画工具库
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 基于HAProxy的高性能缓存服务器nuster
  • 前端临床手札——文件上传
  • 删除表内多余的重复数据
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • Mac 上flink的安装与启动
  • Prometheus VS InfluxDB
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • ​卜东波研究员:高观点下的少儿计算思维
  • ​业务双活的数据切换思路设计(下)
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (3)nginx 配置(nginx.conf)
  • (WSI分类)WSI分类文献小综述 2024
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (四)JPA - JQPL 实现增删改查
  • (一)RocketMQ初步认识
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转)visual stdio 书签功能介绍
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .Family_物联网
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .net 4.0发布后不能正常显示图片问题
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .net用HTML开发怎么调试,如何使用ASP.NET MVC在调试中查看控制器生成的html?
  • .net中生成excel后调整宽度
  • @Async注解的坑,小心