使用 @ExceptionHandler 处理异常
@ExceptionHandler 是作用在方法上的注解,在对应的Controller中定义 @ExceptionHandler 注解的方法即可处理当前 Controller 对应的异常。
package com.yyoo.springmvc.controller;
import com.yyoo.springmvc.bean.MyResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo5")
public class Demo5Controller {
@ExceptionHandler(Exception.class)
public MyResponse exceptionHandler(Exception ex){
return MyResponse.success(ex.getMessage());
}
@RequestMapping("testException")
public MyResponse testException(){
if(true){
throw new RuntimeException("发生异常");
}
return MyResponse.success();
}
}
@ExceptionHandler(Exception.class) 表示处理所以Exception或其子类。如果我们需要更细的异常控制,我们可以定义多个由@ExceptionHandler 注解的方法,然后对应的Exception.class不一样。
如果我们需要同一个方法处理多种类型的异常:@ExceptionHandler({Exception1.class,Exception2.class})
@ExceptionHandler 注解支持的方法参数
方法参数 | 描述 |
---|---|
Exception | 用于访问引发的异常(我们都示例中就是Exception)。 |
HandlerMethod | 用于访问引发异常的控制器方法。 |
WebRequest, NativeWebRequest | 对请求参数以及请求和会话属性的通用访问,无需直接使用 Servlet API。 |
javax.servlet.ServletRequest, javax.servlet.ServletResponse | 选择任何特定的请求或响应类型(例如,ServletRequestor HttpServletRequest或 Spring 的MultipartRequestor MultipartHttpServletRequest)。 |
javax.servlet.http.HttpSession | 强制会话的存在。因此,这样的论证永远不会null。请注意,会话访问不是线程安全的。多个请求是可以同时访问一个会话。 |
java.security.Principal | 当前经过身份验证的用户 -Principal如果已知,可能是特定的实现类。 |
HttpMethod | 请求的 HTTP 方法。 |
java.util.Locale | 当前请求区域设置,由最具体的LocaleResolver可用区域确定- 实际上,配置的LocaleResolver或LocaleContextResolver. |
java.util.TimeZone, java.time.ZoneId | 与当前请求关联的时区,由 确定LocaleContextResolver。 |
java.io.OutputStream, java.io.Writer | 用于访问由 Servlet API 公开的原始响应正文。 |
java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap | 用于访问模型以获得错误响应。总是空的。 |
RedirectAttributes | 指定在重定向的情况下使用的属性 - (即附加到查询字符串)和要临时存储的 flash 属性,直到重定向后的请求。 |
@SessionAttribute | 用于访问任何会话属性,与作为类级别@SessionAttributes声明的结果存储在会话中的模型属性相反。 |
@RequestAttribute | 用于访问请求属性。 |
@ExceptionHandler 注解支持的方法返回值
返回值 | 描述 |
---|---|
@ResponseBody | 返回值通过HttpMessageConverter实例转换并写入响应。 |
HttpEntity, ResponseEntity | 返回值指定完整的响应(包括 HTTP 标头和正文)通过HttpMessageConverter实例转换并写入响应。 |
String | 要与ViewResolver实现一起解析并与隐式模型一起使用的视图名称 |
View | View实例以使用用于与所述隐式模型一起渲染 |
java.util.Map, org.springframework.ui.Model | 要添加到隐式模型的属性 |
@ModelAttribute | 要添加到模型的属性 |
void | 用的方法void返回类型(或null返回值)被认为已经完全处理的响应。 |
@ControllerAdvice 或 @RestControllerAdvice 统一处理异常
@ControllerAdvice 和 @RestControllerAdvice 与 @Controller 或 @RestController 意思是一样的,这里不在做过多讲解了。
@ControllerAdvice 和 @RestControllerAdvice 是作用在类上的注解,用于SpringMVC的全局异常处理。通常情况下我们会使用@ControllerAdvice 或 @RestControllerAdvice 来定义我们都全局处理异常类。
package com.yyoo.springmvc.config;
import com.yyoo.springmvc.bean.MyResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public MyResponse exceptionHandler(Exception e){
// 注:这里的e.getMessage可能是大量的异常信息,实际情况下请勿直接使用
// 为了方便异常排查,此处一般我们还得打印日志或者进行日志的处理
return MyResponse.error(e.getMessage());
}
}
@RestControllerAdvice 注解的Bean中 @ExceptionHandler 的使用方法跟上面描述一样。意味着我们都全局异常处理也可以有多个处理方法来处理不同类型的异常。我们示例中是直接处理的顶层异常类,此处理方式还是有些问题的,特别是我们直接返回的e.getMessage。那么我们直接返回汉字"出现异常"可以吗?当然可以,但是这意味着我们的所有的异常最终的提示信息都一样了。
建议的处理方式为:
- 自定义一个异常类(如:MyException - 建议为RuntimeException,这样会少去很多try … catch)
- 在Controller 或 Service 中所有我们可以判断的业务类异常都通过该异常抛出,并对应指定异常信息,方便前端提示。
- 对Exception异常进行处理,现在进入Exception异常处理的异常通常都是些代码错误或者bug导致,直接提示“服务端异常”即可。
@ControllerAdvice 和 @ExceptionHandler
如果我们同时配置了@ControllerAdvice 和 @ExceptionHandler,则Spring MVC会优先匹配 @ExceptionHandler 的方法。
上一篇:Spring MVC 拦截器及其源码解析
下一篇:Spring MVC 异常处理源码解析