|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
异常
@Controller 和 @ControllerAdvice 类可以包含
@ExceptionHandler 方法,用于处理控制器方法抛出的异常,如下例所示:
-
Java
-
Kotlin
@Controller
public class SimpleController {
// ...
@ExceptionHandler
public ResponseEntity<String> handle(IOException ex) {
// ...
}
}
@Controller
class SimpleController {
// ...
@ExceptionHandler
fun handle(ex: IOException): ResponseEntity<String> {
// ...
}
}
该异常可以匹配正在传播的顶层异常(例如直接抛出的IOException),也可以匹配包装异常内部的嵌套原因(例如被包装在IOException中的IllegalStateException)。从5.3版本开始,此匹配可以应用于任意层级的异常原因,而此前仅考虑直接原因。
为了匹配异常类型,建议将目标异常声明为方法参数,如前面的示例所示。当多个异常处理方法匹配时,通常优先选择与根异常(root exception)匹配的方法,而不是与原因异常(cause exception)匹配的方法。更具体地说,系统会使用 ExceptionDepthComparator 根据异常类型与所抛出异常之间的继承深度对异常进行排序。
或者,注解声明可以缩小要匹配的异常类型范围,如下例所示:
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
// ...
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: IOException): ResponseEntity<String> {
// ...
}
你甚至可以使用一个特定异常类型的列表,并配合非常通用的参数签名,如下例所示:
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
// ...
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: Exception): ResponseEntity<String> {
// ...
}
|
根异常与原因异常的匹配区别可能会令人感到意外。 在前面所示的 在 |
我们通常建议您在方法参数签名中尽可能具体,以减少根异常类型与原因异常类型之间不匹配的可能性。
考虑将一个匹配多种异常的方法拆分为多个单独的 @ExceptionHandler 方法,每个方法通过其签名仅匹配一种特定的异常类型。
在多个 @ControllerAdvice 的配置中,我们建议将主要的根异常映射声明在一个通过相应顺序(order)设置为高优先级的 @ControllerAdvice 上。虽然对于某个给定的控制器或 @ControllerAdvice 类中的方法而言,根异常匹配优于原因(cause)匹配,但这仅限于该类内部的方法之间进行比较。这意味着,高优先级 @ControllerAdvice Bean 中对异常原因的匹配,会优先于低优先级 @ControllerAdvice Bean 中的任何匹配(例如根异常匹配)。
最后但同样重要的是,@ExceptionHandler 方法的实现可以选择通过以原始形式重新抛出给定的异常实例,从而放弃处理该异常。
这在你只对根级别匹配或特定上下文中的匹配感兴趣(而这些上下文无法静态确定)的场景中非常有用。被重新抛出的异常会继续沿着剩余的解析链传播,就好像该 @ExceptionHandler 方法从一开始就没有匹配到一样。
Spring MVC 中对 @ExceptionHandler 方法的支持是建立在 DispatcherServlet 层级的 HandlerExceptionResolver 机制之上的。
方法参数
@ExceptionHandler 方法支持以下参数:
| 方法参数 | <description> </description> |
|---|---|
异常类型 |
用于访问抛出的异常。 |
|
用于访问引发异常的控制器方法。 |
|
无需直接使用 Servlet API,即可通用地访问请求参数、请求属性和会话属性。 |
|
选择任意特定的请求或响应类型(例如, |
|
强制要求会话存在。因此,此类参数永远不会 |
|
当前已认证的用户——如果已知,可能是某个特定的 |
|
请求的 HTTP 方法。 |
|
当前请求的区域设置,由可用的最具体的 |
|
由 |
|
用于访问由 Servlet API 暴露的原始响应体。 |
|
用于访问错误响应的模型。始终为空。 |
|
指定在重定向时使用的属性——(即附加到查询字符串中)以及临时存储的 Flash 属性,这些属性会保留到重定向后的下一次请求为止。 参见 重定向属性 和 Flash 属性。 |
|
用于访问任何会话属性,这与由于类级别的 |
|
用于访问请求属性。请参阅 |
返回值
@ExceptionHandler 方法支持以下返回值:
| 返回值 | <description> </description> |
|---|---|
|
返回值通过 |
|
返回值指定整个响应(包括 HTTP 头部和响应体)应通过 |
|
要在响应体中包含详细信息以渲染 RFC 7807 错误响应, 请参阅错误响应 |
|
要在响应体中包含详细信息以渲染 RFC 7807 错误响应, 请参阅错误响应 |
|
一个视图名称,将通过 |
|
一个用于渲染的 |
|
通过 |
|
一个要添加到模型中的属性,其视图名称通过 请注意, |
|
要使用的视图和模型属性,以及可选的响应状态。 |
|
一个返回类型为 如果以上情况均不成立, |
任何其他返回值 |
如果返回值不匹配上述任何一种情况,并且不是简单类型(由 BeanUtils#isSimpleProperty 判定), 默认情况下,它将被视为模型属性并添加到模型中。如果它是简单类型, 则保持未解析状态。 |