springboot源码版本 2.3.12.RELEASE
springboot给webmvc提供的自动配置类是 WebMvcAutoConfiguration,这篇博文中涉及到的源码都是这个类中的。
主要提供的bean
使用 @Bean 提供了一些webmvc常用的bean
- ViewResolver 视图解析器
- RequestContextFilter 过滤器
- RequestMappingHandlerAdapter 处理器适配器
- RequestMappingHandlerMapping 处理器映射器
- WelcomePageHandlerMapping 首页设置
- Validator 参数校验
静态资源的路径映射
addResourceHandlers()
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(),
this.resourceProperties.getStaticLocations());
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
//映射webjar
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
//映射其它静态资源
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
//关注 this.resourceProperties.getStaticLocations()
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
主要做了2件事
- 映射webjar:将
classpath:/META-INF/resources/webjars/
下的资源路径映射为/webjars/**
- 映射其它静态资源:将指定位置下的静态资源路径映射为
/**
静态资源的位置
沿着 this.resourceProperties.getStaticLocations()
定位到 ResourceProperties,这个类是web资源的配置类
//对应yml中的 spring.resources 配置
@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/" };
//指定静态资源位置,默认值为上面的常量
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
//...
}
可以在yml中用 spring.resources.static-locations
指定静态资源位置,未指定时的静态资源默认位置为
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
即 classpath 下的4个文件夹。以上顺序也是静态资源的查找顺序,比如 static、public 下都有一个index.html,映射 /index.html 是映射到 static 中的 index.html,找到第一个即终止,查找首页同理。
springboot自带的resources文件夹本身就是classpath的一部分,当做classpath根目录看待。通常是在自带的resources文件下,新建 static 或public 文件夹来存放静态资源。
静态资源的访问路径
spring.resources.static-locations
指定的静态资源位置会被映射为 /**
即静态资源的根目录。
通常使用默认位置的 classpath:/static/
或 classpath:/public/
,在自带的resources文件夹下,新建 static 或 public 文件夹来存放静态资源。
示例:把 jquery.js 放在 static/js/ 下,映射路径直接取 static | public 后面的部分
<!--html引入路径-->
<script src="js/jquery.min.js"></script>
#浏览器可直接访问静态资源
http://localhost:8080/{context-path}/js/jquery.js
webjars的使用
webjars 顾名思义,以jar包形式引入web静态资源依赖,此处以引入jq为例
<dependency>
<!-- groupid是org.webjars,不能是其它的 -->
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
访问路径是 resources 后面的部分 webjars/jquery/3.6.0/jquery.js,一般是 webjars/{artifactId}/{version}/…
<!-- html引入-->
<script src="webjars/jquery/3.6.0/jquery.js"></script>
#浏览器直接访问
http://localhost:8080/{context-path}/webjars/jquery/3.6.0/jquery.js
首页映射
welcomePageHandlerMapping()
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
//getWelcomePage()获取首页
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
private Resource getWelcomePage() {
//遍历静态资源的所有位置
for (String location : this.resourceProperties.getStaticLocations()) {
//调用getIndexHtml()查找首页
Resource indexHtml = getIndexHtml(location);
if (indexHtml != null) {
return indexHtml;
}
}
//如果在静态资源位置找不到,则在 ServletContext 中找
ServletContext servletContext = getServletContext();
if (servletContext != null) {
//调用getIndexHtml()查找首页
return getIndexHtml(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
return null;
}
private Resource getIndexHtml(String location) {
return getIndexHtml(this.resourceLoader.getResource(location));
}
private Resource getIndexHtml(Resource location) {
try {
//把 index.html 作为首页
Resource resource = location.createRelative("index.html");
if (resource.exists() && (resource.getURL() != null)) {
return resource;
}
}
catch (Exception ex) {
}
return null;
}
先在静态资源位置中查找 index.html 文件,把查找到的第一个 index.html 文件作为首页,映射为 /**,访问 http://localhost:8080/{context-path} 时显示该页面;如果找不到,会在 ServletContext 中继续找。