@Controller和@ControllerAdvice类可以有多个@ExceptionHandler修饰的方法来处理controller抛出的异常样。例如:
@Controller
public class SimpleController {
// ...
@ExceptionHandler
public ResponseEntity<String> handle(IOException ex) {
// ...
}
}
注解可以列出匹配的异常,或者像上面的代码一样,在方法中列出异常。当有多个异常匹配的时候,ExceptionDepthComparator可以根据异常的深度来匹配处理异常的函数。 有多个@ControllerAdvice的时候,需要根据声明的异常匹配的@ControllerAdvice来进行优先级排序。因为异常匹配的时候高优先级的@ControllerAdvice比低优先级的更鲜匹配。
函数参数
| 函数参数 | 解释 |
|---|---|
| 异常类型 | 访问抛出的异常 |
HandlerMethod |
访问抛出异常的方法 |
WebRequest,NativeWebRequest |
访问请求参数,session等 |
ServletRequest,ServletResponse |
可以是指定的请求和响应类型例如ServletRequest,HttpServletRequest,也可以是Spring的MultipartRequest,MultipartHttpServletRequest |
HttpSession |
参数永不为null,访问session非线程安全,如果多个请求访问一个session,需要设置RequestMappingHandlerAdapter的synchronizeOnSession为true。 |
Principal |
当前授权用户。 |
HttpMethod |
请求的HTTP方法 |
Locale |
当前请求的区域,由LocaleResolver解析 |
TimeZone,ZoneId |
由LocaleContextResolver解析的当前请求的时区 |
OutputStream,Writer |
访问由Servlet API 暴露的响应体 |
Map,Model,ModelMap |
访问会在渲染模板时使用的变量。 |
RedirectAttributes |
重定向时使用的属性 |
@SessionAttributes |
在不同的请求中存储session |
@RequestAttribute |
访问请求的属性。 |
返回值
| 返回值类型 | 解释 |
|---|---|
@ResponseBody |
返回值由HttpMessageConverters转换,直接写到响应体 |
HttpEntity<B>, ResponseEntity<B> |
返回值包括,http header和body |
String |
由ViewResolver解析出具体的模板渲染。 |
View |
返回具体的视图 |
Map,Model |
model包含的属性,视图由RequestToViewNameTranslator解析 |
@ModelAttribute |
返回添加到Model的属性,视图由RequestToViewNameTranslator解析. |
ModelAndView |
返回具体视图和添加的model |
void |
返回void,则Spring MVC会认为Controller内部已经处理好响应内容了。 |
| 其他类型 | 如果不返回以上类型,默认当作model属性处理。 |
REST API 异常
REST 服务一般需要将错误的细节放到响应体中。Spring Framework默认并不支持这样处理,因为这属于应用层需要做的事情。然而@RestController可以使用@ExceptionHandler方法通过返回ResponseEntity来包含错误信息。这些方法同样可以放到@ControllerAdvice中。 如果应用需要实现全局的异常处理同时将错误信息放到响应体中,可以实现ResponseEntityExceptionHandler来处理Spring
MVC的引发的异常,将错误写入响应体中。步骤如下: 1. 继承ResponseEntityExceptionHandler,重写响应方法。 2. 使用@ControllerAdvice修饰。 3. 注册为Spring bean
Controller Advice
一般来讲@ExceptionHandler,@InitBinder,@ModelAttribute修饰的方法都是直接放在其声明使用的@Controller中的。如果要声明跨controller的全局函数,就需要在@ControllerAdvice或者@RestControllerAdvice中声明。 @ControllerAdvice被@Component标记,所以可以自动的注册为Spring的bean。@RestControllerAdvice是@ControllerAdvice和@ResponseBody的组合,意味着@ExceptionHandler修饰的方法可以直接通过类型转换将返回值写入到响应体中。
启动后,@RequestMapping,@ExceptionHandler的函数会检测类型为@ControllerAdvice的bean,然后动态运行他们的方法。@ControllerAdvice的全局的@ExceptionHandler的优先级低于在本地@ExceptionHandler的优先级,而@ModelAttribute和@InitBinder则恰好想法,他们会在本地的方法执行之前执行。
默认情况下@ControllerAdvice应用与所有的请求,例如所有的controller,但是也可以通过@ControllerAdvice的属性来缩小这个范围,例如:
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}
// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}
// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}
由于上述选择器是在运行时确定的,所以可能会有一些性能损失。