Spring MVC 注解之 @ControllerAdvice 实现全局异常处理
通常会在 @Controller
注解作用的类的方法上使用@ExceptionHandler,@ModelAttribute,@InitBinder
来处理异常或初始化绑定,这三个注解对所用使用了 @RequestMapping
注解的控制器内的方法有效。
如果希望此类方法在全局范围内(跨控制器)应用,则可以在带有 @ControllerAdvice
或 @RestControllerAdvice
注解的类中声明它们这三个注解。
@ControllerAdvice
用于声明一个 控制器 建言,作用在类上,可以将控制器的全局配置统一放置在该注解作用的类里,结合在方法上使用 @ExceptionHandler
注解,就能实现全局的异常控制。
Controller Advice
@ControllerAdvice
@ControllerAdvice
组合了 @Component
注解,会自动将注释的类注册为 Spring 的 Bean。
默认情况下,@ControllerAdvice 方法对所有请求起效(即所有控制器),但可以通过属性设置指定控制器。如下示例
1 | //所有使用了 @RestController 注解的控制器 |
注:上面的示例中的选择器在运行时进行评估,如果广泛使用,可能会对性能产生负面影响。
@RestControllerAdvice
此注解包含了 @ControllerAdvice
和 @ResponseBody
,作用在 RestController
类上,@ExceptionHandler
注解的方法采用 @ResponseBody 语义,即通过消息转换将内容呈现给响应主体。
@ModelAttribute
本来作用是绑定键值对到 Model
,在 @ControllerAdvice
注解的类的方法中使用,是将键值对添加到全局,所用使用@RequestMapping
注解的方法都能获取到该键值对。
@InitBinder
用来设置 WebDataBinder
, WebDataBinder 用来自动绑定前台请求参数到Model
中。
@ExceptionHandler
@Controller
and @ControllerAdvice
注解的类可以使用 @ExceptionHandler
注解来处理异常,@ExceptionHandler 注解作用在方法上。
@ExceptionHandler 只有一个属性值,是继承自顶级异常类 Throwable 的异常类 Class 对象数组。
1 |
|
使用:
1 |
|
在响应主体中使用错误详细信息实现全局异常处理的应用程序应考虑扩展 ResponseEntityExceptionHandler
,它提供了Spring MVC 引发的异常的处理并提供了自定义响应主体的钩子。
要使用此功能,创建 ResponseEntityExceptionHandler
的子类,并使用 @ControllerAdvice
对其进行注释,重写必要的方法,并将其声明为 Spring bean。
全局异常使用
@ControllerAdvice 示例
定义控制器 Controller
1
2
3
4
5
6
7
8
9
public class UserController {
public String getUser(Integer id) {
throw new ClassNotFoundException("没有找到类");
}
}控制器全局处理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32/**
* @ControllerAdvice:声明一个控制建言,该注解组合了@Component注解,自动注册为Spring的Bean
* @ExceptionHandler:定义全局处理,根据value属性过滤拦截条件,下例拦截所有的Exception
* @ModelAttribute:将model健值添加到全局,所有@RequestMapping注解的方法可获得此值
* @InitBinder:定制WebDataBinder
*
*/
public class ControllerAdviceConfig {
public ModelAndView exception(Exception exception, WebRequest request) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("errorMessage", exception.getMessage());
return mv;
}
public void addAttributes(Model model) {
model.addAttribute("msg", "错误信息");
}
/**
* 忽略request参数的id
* @param webDataBinder
*/
public void initBinder(WebDataBinder webDataBinder) {
webDataBinder.setDisallowedFields("id");
}
}@RestControllerAdvice 示例
定义控制器 Controller,同上。
定义全局处理类
1
2
3
4
5
6
7
8
9
10
11
12
public class GlobalException {
private static final Logger logger = LoggerFactory.getLogger(GlobalException.class);
public ResponseVO globalException(Exception ex) {
logger.error("系统异常,", ex);
return new ResponseVO(-1, null != ex.getMessage() ? ex.getMessage() : ex.toString());
}
}注:上例中的 ResponseVO 类是一个自定义的响应体,通常包含 msg,code,state,data 属性。
自定义业务异常
1
2
3
4
5
6
7
8
9
10
11public class BSException extends RuntimeException {
private static final long serialVersionUID = -1243366730551644726L;
public BSException(String error) {
super(error);
}
public BSException(String error, Throwable e) {
super(error, e);
}
}
参考资料
Spring MVC 注解之 @ControllerAdvice 实现全局异常处理
http://blog.gxitsky.com/2018/03/31/SpringMVC-01-controllerAdvice/