SpringBoot 异常处理详解

2022-10-24 08:26:35

总体来讲,SpringBoot 处理异常有下面几个。

一、利用 SpringBoot 的默认配置,我们自定义覆盖默认的错误页面:

  1、SpringBoot 默认错误处理机制

         SpringBoot 为我们做了一堆的默认配置工作整合,也包含异常处理的配置

         如果没有进行处理出现错误,如果是浏览器访问,它会返回一张 html 的错误页面,如果是其他客户端访问出现异常,它会直接返回json格式的异常数据。

1)在ErrorMvcAutoConfiguration中,重点看一下这三个SpringBoot 错误处理机制源码跟踪

    (1)查看 BasicErrorController 类,默认处理/error请求的。

    其中有两个方法处理错误请求:

    返回的异常信息可以在 DefaultErrorAttributes 类中查询

(2)DefaultErrorAttributes 封装了默认错误数据

(3)DefaultErrorViewResolver 默认错误视图解析器

结论:

1. 有模板引擎的情况下

error/状态码 -- 将错误页面命名为 错误状态码.html 放在模板引擎文件夹里面的error文件夹下(/templates/error/xxx.html),发生此状态码的错误就会来到 对应的页面。使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确状态码优先。

2. 没有模板引擎(模板引擎找不到这个错误页面)

SpringBoot会去静态资源目录(static/error/状态码.html)下面找错误代码命名的页面。

3. 完整的错误页面查找方式应该是:比如发生了500错误

查找500.html 页面(模板引擎)–>查找静态 500.html –> 查找 5xx.html(模板引擎)–>查找静态 5xx.html。

以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面。

2、自定义错误页面覆盖默认的:4xx 客户端错误,5xx 服务端错误

3、自定义异常数据

默认情况下异常数据会展示出5条数据(具体在DefaultErrorAttributes 类的 getErrorAttributes 方法中定义的)。

如果开发者没有自己提供一个 ErrorAttributes 的实例的话,那么 Spring Boot 将自动提供一个ErrorAttributes 的实例,也就是 DefaultErrorAttributes 。开发者自定义 ErrorAttributes 有两种方式 :

  • 直接实现 ErrorAttributes 接口(不推荐)
  • 继承 DefaultErrorAttributes类(推荐),因为 DefaultErrorAttributes 中对异常数据的处理已经完成,开发者可以直接使用。

这里创建一个类继承DefaultErrorAttributes类自定义异常数据:

@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
        Map<String, Object> map = super.getErrorAttributes(webRequest, options);
        if((Integer) map.get("status") == 500){
            map.put("myMessage", "500-服务器内部错误!");
        }
        return map;
    }
}

4、自定义异常视图

异常视图默认就是前面所说的静态或者动态页面(在BasicErrorController 类的 errorHtml 方法中处理的,如果是 ajax 请求,则是在error方法处理)。

这也是可以自定义的:开发者提供了自己的ErrorViewResolver 实例,重新定义一个 ModelAndView 即可。

注意:参数中的 model 类型为 UnmodifiableMap,即不可以直接修改,它里面是封装的错误数据。在这里自定义一个map,遍历model数据拷贝过去并修改到map中,也是可以实现数据自定义的。

@Component
public class MyErrorViewResolver extends DefaultErrorViewResolver {
    public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
        super(applicationContext, resourceProperties);
    }

    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        ModelAndView modelAndView = new ModelAndView("/diy/1234", model);
        return modelAndView;
    }
}

二、某个异常单独处理 @ExceptionHandler注解

某个异常处理主要用到@ExceptionHandler 注解,此注解加到类的方法上,当此注解里定义的异常抛出时,该方法会被执行。

    如果 @ExceptionHandler 所在的类是 @Controller 注解,则此方法只作用在此controller类中。

如果 @ExceptionHandler 所在的类是 @ControllerAdvice 注解,则此方法会作用在全局。

1、某个controller处理: @Controller + @ExceptionHandler

@Controller
public class UserController {
    @GetMapping("/userList")
    public  String userList(Model model){
        int i = 1/0;
        List<User> userList = userService.getAllUser();
        model.addAttribute("userList", userList);
        return "userList";
    }

