zoukankan      html  css  js  c++  java
  • Springboot 自定义异常处理

    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;
        }
    }
    

      

     

  • 相关阅读:
    GoF 23种设计模式概述
    设计模式总篇
    面向对象软件开发六大原则
    StarUML类图相关——关联、聚合、组合、泛化、依赖、实现
    Java8集合框架——ArrayList源码分析
    Q6:ZigZag Conversion
    Python基础学习-列表基本操作
    Python基础学习之字符串(1)
    Python基础学习之序列(2)
    Python基础学习之序列(1)
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/14026931.html
Copyright © 2011-2022 走看看