SpringBoot与web开发(五) ---- SpringBoot 错误处理机制

本文介绍了SpringBoot的错误处理机制,包括默认的错误页面和JSON数据返回。详细讲解了原理,涉及ErrorMvcAutoConfiguration及关键组件。并阐述了如何自定义错误页面,通过模板引擎或静态目录实现。此外,还讨论了自定义JSON数据的方法,通过编写自定义ErrorAttributes实现类来处理异常并传递数据。
摘要由CSDN通过智能技术生成

SpringBoot 错误处理

SpringBoot 默认错误机制,返回一个错误页面和 json数据

  • 浏览器

在这里插入图片描述

在这里插入图片描述

  • 其它客户端

在这里插入图片描述

在这里插入图片描述

1. 原理

源码 ErrorMvcAutoConfiguration

其中有几个重要的组件:

  • DefaultErrorAttributes : 共享信息

    • timestamp 时间
    • status 状态码
    • error 错误提示
    • exception 异常对象
    • message 异常信息
    • errors JSR303 数据校验的信息
  • DefaultErrorViewResolver

    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
       ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
       if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
          modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
       }
       return modelAndView;
    }
    
    private ModelAndView resolve(String viewName, Map<String, Object> model) {
       String errorViewName = "error/" + viewName;
      //使用模板引擎
       TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
             this.applicationContext);
       if (provider != null) {
          return new ModelAndView(errorViewName, model);
       }
       //没有模板引擎 自动在静态资源下面去找
       return resolveResource(errorViewName, model);
    }	
    
  • ErrorPageCustomizer : 自定义

  • BasicErrorController : 处理 /error 请求

    @Controller
    @RequestMapping("${server.error.path:${error.path:/error}}")
    public class BasicErrorController extends AbstractErrorController {
        //html  浏览器
      	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
    		HttpStatus status = getStatus(request);
    		Map<String, Object> model = Collections
    				.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
    		response.setStatus(status.value());
    		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
    		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
    	}
        //json  其他客户端
    	@RequestMapping
    	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
    		Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
    		HttpStatus status = getStatus(request);
    		return new ResponseEntity<>(body, status);
    	}
    

2. 自定义

  • 自定义页面

    1. 有模板引擎,将404页面放在templates/error下面,(4xx)都可以找到 , 同理5xx也是可以的(首先是精确匹配)。
    2. 没有模板引擎,static 目录下创建error目录以及错误页面。
  • 自定义 JSON 数据

    • 以下测试的controller

          /**
           * 测试
           * @param user 测试用户名:aa
           * @return Exception or String
           */
          @RequestMapping("/hello")
          @ResponseBody
          public String hello(@RequestParam("user") String user) {
              if (user.equals("aa")) {
                  throw new UserNotException();
              }
              return "hello";
          }
      
      
    1. 统一显示json

      /**
       * @program: spring-boot-restful-crud
       * @description: 异常处理器
       * @author: YuanChangYue
       * @create: 2019-08-19 12:53
       */
      @ControllerAdvice
      public class MyExceptionHandler {
      
          /**
           * 处理UserNotException
           * 同意返回的是json数据 而不是分开显示为页面或者json
           * @return 处理信息
           */
          @ResponseBody
          @ExceptionHandler(UserNotException.class)
          public Map<String, Object> handlerException(Exception e) {
              Map<String, Object> map = new HashMap<>();
              map.put("code", "user not exist");
              map.put("message", e.getMessage());
              return map;
          }
      }
      
      /**
       * @program: spring-boot-restful-crud
       * @description: 用户不存在异常类
       * @author: YuanChangYue
       * @create: 2019-08-19 12:44
       */
      public class UserNotException extends RuntimeException {
          public UserNotException() {
              super("用户不存在");
          }
      }
      
      

在这里插入图片描述

