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})

相关推荐
楚韵天工16 分钟前
宠物服务平台(程序+文档)
java·网络·数据库·spring cloud·编辑器·intellij-idea·宠物
helloworddm17 分钟前
Orleans Stream SubscriptionId 生成机制详解
java·系统架构·c#
失散1321 分钟前
分布式专题——43 ElasticSearch概述
java·分布式·elasticsearch·架构
ajsbxi21 分钟前
【Java 基础】核心知识点梳理
java·开发语言·笔记
AntBlack44 分钟前
虽迟但到 :盘一盘 SpringAI 现在发展得怎么样了?
后端·spring·openai
聪明的笨猪猪1 小时前
Java JVM “调优” 面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
重整旗鼓~1 小时前
28.redisson源码分析分布式锁
java·开发语言
Query*1 小时前
Java 设计模式——工厂模式:从原理到实战的系统指南
java·python·设计模式
懒羊羊不懒@2 小时前
Java基础语法—最小单位、及注释
java·c语言·开发语言·数据结构·学习·算法
ss2732 小时前
手写Spring第4弹: Spring框架进化论:15年技术变迁:从XML配置到响应式编程的演进之路
xml·java·开发语言·后端·spring