码迷,mamicode.com
首页 > 编程语言 > 详细

Spring boot 错误页面

时间:2018-11-24 14:31:50      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:mapping   源码解析   type   exception   conf   ext.get   xtend   message   nal   

 

默认效果:
1)、浏览器,返回一个默认的错误页面

  1.1 请求头

技术分享图片

  1.2返回结果

 技术分享图片

 

2)、如果是其他客户端,默认响应一个json数据

  2.1请求头

 技术分享图片

  2.2返回结果

 技术分享图片

 

步骤:
  1)系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);

  2) 根据相应规则来到/error请求;被BasicErrorController处理;

  3)响应页面;被Controller处理后去哪个页面是由DefaultErrorViewResolver解析得到的;

 

源码解析

public class ErrorMvcAutoConfiguration {
   // 系统出现错误以后来到error请求进行处理;(相当于web.xml注册错误页面规则) @Bean
public ErrorPageCustomizer errorPageCustomizer() { return new ErrorPageCustomizer(this.serverProperties, this.dispatcherServletPath); } /** * {@link WebServerFactoryCustomizer} that configures the server‘s error pages. */ private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered { private final ServerProperties properties; private final DispatcherServletPath dispatcherServletPath; protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) { this.properties = properties; this.dispatcherServletPath = dispatcherServletPath; } @Override public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath .getRelativePath(this.properties.getError().getPath())); errorPageRegistry.addErrorPages(errorPage); } @Override public int getOrder() { return 0; } } } public class ErrorProperties { /** * Path of the error controller. */ @Value("${error.path:/error}") private String path = "/error"; }

 

 

public class ErrorMvcAutoConfiguration {
   // 系统出现错误以后来到error请求进行处理;(相当于web.xml注册错误页面规则) 
    @Bean
    public ErrorPageCustomizer errorPageCustomizer() {
        return new ErrorPageCustomizer(this.serverProperties, this.dispatcherServletPath);
    }
    
    /**
     * {@link WebServerFactoryCustomizer} that configures the server‘s error pages.
     */
    private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {

        private final ServerProperties properties;

        private final DispatcherServletPath dispatcherServletPath;

        protected ErrorPageCustomizer(ServerProperties properties,
                DispatcherServletPath dispatcherServletPath) {
            this.properties = properties;
            this.dispatcherServletPath = dispatcherServletPath;
        }

        @Override
        public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
            ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath
                    .getRelativePath(this.properties.getError().getPath()));
            errorPageRegistry.addErrorPages(errorPage);
        }

        @Override
        public int getOrder() {
            return 0;
        }

    }
    
    @Configuration
    @ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)
    @Conditional(ErrorTemplateMissingCondition.class)
    protected static class WhitelabelErrorViewConfiguration {
        //默认的SpringBoot错误页面
        private final SpelView defaultErrorView = new SpelView(
                "<html><body><h1>Whitelabel Error Page</h1>"
                        + "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"
                        + "<div id=‘created‘>${timestamp}</div>"
                        + "<div>There was an unexpected error (type=${error}, status=${status}).</div>"
                        + "<div>${message}</div></body></html>");

        @Bean(name = "error")
        @ConditionalOnMissingBean(name = "error")
        public View defaultErrorView() {
            return this.defaultErrorView;
        }

        // If the user adds @EnableWebMvc then the bean name view resolver from
        // WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.
        @Bean
        @ConditionalOnMissingBean
        public BeanNameViewResolver beanNameViewResolver() {
            BeanNameViewResolver resolver = new BeanNameViewResolver();
            resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
            return resolver;
        }

    }
}

public class ErrorProperties {
    /**
     * Path of the error controller.
     */
    @Value("${error.path:/error}")
    private String path = "/error";
    
}
    

 

 

public class ErrorMvcAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
        return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
                this.errorViewResolvers);
    }

}


public abstract class AbstractErrorController implements ErrorController {

    private final ErrorAttributes errorAttributes;

    private final List<ErrorViewResolver> errorViewResolvers;

    public AbstractErrorController(ErrorAttributes errorAttributes) {
        this(errorAttributes, null);
    }
    
    //解析错误页面
    protected ModelAndView resolveErrorView(HttpServletRequest request,
            HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
        for (ErrorViewResolver resolver : this.errorViewResolvers) {
            ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
            if (modelAndView != null) {
                return modelAndView;
            }
        }
        return null;
    }
    
}

/**取出配置項:server.error.path中的值。如果沒有,則取error.path的值,如果還沒有,則默認為/error路徑*/
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
    

    @RequestMapping(produces = "text/html")//产生html类型的数据;浏览器发送的请求来到这个方法处理
    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);
//如果为空,返回error视图(在ErrorMvcConfiguration中配置的@Bean)
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); } //产生json数据,其他客户端来到这个方法处理; @RequestMapping @ResponseBody 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); } } public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered { private static final Map<Series, String> SERIES_VIEWS;

   private final ResourceProperties resourceProperties;
static { Map<Series, String> views = new EnumMap<>(Series.class); views.put(Series.CLIENT_ERROR, "4xx"); views.put(Series.SERVER_ERROR, "5xx"); SERIES_VIEWS = Collections.unmodifiableMap(views); } @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { ModelAndView modelAndView = resolve(String.valueOf(status), 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); }
     //模板引擎不可用
return resolveResource(errorViewName, model); }   // private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
//从静态资源文件夹下解析对应的页面 error/404.html
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; } }

 

 静态资源文件夹路径

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/" };

    /**
     * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
     * /resources/, /static/, /public/].
     */
    private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;

}

 

2)、如果定制错误响应

1、如何定制错误的页面
  1)、有模板引擎的情况下;error/状态码; 【将错误页面命名为 错误状态码.html 放在模板引擎文件夹里面的error文件夹下】,发生此状态码的错误就会来到 对应的页面;
      我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html);
      页面能获取的信息:
      timestamp:时间戳
      status:状态码
      error:错误提示
      exception:异常对象
      message:异常消息
      errors:JSR303数据校验的错误都在这里
  2)、没有模板引擎(模板引擎找不到这个错误页面),静态资源文件夹下找
  3)、以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面

2、如何定制错误的json数据;
  1)、自定义异常处理&返回定制json数据;

 

Spring boot 错误页面

标签:mapping   源码解析   type   exception   conf   ext.get   xtend   message   nal   

原文地址:https://www.cnblogs.com/guchunchao/p/10011332.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!