在这里插入图片描述

  1. 页面和json分开 (通过转发到error)

    /**
     * @program: spring-boot-restful-crud
     * @description: 异常处理器
     * @author: YuanChangYue
     * @create: 2019-08-19 12:53
     */
    @ControllerAdvice
    public class MyExceptionHandler {
    
    //    /**
    //     * 处理UserNotException
    //     *
    //     * @return 处理信息
    //     */
    //    @ResponseBody
    //    @ExceptionHandler(UserNotException.class)
    //    public Map<String, Object> handlerException(Exception e) {
    //        Map<String, Object> map = new HashMap<>();
    //        map.put("code", "user not exist");
    //        map.put("message", e.getMessage());
    //        return map;
    //    }
    
       /**
         * 处理UserNotException
         * 注意:一定要设置错误代码
         * 根据:org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController#getStatus(javax.servlet.http.HttpServletRequest)
         * 关键点:request.setAttribute("javax.servlet.error.status_code", 500);
         *
         * @return 处理信息
         */
        @ResponseBody
        @ExceptionHandler(UserNotException.class)
        public String handlerException(Exception e, HttpServletRequest request) {
            Map<String, Object> map = new HashMap<>();
            //传入错误代码 4xx 5xx
            //Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
            request.setAttribute("javax.servlet.error.status_code", 500);
            map.put("code", "user not exist");
            map.put("message", e.getMessage());
            return "forward:/error";
        }
    }
    
    

在这里插入图片描述

在这里插入图片描述

  1. 将我们的定制数据传递出去

    当出现error时候,会来到/error请求中,这样就会被BasicErrorController类处理,查看这个类发现,相应的响应数据是由getErrorAttributes(在BasicErrorController继承的父类AbstractErrorControllerErrorController.class实现类))方法的得到的。再看ErrorMvcAutoConfiguration自动装载BasicErrorController

     @Bean
      //当没有ErrorController.class就会加载BasicErrorController到容器中
      @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
      public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
      return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);}
    
    • 这样就可以来编写一个BasicErrorController的实现类,放在容器中。
    • BasicErrorController最终会在ErrorAttributes中取出响应数据,所以 我们可以编写自己的ErrorAttribute.
    
      /**
       * @program: spring-boot-restful-crud
       * @description: 自定义ErrorAttributes
       * @author: YuanChangYue
       * @create: 2019-08-19 15:02
       */
      public class MyErrorAtrributes extends DefaultErrorAttributes {
      
          @Override
          public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
              Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
              errorAttributes.put("owner", "ChangYue");
              return errorAttributes;
          } 
      }
    
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190819164733763.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MjUyOTg3,size_16,color_FFFFFF,t_70)

​ 将自定义异常处理类需要传递的数据传递到自定义ErrorAttributes中,并添加进去

  /**
   * @program: spring-boot-restful-crud
   * @description: 自定义ErrorAttributes
   * @author: YuanChangYue
   * @create: 2019-08-19 15:02
   */
  @Component
  public class MyErrorAttributes extends DefaultErrorAttributes {
  
      /**
       * @return 页面和json获取的字段
       */
      @Override
      public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
          Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
          errorAttributes.put("owner", "ChangYue");
          //自定义需要的传递的数据
          Map<String, Object> exc = (Map<String, Object>) webRequest.getAttribute("exc", 0);
          errorAttributes.put("exc", exc);
          return errorAttributes;
      }
  
  }
  
  /**
   * @program: spring-boot-restful-crud
   * @description: 异常处理器
   * @author: YuanChangYue
   * @create: 2019-08-19 12:53
   */
  @ControllerAdvice
  public class MyExceptionHandler {
  
      /**
       * 处理UserNotException
       * 注意:一定要设置错误代码
       * 根据:org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController#getStatus(javax.servlet.http.HttpServletRequest)
       * 关键点:request.setAttribute("javax.servlet.error.status_code", 500);
       *
       * @return 处理信息
       */
      @ExceptionHandler(UserNotException.class)
      public String handlerException(Exception e, HttpServletRequest request) {
          Map<String, Object> map = new HashMap<>();
          //传入错误代码 4xx 5xx
          //Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
          request.setAttribute("javax.servlet.error.status_code", 500);
          map.put("code", "user not exist");
          map.put("message", e.getMessage());
          request.setAttribute("exc", map);
          return "forward:/error";
      }
  }

在这里插入图片描述

同时在错误页面中也可以显示出来

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值