异常
@Controller
和 @ControllerAdvice 类可以有
@ExceptionHandler
方法来处理控制器方法中的异常,如以下示例所示:
include-code::./SimpleController[indent=0]
异常映射
异常可以匹配正在传播的顶级异常(例如,直接抛出的 IOException
)或包装器异常中的嵌套原因(例如,包装在 IllegalStateException
中的 IOException
)。从 5.3 版本开始,这可以匹配任意原因级别,而以前只考虑直接原因。
对于匹配的异常类型,最好将目标异常声明为方法参数,如前面的示例所示。当多个异常方法匹配时,通常首选根异常匹配而不是原因异常匹配。更具体地说,ExceptionDepthComparator
用于根据异常与抛出异常类型的深度对异常进行排序。
或者,注解声明可以缩小要匹配的异常类型,如以下示例所示:
您甚至可以使用特定异常类型的列表和非常通用的参数签名,如以下示例所示:
根异常和原因异常匹配之间的区别可能令人惊讶。
在前面所示的 |
我们通常建议您在参数签名中尽可能具体,减少根异常和原因异常类型之间不匹配的可能性。考虑将多匹配方法分解为单独的 @ExceptionHandler
方法,每个方法通过其签名匹配单个特定异常类型。
在多 @ControllerAdvice
安排中,我们建议在具有相应顺序优先级的 @ControllerAdvice
上声明您的主要根异常映射。虽然根异常匹配优先于原因,但这是在给定控制器或 @ControllerAdvice
类的所有方法中定义的。这意味着高优先级 @ControllerAdvice
bean 上的原因匹配优先于低优先级 @ControllerAdvice
bean 上的任何匹配(例如,根匹配)。
最后但同样重要的是,@ExceptionHandler
方法实现可以选择通过以其原始形式重新抛出异常来退出处理给定异常实例。这在您只对根级别匹配或在无法静态确定的特定上下文中的匹配感兴趣的场景中很有用。重新抛出的异常会通过剩余的解析链传播,就好像给定的 @ExceptionHandler
方法一开始就没有匹配一样。
Spring MVC 中对 @ExceptionHandler
方法的支持建立在 DispatcherServlet
级别,HandlerExceptionResolver 机制之上。
媒体类型映射
除了异常类型之外,@ExceptionHandler
方法还可以声明可生成的媒体类型。这允许根据 HTTP 客户端请求的媒体类型(通常在 "Accept" HTTP 请求头中)来细化错误响应。
应用程序可以直接在注解上声明可生成的媒体类型,对于相同的异常类型:
这里,方法处理相同的异常类型,但不会被拒绝为重复。相反,请求 "application/json" 的 API 客户端将收到 JSON 错误,浏览器将获得 HTML 错误视图。每个 @ExceptionHandler
注解可以声明多个可生成的媒体类型,错误处理阶段的内容协商将决定使用哪种内容类型。
方法参数
@ExceptionHandler
方法支持以下参数:
方法参数 | 描述 |
---|---|
异常类型 |
用于访问抛出的异常。 |
|
用于访问抛出异常的控制器方法。 |
|
泛型访问请求参数以及请求和会话属性,无需直接使用 Servlet API。 |
|
选择任何特定的请求或响应类型(例如, |
|
强制会话的存在。因此,此类参数永远不会为 |
|
当前认证用户——如果已知,可能是特定的 |
|
请求的 HTTP 方法。 |
|
当前请求区域设置,由最具体的 |
|
与当前请求关联的时区,由 |
|
用于访问原始响应体,由 Servlet API 公开。 |
|
用于访问错误响应的模型。始终为空。 |
|
指定重定向时要使用的属性——(即要附加到查询字符串)和要临时存储直到重定向后的请求的 flash 属性。请参阅 重定向属性 和 Flash 属性。 |
|
用于访问任何会话属性,与因类级别 |
|
用于访问请求属性。有关更多详细信息,请参阅 |
返回值
@ExceptionHandler
方法支持以下返回值:
返回值 | 描述 |
---|---|
|
返回值通过 |
|
返回值指定通过 |
|
用于呈现 RFC 9457 错误响应,正文中包含详细信息,请参阅 错误响应 |
|
一个视图名称,将通过 |
|
一个 |
|
要添加到隐式模型的属性,视图名称通过 |
|
要添加到模型的属性,视图名称通过 请注意, |
|
要使用的视图和模型属性,以及可选的响应状态。 |
|
具有 如果以上都不是, |
任何其他返回值 |
如果返回值与上述任何一个都不匹配,并且不是简单类型(由 BeanUtils#isSimpleProperty 确定),则默认情况下,它被视为要添加到模型的模型属性。如果它是简单类型,则保持未解析。 |