    //局部异常处理 - 页面
    @ExceptionHandler(value = {java.lang.ArithmeticException.class})
    public ModelAndView exHandler(Exception ex){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("err", ex.getMessage()); //更加自由显示处理异常
        modelAndView.setViewName("/myError");
        return modelAndView;
    }

  /*  //局部异常处理 - JSON格式
    @ExceptionHandler(value = {java.lang.Exception.class})
    @ResponseBody
    public String exHandler(Exception e){
        // 判断发生异常的类型是除0异常则做出响应
        if(e instanceof ArithmeticException){
            return "发生了除0异常";
        }
        // 未知的异常做出响应
        return "发生了未知异常";
    }*/

}

2、全局异常处理:@ControllerAdvice + @ExceptionHandler

    在spring 3.2中,新增了@ControllerAdvice注解,可以用于定义 @ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。

    简单的说,进入Controller层的错误才会由 @ControllerAdvice 处理,拦截器抛出的错误以及访问错误地址的情况 @ControllerAdvice 处理不了,由SpringBoot默认的异常处理机制处理。

@ControllerAdvice
public class DoAllErrotController {
    //全局异常处理 - 视图
    @ExceptionHandler(value = {java.lang.ArithmeticException.class})
    public ModelAndView exHandler(Exception ex){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("err", ex.getMessage()); //更加自由显示处理异常
        modelAndView.setViewName("/myError");
        return modelAndView;
    }

    //全局异常处理 - JSON格式
   /*  
    @ExceptionHandler(value = {RuntimeException.class})
    @ResponseBody
    public Map<String, Object> errorJson(){        
        Map<String, Object> errorMap = new HashMap<>();
        errorMap.put("errorCode", "500");
        errorMap.put("errorMessage", "发送异常啦!");
        return errorMap;
    }
    */
}

 某个controller处理和全局异常处理同时处理时, 先某个,某个处理没有回再全局处理。

3、使用@ControllerAdvice定义全局数据

如果有个需求,想在所有的Controller类中获取某个或者多个全局的数据,可以使用@ControllerAdvice定义全局数据。

@ControllerAdvice
public class MyGlobalData {

    // 自定义kv。key - globalKey1,v - Map。 
    @ModelAttribute(value = "globalKey1")
    public Map<String, Object> globalData(){
        Map<String, Object> map = new HashMap<>();
        map.put("aaa","vvv1");
        map.put("bbb","vvv2");
        return map;
    }
}
@Controller
public class ErrorController {

    @GetMapping("/get")
    @ResponseBody
    public String get(Model model){
        Map<String, Object> map = model.asMap();
        map.forEach((k,v) -> {
            System.out.println(k);
            System.out.println(v);
        });
        return "success";
    }
}

三、全局异常处理:注入SimpleMappingExceptionResolver

      在@Configuration注解的配置类中,注入SimpleMappingExceptionResolver,bean配置来处理做全局异常处理,但是这种方法不能返回异常的具体信息。

@Configuration
public class MyErrorConfig {

    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.put("java.lang.NullPointerException","myError"); //参数:异常类型,视图名称
        properties.put("java.lang.ArithmeticException","myError");
        simpleMappingExceptionResolver.setExceptionMappings(properties); //设置异常与视图映射信息的,默认通过${exception} 获取,可修改
        simpleMappingExceptionResolver.setExceptionAttribute("err"); //
        return simpleMappingExceptionResolver;
    }
}

注入bean的配置和@ControllerAdvice方式同时使用时,优先是@ControllerAdvice方式处理。

之前SpringMVC 的配置:

四、自定义 HandlerExceptionResolver 类处理异常(不常用)

需 要 再 全 局 异 常 处 理 类 中 实 现 HandlerExceptionResolver 接口,并添加@Configuration注解。

@Configuration
public class MyErrorConfig5  implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        if(e instanceof ArithmeticException){
            modelAndView.setViewName("myError");
        }
        if(e instanceof NullPointerException){
            modelAndView.setViewName("error");
        }
        modelAndView.addObject("err",e);
        return modelAndView;
    }
}

项目中根据情况,合理选择上面的处理方式。

 ends~

  • 作者:Charge8
  • 原文链接:https://blog.csdn.net/qq_42402854/article/details/91415966
    更新时间:2022-10-24 08:26:35