zoukankan      html  css  js  c++  java
  • 错误处理和定制错误页面

    配置原理:

    可以参照ErrorMvcAutoConfiguration:错误处理的自动配置

    给容器添加了如下组件:

    DefaultErrorAttributes

       @Bean
        @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
        public DefaultErrorAttributes errorAttributes() {
            return new DefaultErrorAttributes();
        }

    BasicErrorController  :  处理默认/error请求

    @Controller
    @RequestMapping("${server.error.path:${error.path:/error}}")
    public class BasicErrorController extends AbstractErrorController{
      
      @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)//产生html类型的数据,浏览器发送的请求来到这个方法处理
       public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
          HttpStatus status = getStatus(request);
          Map<String, Object> model = Collections
                    .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
          response.setStatus(status.value());
         //去哪个页面作为错误页面,包含页面地址和内容
          ModelAndView modelAndView = resolveErrorView(request, response, status, model);
          return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
       }
     
       @RequestMapping//产生json数据,其他客户端来这里
       public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
          HttpStatus status = getStatus(request);
          if (status == HttpStatus.NO_CONTENT) {
             return new ResponseEntity<>(status);
          }
          Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
          return new ResponseEntity<>(body, status);
       }

    }

    ErrorPageCustomizer

    @Value("${error.path:/error}")
    private String path="/error";//系统出现错误来到error请求进行处理,选择异常处理页面所在文件夹

    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) {
          //默认springboot可以找到一个页面? error/404 String errorViewName
    = "error/" + viewName;
          //模板引擎可以解析这个页面地址就用模板引擎 TemplateAvailabilityProvider provider
    = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext); if (provider != null) {
            //模板引擎可用的情况下返回errorViewName指定的视图地址
    return new ModelAndView(errorViewName, model); }
          //模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面
    return resolveResource(errorViewName, model); }
      private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
        for (String location : this.resourceProperties.getStaticLocations()) {
           try {
              Resource resource = this.applicationContext.getResource(location);
              resource = resource.createRelative(viewName + ".html");
              if (resource.exists()) {
            return new ModelAndView(new HtmlResourceView(resource), model);
              }
           }catch (Exception ex) {
         }
       }
       return null;
     }

    一旦发生错误,ErrorPageCustomizer就会发生作用,就会来到error下;就会被BasicErrorController 处理:

    1)响应页面:

      去哪个页面是由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;
        }

    2)指定错误页面:

      有模板引擎的情况下:根据error status状态码来到Templates文件下error文件夹中找对应的页面

      没有的话,在static静态资源文件夹找

     

    自定义异常处理: 

       @ResponseBody
        @org.springframework.web.bind.annotation.ExceptionHandler(NullUserException.class)
        public Map<String, String> handleNullUserException(Exception e) {
            Map<String, String> map = new HashMap<>();
            map.put("name", "miao");
            map.put("age", "23");
            return map;
        }
    没有自适应效果
    @ResponseBody
        @org.springframework.web.bind.annotation.ExceptionHandler(NullUserException.class)
        public String handleNullUserException(Exception e, HttpServletRequest request) {
            // 一定要有自己的错误状态码
            request.setAttribute("javax.servlet.error.status_code", 400);
            Map<String, String> map = new HashMap<>();
            map.put("name", "miao");
            map.put("age", "23");
            return "forward:/error";
        }
    有自适应效果
    定制自己的异常数据:
    出现错误会后,会来到error,会被 BasicErrorControllrt 处理,响应出去的数据是由getErrorAttributes得到的
    1,我们可以编写一个ErrorController的实现类,或者AbstractErrorController的子类,放在容器中

    //@Component
    public class MyErrorAttributes extends DefaultErrorAttributes {
     @Override
     public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
      Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
      if ((Integer) map.get("status") == 500) {
       map.put("message", "服务器内部错误!");
      }
      return map;
     }
    }
    //定义好的 ErrorAttributes 一定要注册成一个 Bean ,这样,Spring Boot 就不会使用默认的 DefaultErrorAttributes 了
    自定义异常视图解析
    @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) { return new ModelAndView("/aaa/123", model); } }
    实际上,开发者也可以在这里定义异常数据(直接在 resolveErrorView 方法重新定义一个 model ,将参数中的model 数据拷贝过去并修改,注意参数中的 model 类型为 UnmodifiableMap,即不可以直接修改),而不需要自定义MyErrorAttribute
  • 相关阅读:
    学习英文之社区,博客及源码 转载
    Windows 的 80 端口被 System 进程占用解决方案
    MySQL 报错:Translating SQLException with SQL state '42000', error code '1064', message
    程序员如何写工作日志?
    log4j 配置文件参数说明
    Java 后端彻底解决跨域问题(CORS)
    常用正则表达式语法
    使用 windows 批处理指令(BAT文件)进行压缩文件(zip)解压操作
    使用 windows 批处理指令(BAT文件)进行文件删除、复制操作
    idea 关于高亮显示与选中字符串相同的内容踩过的坑
  • 原文地址:https://www.cnblogs.com/QianYue111/p/13761911.html
Copyright © 2011-2022 走看看