Spring boot 错误页面

 

默认效果:
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数据;

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

时间: 2024-10-16 21:32:58

Spring boot 错误页面的相关文章

spring boot 错误页面配置

如果访问了错误的路径,或者后台报错 如果没有一个统一的页面! 或者说页面上展示一堆报错信息,既影响美观,又对用户不友好! 那么如何配置? 定义 ErrorPageConfig,配置错误状态与对应访问路径 @Component public class ErrorPageConfig implements ErrorPageRegistrar { private static final Logger logger = LoggerFactory.getLogger(ErrorPageConfig

Spring boot错误处理以及定制错误页面

如果是浏览器访问,返回错误页面 注意浏览器发送请求的请求头:  注意区别其他客户端哦比如 postman 如果是其他客户端,返回一个Json数据 原理可以参照ErrorMvcAutoConfiguration:错误处理的自动配置: 给容器中添加了以下组件1.DefaultErrorAttributes: 2.BasicErrorController:处理默认/error请求 3.ErrorPageCustomizer: 4.DefaultErrorViewResolver: 步骤:一但系统出现4

spring boot错误: 找不到或无法加载主类

一:当在eclipse启动spring boot项目时出现问题: springboot错误: 找不到或无法加载主类 解决办法: 1,通过cmd命令行,进入项目目录进行,mvn clean install 进行编译 项目install后,再到eclipse 上选中项目按F5刷新项目.再运行即可问题解决. 2,在eclipse 上选中项目 点击clean 清理项目再运行 问题解决. 3,如果运行还是出现无法加载主类, (a)排查项目代码是否有问题, (b)可以进入cmd,  cd 进入项目目录 执行

Spring boot 错误处理机制

请求方式时,若不存在 浏览器出现White label Error Page 错误页面 其他客户端出现响应一个JSON格式文本包含错误码等信息 浏览器发送请求的请求头: 客户端请求头 这样就能区分来自哪.. 原理:ErrorMvcAutoconfiguration 处理错误的自动配置 里面添加了以下组件 DefaultErrorAttributes 帮我们在页面共享信息: @Override public Map<String, Object> getErrorAttributes(Reque

spring Boot &nbsp; .ftl页面

jsp使用EL表达式  引入 c  标签 当使用模板时  ftl页面  需要循环遍历时 引入 <#list></#list>标签 <#list bookList as book> 指定循环对象对应的类 其他的都差不多 <#list bookList as book> <tr> <td>${book.id}</td> <td>${book.name}</td> <td>${book.aut

spring Boot &nbsp; .yml页面

server: port: 80   //配置端口  不要写8080端口 context-path: /     //配置根路径,不需要写项目名 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/db_book username: root password: 123456 jpa: hibernate: ddl-auto: update   //自动更新(没

spring boot 错误,求大神帮解决

Exception in thread "main" java.lang.IllegalStateException: Failed to read Class-Path attribute from manifest of jar file:/C:/Users/wo/.m2/repository/com/amazonaws/aws-java-sdk-core/1.11.125/aws-java-sdk-core-1.11.125.jar    at org.springframewo

分享spring boot controller统一日志代码

最近项目需要做一个controller层的aop,主要解决下面问题: 1.controller日志统一打印输出json格式,兼容json和velocity . 2.项目异常处理 3.异常邮件发送 4.页面访问统计 主要思路使用aop实现,controller参数统一使用@RequestParam接收. controller @RequestMapping(name = "添加个人信息", value ="/addInfo", method = RequestMeth

Spring Boot自定义错误页面,Whitelabel Error Page处理方式

我已经是Spring Framework框架的忠实粉丝.对于企业软件开发者来说它提供了对常见问题的通用解决方案,包括那些你在未来开发中没有意识到的问题.但是,它构建的J2EE项目变得比较臃肿,需要被一种新的解决方案替代. 我最大的抱怨就是最开始使用spring Framework构建项目十分缓慢和复杂,比如构建一个包含JPA的MVC应用.为改变这种情况,Spring Boot应运而生了. Spring Boot以一种新的微服务的方式来替代以Spring Framework构建项目的传统方式,我已