Springboot 自定义异常处理需要使用到 @ControllerAdvice 和 @ExceptionHandler 这两个注解
@ControllerAdvice 注解是 Spring 3.2 提供的一个新注解,它是一个 Controller 增强器,可以对 Controller 中被 @RequestMapping 注解的方法加上一些我们自定义的逻辑处理,最常用的就是用作异常处理
@ExceptionHandler 注解的作用是用来指明异常的类型,即如果这里指定为 NullpointerException ,则数组越界异常就不会进到这个方法中来.该注解需要配合 @ControllerAdvice 注解一起使用,可以对异常进行统一的处理,规定返回的是 Json 格式或者是跳转到一个错误的页面
话不多说,Springboot 要实现自定义异常,这里会有下面几种方式,这里只讲两种,如果想要更多的方式,可以参考官方文档
1、全面接管 Springboot 异常处理,覆盖默认的异常处理机制
Springboot 的异常处理控制器是 BasicErrorController,如果容器中已经存在了一个 ErrorController 的实现类,那么该控制器就不会注入到容器中
@Bean
// 如果容器中没有 ErrorController 的实现类,那么判断条件才成立,才会将 basicErrorController 注入到容器中
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
this.errorViewResolvers);
}
从 springboot 的默认配置中就可以看到,如果我们自定义一个 ErrorController 实现类,那么 Springboot 默认的配置就会失效,我们可以完全的自定义 springboot 的异常处理
@ControllerAdvice(annotations = Controller.class)
public class MyExceptionAdvice implements ErrorController {
@ResponseBody
// 这里可以传入 Exception.class,也可以传入自定义的 MyException.class
@ExceptionHandler(Exception.class)
// 这里的参数有很多,根据自己的需求选择合适的参数,具体可以参考官方文档
public Map<String, Object> myErrorHandler(Exception e, HttpServletRequest request) {
// 返回 Json 格式
Map<String, Object> map = new HashMap<>();
if (e instanceof MyException) {
MyException me = (MyException) e;
map.put("errorCode", me.getCode());
map.put("errorMessage", me.getMessage());
}else if(e instanceof IndexOutOfBoundsException){
map.put("errorMessage",e.getMessage());
}
return map;
}
@Override
public String getErrorPath() {
return "hello errors";
}
}
这里也可以写两个方法,使用@ExceptionHandler(MyException)、@ExceptionHandler(IndexOutOfBoundsException) 来拦截对应的异常,并进行相关的逻辑处理.当然也可以如上面这种方式使用同一个方法进行统一处理.
自定义异常实现 RuntimeException
public class MyException extends RuntimeException {
private String code;
private String message;
public MyException(String code, String message) {
this.code = code;
this.message = message;
}
// 省略 get / set 方法
}
控制器
@Controller
public class SpringbootErrorController {
@RequestMapping("/error01")
public String error01() {
throw new MyException("404", "resource not found exception!!!");
}
@RequestMapping("/error02")
public String error02() {
throw new IndexOutOfBoundsException("数组下标越界异常...");
}
}
浏览器分别发送 localhost:8080/error01、localhost:8080/error02 ,结果如下
{"errorMessage":"resource not found exception!!!","errorCode":"404"}
{"errorMessage":"数组下标越界异常..."}
如果不需要返回json数据,而要渲染某个页面模板返回给浏览器,那么可以这么实现
@ControllerAdvice(annotations = Controller.class)
public class MyExceptionAdvice implements ErrorController {
@ResponseBody
@ExceptionHandler(Exception.class)
public ModelAndView myErrorHandler(Exception e, HttpServletRequest request) {
// 渲染到页面
ModelAndView mav = new ModelAndView();
if (e instanceof MyException) {
MyException me = (MyException) e;
mav.addObject("errorCode", me.getCode());
mav.addObject("errorMessage", me.getMessage());
}else if(e instanceof IndexOutOfBoundsException){
mav.addObject("errorMessage", e.getMessage());
}
mav.setViewName("error/4xx");
return mav;
}
@Override
public String getErrorPath() {
return "hello errors";
}
}
2、使用 Springboot 默认的控制器 BasicErrorController,该控制器中错误的数据信息来源是 DefaultErrorAttributes ,我们只需要编写一个类 MyDefaultErrorAttributes 继承 DefaultErrorAttributes ,这样容器中就只会存在MyDefaultErrorAttributes 这个 bean
@Bean
// 如果容器中已经存在了 ErrorAttributes 的实现类,那么 DefaultErrorAttributes 就不会再注入 IOC 容器了
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes();
}
具体实现如下:
// 自定义类注入容器中,这样 DefaultErrorAttributes 就不会再注入容器中了
@Component
public class MyDefaultErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
errorAttributes.put("name","xiaomaomao");
errorAttributes.put("age","22");
return errorAttributes;
}
}