SpringMVC 笔记 - 9 - 异常处理器
一、异常处理器的核心概念
在 SpringMVC 框架中,控制器(Controller)的处理器方法执行过程中,可能因参数错误、业务逻辑异常、IO 异常等各种原因抛出异常。如果不做特殊处理,异常会直接暴露给前端,既不友好也可能泄露系统敏感信息。
异常处理器(HandlerExceptionResolver) 是 SpringMVC 提供的异常处理核心接口,专门用于统一拦截、处理处理器方法执行过程中抛出的异常。
核心作用(一句话概括):拦截处理器方法执行时抛出的异常,通过预设的逻辑跳转到指定视图,并向前端展示友好的异常提示信息,避免原始异常直接暴露。
核心接口与方法
SpringMVC 通过HandlerExceptionResolver接口定义异常处理的规范,其核心方法为:
java
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
-
参数说明:
request/response:当前请求和响应对象;handler:抛出异常的处理器(Controller 方法);ex:捕获到的异常对象。
-
返回值:
ModelAndView,指定异常处理完成后跳转的视图名称,以及需要传递到视图的异常数据。
二、异常处理器的两大默认实现
SpringMVC 为HandlerExceptionResolver提供了两个常用的默认实现类,分别对应 "默认异常处理" 和 "自定义异常处理" 场景。
1. DefaultHandlerExceptionResolver(默认异常处理器)
这是 SpringMVC 内置的默认异常处理器,无需手动配置,框架会自动启用。
核心特性
- 针对 SpringMVC 框架自身的常见异常(如请求方式不匹配、参数绑定失败、视图找不到等)进行标准化处理;
- 例如:当前端发送
POST请求,但处理器方法仅支持GET请求时,该处理器会捕获RequestMethodNotSupportedException,并返回 405(Method Not Allowed)状态码; - 优先级高于自定义异常处理器(若未手动调整优先级);
- 缺点:仅处理框架内置异常,无法灵活适配业务自定义异常,且提示信息固定,无法自定义前端展示视图。
2. SimpleMappingExceptionResolver(自定义异常处理器)
这是开发中最常用的自定义异常处理器实现类,支持通过配置灵活指定 "异常类型 - 跳转视图" 的映射关系,还能将异常对象传递到视图层展示。
核心优势
- 支持按异常类型(如
NullPointerException、Exception等)指定不同的跳转视图; - 可将异常对象存入 Request 域,供前端页面展示自定义提示;
- 支持调整优先级,覆盖默认异常处理器的逻辑。
三、自定义异常处理器的实现方式
SpringMVC 提供两种主流方式配置SimpleMappingExceptionResolver:XML 配置文件方式、注解方式。
方式 1:XML 配置文件(springmvc.xml)
通过 SpringMVC 的 XML 配置文件声明SimpleMappingExceptionResolver Bean,适用于传统 XML 配置的项目。
完整配置示例(结合实战代码)
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 组件扫描:确保Controller被Spring管理 -->
<context:component-scan base-package="com.zzz"/>
<!-- 视图解析器:配置Thymeleaf模板解析(需配合前端页面路径) -->
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="order" value="1"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring6.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/> <!-- 视图前缀 -->
<property name="suffix" value=".html"/> <!-- 视图后缀 -->
<property name="templateMode" value="HTML"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
<!-- 自定义异常处理器:SimpleMappingExceptionResolver -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 优先级:设置为-1,让自定义处理器优先级高于默认处理器(DefaultHandlerExceptionResolver) -->
<!-- <property name="order" value="-1"/> -->
<!-- 异常映射:key=异常全类名,value=跳转的视图名称 -->
<property name="exceptionMappings">
<props>
<!-- 匹配所有Exception及其子类,跳转到tip视图 -->
<prop key="java.lang.Exception">tip</prop>
<!-- 可扩展:针对特定异常配置专属视图 -->
<!-- <prop key="java.lang.NullPointerException">nullTip</prop> -->
<!-- <prop key="com.zzz.exception.BusinessException">businessTip</prop> -->
</props>
</property>
<!-- 异常对象存储:将异常存入Request域,key为"yiChang",供前端页面获取 -->
<property name="exceptionAttribute" value="yiChang"/>
</bean>
<!-- 开启MVC注解驱动 -->
<mvc:annotation-driven/>
<!-- 静态资源处理 -->
<mvc:default-servlet-handler/>
</beans>
关键配置说明
| 配置项 | 作用 |
|---|---|
order |
异常处理器优先级,值越小优先级越高;默认处理器优先级为 0,自定义设为 - 1 可覆盖 |
exceptionMappings |
异常类型与视图的映射关系,key 必须是异常的全类名(如java.lang.Exception) |
exceptionAttribute |
将异常对象存入 Request 域的 key 名称,前端可通过该 key 获取异常信息 |
方式 2:注解方式(@ControllerAdvice + @ExceptionHandler)
基于注解的异常处理更灵活,无需 XML 配置,适用于注解驱动的现代 SpringMVC 项目。
完整实现示例(结合实战代码)
java
package com.zzz.controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* 全局异常处理器(注解版)
* @ControllerAdvice:标识这是一个全局控制器增强类,可拦截所有Controller的异常
*/
@ControllerAdvice // 核心注解:开启全局异常处理
public class ExceptionController {
/**
* 异常处理方法:@ExceptionHandler指定处理的异常类型
* 方法参数:
* - Exception e:捕获到的异常对象
* - Model model:用于向视图传递数据(存入Request域)
* 返回值:跳转的视图名称
*/
@ExceptionHandler // 不指定异常类型时,默认处理所有Exception
// @ExceptionHandler({NullPointerException.class, BusinessException.class}) // 精准处理指定异常
public String handleException(Exception e, Model model) {
// 将异常对象存入Model(最终传递到Request域),key为"yiChang"
model.addAttribute("yiChang", e);
// 跳转到tip视图(需配合视图解析器的前缀/后缀)
return "tip";
}
}
注解核心说明
| 注解 | 作用 |
|---|---|
@ControllerAdvice |
全局控制器增强注解,可指定扫描的 Controller 包(如@ControllerAdvice(basePackages = "com.zzz.controller")) |
@ExceptionHandler |
标注在方法上,指定该方法处理的异常类型(支持数组,如{Exception.class, NullPointerException.class}) |
前端视图展示异常信息(tip.html)
通过 Thymeleaf 模板引擎获取 Request 域中的异常对象,展示友好提示:
html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Tip</title>
</head>
<body>
<!-- 友好提示 -->
<h1>出错了,请联系管理员</h1>
<hr>
<!-- Thymeleaf表达式获取Request域中的异常对象(key为yiChang) -->
<div th:text="${yiChang}"></div>
<!-- 可扩展:展示异常详情(如堆栈信息) -->
<!-- <div th:text="${yiChang.stackTrace}"></div> -->
<!-- <div th:text="${yiChang.message}"></div> -->
</body>
</html>
四、异常处理器的执行流程
- 前端发送请求(如
POST /index),DispatcherServlet 将请求分发到对应的 Controller 处理器方法(如IndexController.toIndex()); - 处理器方法执行过程中抛出异常(如空指针、请求方式不匹配等);
- DispatcherServlet 检测到异常,调用已配置的
HandlerExceptionResolver异常处理器; - 异常处理器按优先级执行(自定义处理器优先级高于默认处理器),根据
exceptionMappings找到对应的跳转视图; - 异常处理器将异常对象存入 Request 域(key 由
exceptionAttribute指定),并返回ModelAndView; - 视图解析器(如 ThymeleafViewResolver)解析视图名称,跳转到指定的 HTML 页面;
- 前端页面通过 Thymeleaf 表达式获取异常信息,展示友好提示。
五、实战注意事项
1. 视图路径匹配
SpringMVC 的视图解析器配置了前缀(/WEB-INF/templates/)和后缀(.html),因此异常处理器中指定的视图名称(如tip)会被解析为/WEB-INF/templates/tip.html,需确保该文件存在。
2. 优先级调整
- 默认情况下,
DefaultHandlerExceptionResolver(默认处理器)优先级高于SimpleMappingExceptionResolver(自定义处理器); - 若需让自定义处理器优先执行,需给
SimpleMappingExceptionResolver配置order属性(如order=-1)。
3. 注解方式与 XML 方式的兼容
- 项目中可同时存在 XML 配置和注解配置的异常处理器,优先级由
@Order(注解)或order(XML)决定; - 注解方式的
@ControllerAdvice优先级默认高于 XML 配置的SimpleMappingExceptionResolver(可通过@Order调整)。
4. 异常信息的安全控制
- 生产环境中,不建议直接展示完整的异常堆栈信息(避免泄露系统信息);
- 可在异常处理器中对异常信息进行封装,仅向前端返回友好提示(如 "系统繁忙,请稍后重试"),详细异常日志通过
log4j/slf4j记录到日志文件。
5. 扩展:自定义业务异常
开发中可自定义业务异常类,针对性处理不同业务场景的异常:
java
// 自定义业务异常
public class BusinessException extends RuntimeException {
private String code; // 异常码
private String msg; // 异常提示
// 构造方法、getter/setter
}
// 注解版异常处理器扩展
@ControllerAdvice
public class ExceptionController {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public String handleBusinessException(BusinessException e, Model model) {
model.addAttribute("errorCode", e.getCode());
model.addAttribute("errorMsg", e.getMsg());
return "businessTip"; // 业务异常专属视图
}
// 处理通用异常
@ExceptionHandler(Exception.class)
public String handleException(Exception e, Model model) {
model.addAttribute("yiChang", e);
return "tip";
}
}
六、两种实现方式的对比
| 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| XML 配置方式 | 配置集中,无需修改代码 | 灵活性低,不支持复杂逻辑 | 传统 XML 配置项目、简单异常处理 |
| 注解方式 | 灵活度高,支持复杂业务逻辑 | 配置分散在代码中 | 注解驱动项目、复杂异常处理 |
七、总结
- 异常处理器是 SpringMVC 统一处理处理器方法异常的核心机制,核心接口为
HandlerExceptionResolver; DefaultHandlerExceptionResolver是默认处理器,处理框架内置异常;SimpleMappingExceptionResolver是自定义处理器,支持灵活配置;- 自定义异常处理器有两种实现方式:XML 配置(适合简单场景)、注解(
@ControllerAdvice + @ExceptionHandler,适合复杂场景); - 异常处理器的核心价值是统一拦截异常、跳转友好视图、隐藏原始异常信息,提升用户体验和系统安全性。