zoukankan      html  css  js  c++  java
  • spring boot 尚桂谷学习笔记06 异常处理 ---Web

    ------错误处理机制------

      默认效果

        1 返回一个默认的错误页面

      浏览器发送请求的请求头:优先接收 text/html 数据

       客户端则默认响应json数据 : accept 没有说明返回什么数据 默认返回json

      原理:参照 ErrorMvcAutoConfiguration 错误的自动配置

        1 DefaultErrorAttributes

      // 帮助我们共享页面信息
      public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map<String, Object> errorAttributes = new LinkedHashMap(); errorAttributes.put("timestamp", new Date()); this.addStatus(errorAttributes, webRequest); this.addErrorDetails(errorAttributes, webRequest, includeStackTrace); this.addPath(errorAttributes, webRequest); return errorAttributes; }

        2 BasicErrorController

    @Controller
    @RequestMapping({"${server.error.path:${error.path:/error}}"}) // 都是响应 /error请求
    public class BasicErrorController extends AbstractErrorController {
      
      @RequestMapping(
      produces = {"text/html"} // 产生html类型的数据
      )
      public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
       HttpStatus status = this.getStatus(request);
      Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
      response.setStatus(status.value());
        // 去哪个页面作为错误页面 包含页面地址和内容
      ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
      return modelAndView == null ? new ModelAndView("error", model) : modelAndView;
      }

      @RequestMapping
      @ResponseBody // 产生json数据
      public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
      Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
      HttpStatus status = this.getStatus(request);
       return new ResponseEntity(body, status);
      }

        3 ErrorPageCustomizer

    @Value("${error.path:/error}")
    private String path = "/error"; 系统出现错误 到 error请求 (web.xml 注册的错误规则)

        4 DefaultErrorViewResolver

      public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
            ModelAndView modelAndView = this.resolve(String.valueOf(status), model);
            if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
                modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
            }
    
            return modelAndView;
        }
    
        private ModelAndView resolve(String viewName, Map<String, Object> model) {
         // 默认可以找到一个页面 error/404 String errorViewName
    = "error/" + viewName;
         // 模板引擎可以解析这个页面地址就用模板引擎解析 // 模板引擎可以用的情况下返回得到errorViewName指定视图地址
         // 模板引擎不可用 就在静态资源文件夹下找 errorViewName 对应的页面
         TemplateAvailabilityProvider provider
    = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext); return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model); }

        步骤:

          一旦系统出现4xx或者5xx错误:ErrorPageCustomizer 生效(定制错误的响应规则) 就会来到/error 请求

          就会被 BasicErrorController 处理:

            1) 响应页面: 去哪个页面由 DefaultErrorViewResolver 决定

    protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
            Iterator var5 = this.errorViewResolvers.iterator();
         // 所有的ErrorViewResolver 得到 ModelAndView
            ModelAndView modelAndView;
            do {
                if (!var5.hasNext()) {
                    return null;
                }
    
                ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
                modelAndView = resolver.resolveErrorView(request, status, model);
            } while(modelAndView == null);
    
            return modelAndView;
        }

      2 如何定制错误响应

        1) 定制错误页面

          1) 有模板引擎的情况下error/ 状态码 ( error/404.html) 将错误页面命名为错误状态码.html 发生此状态码到此错误页面

            也可以使用 4xx.html或者5xx.html 来匹配 4开头的或者5开头的错误 如果有精确的会优先到精确的错误提示页面

            页面能获取的信息:

              timestamp:时间戳

              status:状态码

              error:错误提示

              exception:异常对象

              message:异常消息

              errors:JSR303 数据校验的错误信息

              

              

          2) 没有模板引擎,在静态资源文件夹下寻找 static文件夹下寻找

          3) 模板引擎静态资源都没有 就是默认来到springboot 默认的错误提示页面

        2) 定制json 错误数据

          1) 自定义异常处理&返回json数据

    //异常处理器
    @ControllerAdvice
    public class MyExceptionHandler {
    
       // 浏览器客户端返回都是json数据 @ResponseBody @ExceptionHandler(UserNotExistException.
    class) public Map<String , Object> handleException(Exception e) { Map<String , Object> map = new HashMap<String, Object>(); map.put("code", "user.notexist"); map.put("message", e.getMessage()); return map; } }
    // 没有自适应效果...

          2) 转发到/error 进行自适应响应 实现功能但是 map.put 信息无法接受

        @ResponseBody
        @ExceptionHandler(UserNotExistException.class)
        public String handleException(Exception e, HttpServletRequest request) {
            Map<String , Object> map = new HashMap<String, Object>();
            // 传入我们自己设置的状态码 4xx 5xx 否则不会进入到错误页面的解析流程
            request.setAttribute("javax.servlet.error.status_code", 400);
            map.put("code", "user.notexist");
            map.put("message", e.getMessage());
    
            // 转发到 /error页面
            return "forward:/error";
        }

          3) 将我们的定制数据携带出去

            出现错误以后 会来到 /error 请求 会被 ErrorBaseController 处理,响应出去的数据可以

            获取的数据时由 getErrorAttributes 得到的(是 AbstractErrorController规定的方法)

            ---1完全来编写一个 ErrorController【或者编写AbstractErrorController类子类】 的实现类放在容器中

            ---2页面上能用的数据 或者json 能用的返回数据 通过 errorAttributes.getErrorAttributes得到

              容器中DefaultErrorAttributes.getErrorAttributes 此方法定义返回数据可以自己写一个

    // 给容器加入自己定义的ErrorAttributes
    @Component
    public class MyErrorAttributes extends DefaultErrorAttributes{
    
    
        @Override
        public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
            Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
            map.put("company", "lixuchun");
            // scope
            // request 0
            // session 1
            Map<String , Object> ext = (Map<String , Object>)webRequest.getAttribute("ext", 0);
            map.put("ext", ext);
            return map;
        }
    }

              在MyExceptionHandler 中加入

        @ResponseBody
        @ExceptionHandler(UserNotExistException.class)
        public String handleException(Exception e, HttpServletRequest request) {
            Map<String , Object> map = new HashMap<String, Object>();
            // 传入我们自己设置的状态码 4xx 5xx 否则不会进入到错误页面的解析流程
            request.setAttribute("javax.servlet.error.status_code", 400);
            map.put("code", "user.notexist");
            map.put("message", e.getMessage());
            request.setAttribute("ext", map);
            // 转发到 /error页面
            return "forward:/error";
        }

              访问结果:

              

  • 相关阅读:
    岳麓山岳麓书院
    花洲书院
    《诫子书》诸葛亮
    AI ML DL
    台湾大学林轩田机器学习基石
    LeNet
    VGGNet
    AlexNet 2012
    AS 中 Plugin for Gradle 和 Gradle 之间的版本对应关系
    AndroidStudio、gradle、buildToolsVersion关系
  • 原文地址:https://www.cnblogs.com/lixuchun/p/8997943.html
Copyright © 2011-2022 走看看