1:页面呈现
常见的错误页面
这个空白页面主要包括 默认错误路径、时间戳、错误提示消息 和错误状态码
但如果我们使用其他的客户端(非浏览器),例如 Postman工具 发送 http://127.0.0.1:8080/noPage 请求时,默认响应客户端的是JSON数据,如下图所示
响应完整信息如上图
2:原理分析
出现上面的两种默认效果的原因是 SpringBoot容器为我们自动配置了 错误处理自动配置的 控制器 ErrorMvcAutoConfiguration
我们首先看看程序启动,springboot容器里的bean
以下是一个常见的springboot启动类改写的
package com.foxconn.sw.macaddress;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//事务管理
@EnableTransactionManagement
//会自动 装配指定包下面所有Mapper,省得在每个Mapper上面写@Mapper
@MapperScan("com.foxconn.sw.macaddress.dao")
@SpringBootApplication
public class MacaddressApplication {
public static void main(String[] args) {
SpringApplication.run(MacaddressApplication.class, args);
}
}
获取一下初始化的bean
package com.foxconn.sw.macaddress;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//事务管理
@EnableTransactionManagement
//会自动 装配指定包下面所有Mapper,省得在每个Mapper上面写@Mapper
@MapperScan("com.foxconn.sw.macaddress.dao")
@SpringBootApplication
public class MacaddressApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MacaddressApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
String beanDefinitionName = beanDefinitionNames[i];
System.err.println(beanDefinitionName);
}
}
}
这样我们就可以得到IOC容器初始化的beanName,以下是完整结果,其中就包含一些spring整合springmvc的如dispatcherServlet,文件上传,视图解析器mvcviewResolver等
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalPersistenceAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
macaddressApplication
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
druidConfig
myBatisConfig
springMvcConfiguer
applicationController
deliveryRecordController
loginController
macaddressController
userController
applicationService
deliveryRecordService
macaddressService
userServiceImpl
druidDataSource
druidServlet
filterRegistrationBean
configurationCustomizer
localeResolver
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
org.springframework.transaction.config.internalTransactionAdvisor
transactionAttributeSource
transactionInterceptor
org.springframework.transaction.config.internalTransactionalEventListenerFactory
org.springframework.aop.config.internalAutoProxyCreator
com.foxconn.sw.macaddress.MacaddressApplication#MapperScannerRegistrar#0
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
messageSourceProperties
messageSource
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
org.springframework.boot.context.internalConfigurationPropertiesBinderFactory
org.springframework.boot.context.internalConfigurationPropertiesBinder
org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
propertySourcesPlaceholderConfigurer
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration
websocketServletWebServerCustomizer
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
tomcatServletWebServerFactory
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
servletWebServerFactoryCustomizer
tomcatServletWebServerFactoryCustomizer
server-org.springframework.boot.autoconfigure.web.ServerProperties
webServerFactoryCustomizerBeanPostProcessor
errorPageRegistrarBeanPostProcessor
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletConfiguration
dispatcherServlet
spring.mvc-org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
spring.http-org.springframework.boot.autoconfigure.http.HttpProperties
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration
dispatcherServletRegistration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
taskExecutorBuilder
applicationTaskExecutor
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration
defaultValidator
methodValidationPostProcessor
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration
error
beanNameViewResolver
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$DefaultErrorViewResolverConfiguration
conventionErrorViewResolver
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
errorAttributes
basicErrorController
errorPageCustomizer
preserveErrorControllerTargetClassPostProcessor
spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration
requestMappingHandlerAdapter
requestMappingHandlerMapping
welcomePageHandlerMapping
mvcConversionService
mvcValidator
mvcContentNegotiationManager
mvcPathMatcher
mvcUrlPathHelper
viewControllerHandlerMapping
beanNameHandlerMapping
routerFunctionMapping
resourceHandlerMapping
mvcResourceUrlProvider
defaultServletHandlerMapping
handlerFunctionAdapter
mvcUriComponentsContributor
httpRequestHandlerAdapter
simpleControllerHandlerAdapter
handlerExceptionResolver
mvcViewResolver
mvcHandlerMappingIntrospector
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter
defaultViewResolver
viewResolver
requestContextFilter
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
hiddenHttpMethodFilter
formContentFilter
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration
hikariPoolDataSourceMetadataProvider
org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker
org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationConfiguration
dataSourceInitializerPostProcessor
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
sqlSessionFactory
sqlSessionTemplate
mybatis-org.mybatis.spring.boot.autoconfigure.MybatisProperties
com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration
pageHelperProperties
pagehelper-com.github.pagehelper.autoconfigure.PageHelperProperties
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
mbeanExporter
objectNamingStrategy
mbeanServer
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
springApplicationAdminRegistrar
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration$CglibAutoProxyConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration
transactionManager
jpaVendorAdapter
entityManagerFactoryBuilder
entityManagerFactory
spring.jpa.hibernate-org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties
spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
dataSourceInitializedPublisher
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration
persistenceExceptionTranslationPostProcessor
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
emBeanDefinitionRegistrarPostProcessor
jpaMappingContext
jpaContext
org.springframework.data.jpa.util.JpaMetamodelCacheCleanup
org.springframework.data.jpa.repository.support.JpaEvaluationContextExtension
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration
standardJacksonObjectMapperBuilderCustomizer
spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration
jacksonObjectMapperBuilder
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$ParameterNamesModuleConfiguration
parameterNamesModule
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration
jacksonObjectMapper
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
jsonComponentModule
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration
stringHttpMessageConverter
org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration
mappingJackson2HttpMessageConverter
org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
messageConverters
org.springframework.data.web.config.ProjectingArgumentResolverRegistrar
projectingArgumentResolverBeanPostProcessor
org.springframework.data.web.config.SpringDataWebConfiguration
pageableResolver
sortResolver
org.springframework.data.web.config.SpringDataJacksonConfiguration
jacksonGeoModule
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
pageableCustomizer
sortCustomizer
spring.data.web-org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration
h2Console
spring.h2.console-org.springframework.boot.autoconfigure.h2.H2ConsoleProperties
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateConfiguration
jdbcTemplate
org.springframework.boot.autoconfigure.jdbc.NamedParameterJdbcTemplateConfiguration
namedParameterJdbcTemplate
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration
spring.jdbc-org.springframework.boot.autoconfigure.jdbc.JdbcProperties
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
spring.security.oauth2.resourceserver-org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
taskSchedulerBuilder
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafJava8TimeDialect
java8TimeDialect
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafWebMvcConfiguration$ThymeleafViewResolverConfiguration
thymeleafViewResolver
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafWebMvcConfiguration
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration
templateEngine
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$DefaultTemplateResolverConfiguration
defaultTemplateResolver
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration
spring.thymeleaf-org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration$DataSourceTransactionManagerConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$TransactionTemplateConfiguration
transactionTemplate
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
platformTransactionManagerCustomizers
spring.transaction-org.springframework.boot.autoconfigure.transaction.TransactionProperties
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration
restTemplateBuilder
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration$TomcatWebServerFactoryCustomizerConfiguration
tomcatWebServerFactoryCustomizer
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
characterEncodingFilter
localeCharsetMappingsCustomizer
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
multipartConfigElement
multipartResolver
spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$RestartConfiguration
restartingClassPathChangedEventListener
classPathFileSystemWatcher
classPathRestartStrategy
fileSystemWatcherFactory
conditionEvaluationDeltaLoggingListener
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration
liveReloadServer
optionalLiveReloadServer
liveReloadServerEventListener
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration
spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties
applicationDao
deliveryRecordDao
macaddressDao
userDao
org.springframework.orm.jpa.SharedEntityManagerCreator#0
查找一下
回到开头的ErrorMvcAutoConfiguration
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.servlet.error;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.util.HtmlUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} to render errors via an MVC error
* controller.
*
* @author Dave Syer
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Brian Clozel
* @since 1.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
// Load before the main WebMvcAutoConfiguration so that the error View is available
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {
private final ServerProperties serverProperties;
public ErrorMvcAutoConfiguration(ServerProperties serverProperties) {
this.serverProperties = serverProperties;
}
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
ObjectProvider<ErrorViewResolver> errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
errorViewResolvers.orderedStream().collect(Collectors.toList()));
}
@Bean
public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
@Bean
public static PreserveErrorControllerTargetClassPostProcessor preserveErrorControllerTargetClassPostProcessor() {
return new PreserveErrorControllerTargetClassPostProcessor();
}
@Configuration(proxyBeanMethods = false)
static class DefaultErrorViewResolverConfiguration {
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
DefaultErrorViewResolverConfiguration(ApplicationContext applicationContext,
ResourceProperties resourceProperties) {
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
}
@Bean
@ConditionalOnBean(DispatcherServlet.class)
@ConditionalOnMissingBean(ErrorViewResolver.class)
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)
@Conditional(ErrorTemplateMissingCondition.class)
protected static class WhitelabelErrorViewConfiguration {
private final StaticView defaultErrorView = new StaticView();
@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;
}
}
/**
* {@link SpringBootCondition} that matches when no error template view is detected.
*/
private static class ErrorTemplateMissingCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage.forCondition("ErrorTemplate Missing");
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(context.getClassLoader());
TemplateAvailabilityProvider provider = providers.getProvider("error", context.getEnvironment(),
context.getClassLoader(), context.getResourceLoader());
if (provider != null) {
return ConditionOutcome.noMatch(message.foundExactly("template from " + provider));
}
return ConditionOutcome.match(message.didNotFind("error template view").atAll());
}
}
/**
* Simple {@link View} implementation that writes a default HTML error page.
*/
private static class StaticView implements View {
private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html", StandardCharsets.UTF_8);
private static final Log logger = LogFactory.getLog(StaticView.class);
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (response.isCommitted()) {
String message = getMessage(model);
logger.error(message);
return;
}
response.setContentType(TEXT_HTML_UTF8.toString());
StringBuilder builder = new StringBuilder();
Date timestamp = (Date) model.get("timestamp");
Object message = model.get("message");
Object trace = model.get("trace");
if (response.getContentType() == null) {
response.setContentType(getContentType());
}
builder.append("<html><body><h1>Whitelabel Error Page</h1>").append(
"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
.append("<div id='created'>").append(timestamp).append("</div>")
.append("<div>There was an unexpected error (type=").append(htmlEscape(model.get("error")))
.append(", status=").append(htmlEscape(model.get("status"))).append(").</div>");
if (message != null) {
builder.append("<div>").append(htmlEscape(message)).append("</div>");
}
if (trace != null) {
builder.append("<div style='white-space:pre-wrap;'>").append(htmlEscape(trace)).append("</div>");
}
builder.append("</body></html>");
response.getWriter().append(builder.toString());
}
private String htmlEscape(Object input) {
return (input != null) ? HtmlUtils.htmlEscape(input.toString()) : null;
}
private String getMessage(Map<String, ?> model) {
Object path = model.get("path");
String message = "Cannot render error page for request [" + path + "]";
if (model.get("message") != null) {
message += " and exception [" + model.get("message") + "]";
}
message += " as the response has already been committed.";
message += " As a result, the response may have the wrong status code.";
return message;
}
@Override
public String getContentType() {
return "text/html";
}
}
/**
* {@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;
}
}
/**
* {@link BeanFactoryPostProcessor} to ensure that the target class of ErrorController
* MVC beans are preserved when using AOP.
*/
static class PreserveErrorControllerTargetClassPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] errorControllerBeans = beanFactory.getBeanNamesForType(ErrorController.class, false, false);
for (String errorControllerBean : errorControllerBeans) {
try {
beanFactory.getBeanDefinition(errorControllerBean)
.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
}
catch (Throwable ex) {
// Ignore
}
}
}
}
}
render()就是图一出来的结果的原因。再来仔细分析下这个配置类 ErrorMvcAutoConfiguration
首先,我们ErrorMvcAutoConfiguration
为我们配置了这几个组件(@Bean)
- DefaultErrorAttributes
- BasicErrorController
- ErrorPageCustomizer
- DefaultErrorViewResolve
ErrorPageCustomizer
@Bean
public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
这个组件它会实例化出一个 ErrorPageCustomizer
对象,在ErrorPageCustomizer
对象中有一个重要的方法registerErrorPages
在ErrorMvcAutoConfiguration中有个静态内部类
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;
}
}
registerErrorPages方法会注册一个错误页面, 通过 getPath()
获取到路径,getPath
存在默认的值为"/error",如果在配置文件中配值了``server.error.path=/errors那就会从配置文件中取出
error.path`的值,没有就会获取默认配置文件的配置/error
ErrorPageCustomizer
组件的作用就是 当 用户请求一旦发生错误时,就会获得 path (错误页面的路径),然后将我们转发到 path 路径下。 并将该路径信息发给BasicErrorController
进行处理
basicErrorController就是默认的程序出错的controller
我们到springboot系统自动配置类中找到这个类找到其核心代码
@Override
public String getErrorPath() {
return this.errorProperties.getPath();
}
@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);
}
@RequestMapping
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, isIncludeStackTrace(request, MediaType.ALL));
return new ResponseEntity<>(body, status);
}
它是用来处理 配置文件下的 server.error.path
的请求,如果 server.error.path
未配置时,就会处理 配置文件下的 error.path
的请求,如果也没配置,就会处理/error
在这个控制器组件下面 存在着两个 @RequestMapping ,都是处理同一个请求路径的 方法。只是这两个方法的返回值不一样
但是竟然这两种方式都是用于处理一个请求的,为什么浏览器获取的数据和postMan获取的会不一样呢?
原因是浏览器发送的请求的请求头包含这串信息
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
也就是说 浏览器优先接收 text/html类型的数据,也就是第一个@RequestMapping那个
而postMan发送请求时 的请求头如下,它没有指明 希望接收的数据类型,所以服务端给它返回一个JSON类型的数据
那重点来了,返回页面时,又是如何实现的呢?
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE) // TEXT_HTML_VALUE = "text/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);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
当用户发送请求,发送错误时
- 首先,它会通过请求获取响应状态码和一些model数据,,然后返回一个
modelAndViews
, 通过第7行,我们可以知道modelAndViews
是通过调用resolveErrorView()
方法获得的。modelAndViews
包含了需要返回的地址,页面等信息 - 响应页面是调用了
resolveErrorView()
,如下
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;
}
第2行:遍历所有的 ErrorViewResolver
,调用resolver. resolveErrorView(request, status, model)
如果存在着 一个 modelAndView
就返回.
在之前,Spring Boot 为我们自动注册了一个 DefaultErrorViewResolver
到容器中,也就是说resolveErrorView()
方法将会由 DefaultErrorViewResolver
进行调用。
DefaultErrorViewResolver
按照该类的描述,这个类是全局的错误控制器,渲染出现的错误的属性。也可以@ExceptionHandler指定异常处理或者添加对应的服务器错误页面实现跳转
BasicErrorController中有一个属性ErrorProperties
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web;
import org.springframework.beans.factory.annotation.Value;
/**
* Configuration properties for web error handling.
*
* @author Michael Stummvoll
* @author Stephane Nicoll
* @author Vedran Pavic
* @since 1.3.0
*/
public class ErrorProperties {
/**
* Path of the error controller.
*/
@Value("${error.path:/error}")
private String path = "/error";
/**
* Include the "exception" attribute.
*/
private boolean includeException;
/**
* When to include a "stacktrace" attribute.
*/
private IncludeStacktrace includeStacktrace = IncludeStacktrace.NEVER;
private final Whitelabel whitelabel = new Whitelabel();
public String getPath() {
return this.path;
}
public void setPath(String path) {
this.path = path;
}
public boolean isIncludeException() {
return this.includeException;
}
public void setIncludeException(boolean includeException) {
this.includeException = includeException;
}
public IncludeStacktrace getIncludeStacktrace() {
return this.includeStacktrace;
}
public void setIncludeStacktrace(IncludeStacktrace includeStacktrace) {
this.includeStacktrace = includeStacktrace;
}
public Whitelabel getWhitelabel() {
return this.whitelabel;
}
/**
* Include Stacktrace attribute options.
*/
public enum IncludeStacktrace {
/**
* Never add stacktrace information.
*/
NEVER,
/**
* Always add stacktrace information.
*/
ALWAYS,
/**
* Add stacktrace information when the "trace" request parameter is "true".
*/
ON_TRACE_PARAM
}
public static class Whitelabel {
/**
* Whether to enable the default error page displayed in browsers in case of a
* server error.
*/
private boolean enabled = true;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}
定义了图一的错误信息,同时 BasicErrorController extends AbstractErrorController
@RequestMapping("${server.error.path:${error.path:/error}}")代表使用的配置文件的地址
定义了application.properties文件的默认属性,如果未定义,则使用的默认的上方的/error
再来看一下BasicErrorController ,其中有2个构造器,属性
errorAttributes:Provides access to error attributes which can be logged or presented to the user.
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.web.servlet.error;
import java.util.Map;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
/**
* Provides access to error attributes which can be logged or presented to the user.
*
* @author Phillip Webb
* @since 2.0.0
* @see DefaultErrorAttributes
*/
public interface ErrorAttributes {
/**
* Returns a {@link Map} of the error attributes. The map can be used as the model of
* an error page {@link ModelAndView}, or returned as a
* {@link ResponseBody @ResponseBody}.
* @param webRequest the source request
* @param includeStackTrace if stack trace elements should be included
* @return a map of error attributes
*/
Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace);
/**
* Return the underlying cause of the error or {@code null} if the error cannot be
* extracted.
* @param webRequest the source request
* @return the {@link Exception} that caused the error or {@code null}
*/
Throwable getError(WebRequest webRequest);
}
使用webRequest和堆栈信息,返回一个错误属性的有序map getErrorAttributes(WebRequest webRequest,boolean includeStackTrace)的实现方法
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, webRequest);
addErrorDetails(errorAttributes, webRequest, includeStackTrace);
addPath(errorAttributes, webRequest);
return errorAttributes;
}
errorProperties:
errorViewResolvers