Spring MVC 中的统一异常处理

文章目录

  • [Spring MVC 中的统一异常处理](#Spring MVC 中的统一异常处理)
    • [Spring MVC 中跳转自定义 404 页面的两种常见方式](#Spring MVC 中跳转自定义 404 页面的两种常见方式)
      • [在 web.xml 中指定自定义的 404 页面](#在 web.xml 中指定自定义的 404 页面)
      • [提供一个匹配 * 的 Controller 请求处理方法](#提供一个匹配 * 的 Controller 请求处理方法)
    • [使用 @ExceptionHandler 注解](#使用 @ExceptionHandler 注解)
    • [使用 @ControllerAdvice + @ExceptionHandler 注解](#使用 @ControllerAdvice + @ExceptionHandler 注解)
      • 使用示例
      • [控制生效的 Controller 范围](#控制生效的 Controller 范围)

Spring MVC 中的统一异常处理

Spring MVC 中跳转自定义 404 页面的两种常见方式

在 web.xml 中指定自定义的 404 页面

xml 复制代码
<error-page>
  <error-code>404</error-code>
  <location>/WEB-INF/jsp/404.jsp</location>
</error-page>

提供一个匹配 * 的 Controller 请求处理方法

java 复制代码
// 凡是不能精确匹配的 url,都会由这个请求处理方法处理
@RequestMapping("*")
public String error404() {
    return "404";
}

使用 @ExceptionHandler 注解

@ExceptionHandler 注解用于标注于某个 Controller 的方法上,例如:

java 复制代码
@Controller      
public class GlobalController {               

    /**    
     * 用于处理异常的
     */      
    @ExceptionHandler({AException.class, BException.class, ...})       
    public String exception(MyException e) {    
        ...
    }

    @RequestMapping("test1")       
    public void test2() {
        ...
    }
    
    @RequestMapping("test2")       
    public void test2() {
        ...
    }
}

当 Controller 的请求方法发生指定异常时,@ExceptionHandler 所标注的方法将会被执行。返回给服务器的数据也就由该方法的返回值决定。

@ExceptionHandler 所标注的方法的常见参数有以下几种:

  • 一个异常参数。代表所发生的异常(最常用)

  • HttpServletRequest / HttpServletResponse 对象

  • HttpSession 对象

  • Model 对象

  • 等等。

@ExceptionHandler 所标注的方法的返回值的类型支持:

  • ModelAndView 对象(最常用)

  • Model 对象

  • Map 对象

  • View 对象

  • 被解析成一个视图名称的 String 值(次常用)

  • 等等

另外,可以将 @ResponseStatus@ExceptionHandler 结合使用,来定义 HTTP 响应的响应状态。

可以看到,这种方式最大的缺陷就是不能全局控制异常。每个类都要写一遍。

使用 @ControllerAdvice + @ExceptionHandler 注解

@ExceptionHandler 需要进行异常处理的方法必须与出错的方法在同一个 Controller 里面。那么当代码加入了 @ControllerAdvice,则不需要必须在同一个 controller 中了。

这也是 Spring 3.2 带来的新特性。从名字上可以看出大体意思是控制器增强。

使用示例

请确保此 WebExceptionHandle 类能被扫描到并装载进 Spring 容器中。由于标注了 @ControllerAdvice 注解,在开启了包扫描的情况下,Spring 会创建该类的单例对象。

java 复制代码
@Slf4j
@ControllerAdvice(assignableTypes = FirstController.class)
public class FirstControllerExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    public String demo1(Exception e) {
        log.warn("IllegalArgumentException");
        return "";
    }

    @ExceptionHandler(NullPointerException.class)
    public String demo(Exception e) {
        log.warn("NullPointerException");
        return "";
    }
}

上述方法中的参数对象就是 Controller 层抛出的异常对象。注意,该方法如果有第二个参数,那么该机制会失效,无法捕获-处理 Controller 抛出的异常!

控制生效的 Controller 范围

注意到,我是这样编写注解的:

java 复制代码
@ControllerAdvice(assignableTypes = { FirstController.class })

它用来限定这些异常处理函数起作用的 Controller 的范围。如果不写,则默认对所有 Controller 有效。

这也是 ControllerAdvice 进行统一异常处理的优点,它能够细粒度的控制该异常处理器针对哪些 Controller 有效,这样的好处是:

  1. 一个系统里就能够存在不同的异常处理器,Controller 也可以有选择的决定使用哪个,更加灵活。

  2. 不同的业务模块可能对异常处理的方式不同,通过该机制就能做到。

  3. 设想一个一开始并未使用全局异常处理的系统,如果直接引入全局范围内生效的全局异常处理,势必可能会改变已有 Controller 的行为,有侵入性。

    也就是说,如果不控制生效范围,即默认对所有 Controller 生效。如果控制生效范围,则默认对所有 Controller 不生效,降低侵入性。

ControllerAdvice 支持的限定范围:

  1. 按注解:@ControllerAdvice(annotations = RestController.class)

  2. 按包名:@ControllerAdvice("org.example.controllers")

  3. 按类型:@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})

相关推荐
xiaoye37085 小时前
Java 自动装箱 / 拆箱 原理详解
java·开发语言
YDS8296 小时前
黑马点评 —— 分布式锁详解加源码剖析
java·spring boot·redis·分布式
迷藏4946 小时前
**发散创新:基于 Rust的开源权限管理系统设计与实战**在现代软件架构中,**权限控制**早已不
java·开发语言·rust·开源
升鲜宝供应链及收银系统源代码服务7 小时前
《IntelliJ + Claude Code + Gemini + ChatGPT 实战配置手册升鲜宝》
java·前端·数据库·chatgpt·供应链系统·生鲜配送
daidaidaiyu7 小时前
Nacos实例一则及其源码环境搭建
java·spring
小江的记录本7 小时前
【Redis】Redis全方位知识体系(附《Redis常用命令速查表(完整版)》)
java·数据库·redis·后端·python·spring·缓存
摇滚侠7 小时前
Java 项目《谷粒商城-1》架构师级Java 项目实战,对标阿里 P6-P7,全网最强,实操版本
java·开发语言
zihao_tom8 小时前
Spring Boot(快速上手)
java·spring boot·后端
hua872228 小时前
SpringSecurity之跨域
java
小王不爱笑1328 小时前
G1 GC 的核心基础:Region 模型的补充细节
java·jvm·算法