发布时间:2023-12-05 15:00
源码地址
我们都无需自定义配置)
The auto-configuration adds the following features on top of Spring’s defaults:
Inclusion of ContentNegotiatingViewResolver
and BeanNameViewResolver
beans.
内容协商视图解析器和BeanName视图解析器
Support for serving static resources, including support for WebJars (covered later in this document)).
静态资源(包括webjars)
Automatic registration of Converter
, GenericConverter
, and Formatter
beans.
自动注册 Converter,GenericConverter,Formatter
Support for HttpMessageConverters
(covered later in this document).
支持 HttpMessageConverters
(后来我们配合内容协商理解原理)
Automatic registration of MessageCodesResolver
(covered later in this document).
自动注册 MessageCodesResolver
(国际化用)
Static index.html
support.
静态index.html 页支持
Custom Favicon
support (covered later in this document).
自定义 Favicon
Automatic use of a ConfigurableWebBindingInitializer
bean (covered later in this document).
自动使用 ConfigurableWebBindingInitializer
,(DataBinder负责将请求数据绑定到JavaBean上)
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own
@Configuration
class of typeWebMvcConfigurer
but without@EnableWebMvc
.不用@EnableWebMvc注解。使用
**@Configuration**
+**WebMvcConfigurer**
自定义规则If you want to provide custom instances of
RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
, orExceptionHandlerExceptionResolver
, and still keep the Spring Boot MVC customizations, you can declare a bean of typeWebMvcRegistrations
and use it to provide custom instances of those components.声明
**WebMvcRegistrations**
改变默认底层组件If you want to take complete control of Spring MVC, you can add your own
@Configuration
annotated with@EnableWebMvc
, or alternatively add your own@Configuration
-annotatedDelegatingWebMvcConfiguration
as described in the Javadoc of@EnableWebMvc
.使用
**@EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration 全面接管SpringMVC**
4.2.1)静态资源访问
4.2.1.1)静态资源目录
只要静态资源放在类路径下: called /static
(or /public
or /resources
or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
示例:工程中新建相应的文件夹,目录如下图
浏览器访问:
http://localhost:8080/metainf.jpg,图片如下:
http://localhost:8080/public.gif,图片如下:
http://localhost:8080/resources.jpg,图片如下:
http://localhost:8080/public.gifhttp://localhost:8080/static.png,图片如下:
原理: 静态映射/**,拦截所以请求;请求进来,先去找Controller看能不能处理;不能处理的所有请求又都交给静态资源处理器;静态资源也找不到则响应404页面
新建 HelloController.java,代码如下:
@RestController
public class HelloController {
@RequestMapping(\"/metainf.jpg\")
public String hello(){
return \"aaaa\";
}
}
浏览器访问:http://localhost:8080/metainf.jpg,图片如下:
改变默认的静态资源路径
4.2.2)静态资源访问前缀
默认无前缀,application.yaml,代码如下:
spring:
mvc:
static-path-pattern: /res/**
当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
浏览器访问:http://localhost:8080/resources.jpg,页面报错,访问:http://localhost:8080/res/resources.jpg,页面可以正常访问,如下图:
4.2.2.1)改变默认的静态资源路径
修改配置文件application.yaml,代码如下:
spring:
mvc:
# 静态资源访问默认无前缀
static-path-pattern: /res/**
resources:
# 改变默认的静态资源路径
static-locations: [classpath:/abc/]
浏览器访问:http://localhost:8080/resources.jpg,页面报错,访问:http://localhost:8080/res/abc.jpg,页面可以正常访问,如下图:
4.2.3)欢迎页支持
静态资源路径下 index.html
可以配置静态资源路径
但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
清空配置文件application.yaml,不使用额外配置【配置访问前缀会导致welcome page功能失效】,在resource目录下新建首页index.html,代码如下:
Title
SpringBoot,欢迎您
浏览器访问默认地址:http://localhost:8080/,页面如下图:
4.2.4)自定义 Favicon
自定义网页图标,favicon.ico 放在静态资源目录下即可,放到static目录下,浏览器访问默认地址:http://localhost:8080/,页面如下图:【配置访问前缀会导致自定义 Favicon功能失效】
4.2.5)静态资源配置原理
SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
SpringMVC功能的自动配置类 WebMvcAutoConfiguration,通过它实现资源配置,源码如下:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = \"\";
public static final String DEFAULT_SUFFIX = \"\";
private static final String[] SERVLET_LOCATIONS = new String[]{\"/\"};
public WebMvcAutoConfiguration() {
}
...
}
4.2.5.1)配置类只有一个有参构造器
给容器中配置内容:WebMvcAutoConfigurationAdapter方法,配置文件的相关属性和xxx进行了绑定。WebMvcProperties==spring.mvc、ResourceProperties==spring.resources,源码如下:
@ConfigurationProperties(
prefix = \"spring.mvc\"
)
public class WebMvcProperties {
private org.springframework.validation.DefaultMessageCodesResolver.Format messageCodesResolverFormat;
...
}
——————————————————————————————————————————————————————————————————
@ConfigurationProperties(
prefix = \"spring.resources\",
ignoreUnknownFields = false
)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{\"classpath:/META-INF/resources/\", \"classpath:/resources/\", \"classpath:/static/\", \"classpath:/public/\"};
private String[] staticLocations;
private boolean addMappings;
private final ResourceProperties.Chain chain;
private final ResourceProperties.Cache cache;
...
}
有参构造器所有参数的值都会从容器中确定:
ResourceProperties resourceProperties:获取和spring.resources绑定的所有的值的对象
WebMvcProperties mvcProperties :获取和spring.mvc绑定的所有的值的对象
ListableBeanFactory beanFactory :Spring的beanFactory
HttpMessageConverters: 找到所有的HttpMessageConverters
ResourceHandlerRegistrationCustomizer :找到资源处理器的自定义器
ServletRegistrationBean : 给应用注册Servlet、Filter....
WebMvcAutoConfigurationAdapter方法,源码如下:
@Configuration(
proxyBeanMethods = false
)
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final ResourceProperties resourceProperties;
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final ObjectProvider messageConvertersProvider;
private final ObjectProvider dispatcherServletPath;
private final ObjectProvider> servletRegistrations;
final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider messageConvertersProvider, ObjectProvider resourceHandlerRegistrationCustomizerProvider, ObjectProvider dispatcherServletPath, ObjectProvider> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}
...
}
在配置文件application.yaml中可以设置禁用静态资源,代码如下:
spring:
mvc:
static-path-pattern: /res/**
resources:
# 禁用所有静态资源规则
add-mappings: false
4.2.5.2)欢迎页的处理规则
HandlerMapping:处理器映射。保存了每一个Handler能处理哪些请求。
WelcomePageHandlerMapping,源码如下
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
ApplicationContext applicationContext, Optional welcomePage, String staticPathPattern) {
if (welcomePage.isPresent() && \"/**\".equals(staticPathPattern)) {
//要用欢迎页功能,必须是/**
logger.info(\"Adding welcome page: \" + welcomePage.get());
setRootViewName(\"forward:index.html\");
}
else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
// 调用Controller /index
logger.info(\"Adding welcome page template: index\");
setRootViewName(\"index\");
}
}