静态资源映射
静态资源映射
SpringBoot 2.7.5
对应的自动配置类是 WebMvcAutoConfiguration
,我们之前在《SpringBoot 基础篇 -2- 自动配置.md》中的 WebMvcAutoConfiguration
小节中,对其就有一定的介绍。
静态资源访问
官方文档
《SpringMVC- 第十篇:基于注解配置 SpringMVC.md》中的 addResourceHandlers
小节
《SpringMVC 中的静态资源处理.md》
静态文件位置和 URL 映射
默认情况下,Spring Boot 从类路径(src/main/resources
)中的 /static
或 /public
或 /resources
或 /META-INF/resources
目录或 ServletContext
的根目录中提供静态内容。它使用来自 Spring MVC 的 ResourceHttpRequestHandler
,因此您可以通过添加您自己的 WebMvcConfigurer
并重写 addResourceHandlers
方法来修改该行为。
需要继承
WebMvcConfigurer
然后重写addResourceHandlers
方法,请查看《SpringMVC- 第十篇:基于注解配置 SpringMVC.md》中的addResourceHandlers
小节
如果需要为不同的静态资源位置配置不同的 URL 匹配模板,估计就得通过这种方式了,具体请参考《SpringBoot-Web 开发 -11- 定制化原理.md》
在独立的 web 应用中,来自容器(比如 Tomcat)的默认 servlet 是不启用的。它可以设置 server.servlet.register-default-servlet
属性来启用。
关于容器中默认的 Servlet 在 SpringMVC 中的开启方式请查看《SpringMVC- 第十篇:基于注解配置 SpringMVC.md》中的
configureDefaultServletHandling
小节
默认情况下,资源映射在 /**
这个 URL 上,但你可以用 spring.mvc.static-path-pattern
这个属性来自定义 URL 映射位置。例如,将所有资源重新定位到 /resources/**
可以通过以下方式实现:
spring:
mvc:
static-path-pattern: /resources/**
您还可以使用 spring.web.resources.static-locations
属性自定义静态资源的位置。(用目录位置列表替换默认值)。root servlet context path /
也会自动添加为资源位置。
root servlet context path 和上面提到的
ServletContext
的根目录 到底是啥路径,是src/main/webapp
这个路径吗?感觉是的
除了前面提到的标准的 4 个静态资源位置之外,还为 Webjar 内容做了一个特例。任何 URL 路径匹配 /webjars/**
模板的请求都会从 jar 文件中提供资源,如果这些资源本身被打包成 Webjars 格式的话。
Webjar,就是将 js、css 这些静态资源打成 jar 包来用
用的不多,懒得实践了
如果你的应用程序被打包成 jar,不要使用 src/main/webapp
目录。尽管该目录是一个通用标准,但它只适用于 war
打包,如果生成jar,大多数构建工具都会忽略它。
Spring Boot 还支持 Spring MVC 提供的高级资源处理特性,比如我们在《SpringMVC 中的静态资源处理.md》中学习过的,带版本信息的资源请求,基于文件内容自动生成版本信息或者基于固定的版本,这个 Spring Boot 都可以支持配置。具体请参考 Static Content 官方文档和《SpringMVC 中的静态资源处理.md》
简单实践
src/main/resources
目录下新建 config/application.yaml
server:
# 当前应用所在的Web服务器监听的本地端口
port: 8081
servlet:
# 应用的上下文路径
context-path: /SpringBoot-WebSimple
# 启用默认的Servlet
register-default-servlet: true
在 src/main/resources
目录下新建 /static
、/public
、/resources
、/META-INF/resources
四个目录,在这四个为目录下均添加一个子目录 image
,并分别添加文件 aaa.jpg
、bbb.jpg
、ccc.jpg
、ddda.jpg
在浏览器中依次输入 http://localhost:8081/SpringBoot-WebSimple/image/aaa.jpg
、http://localhost:8081/SpringBoot-WebSimple/image/bbb.jpg
、http://localhost:8081/SpringBoot-WebSimple/image/ccc.jpg
、http://localhost:8081/SpringBoot-WebSimple/image/ddd.jpg
均可正常访问。
如果在四个路径中存在同路径下的同名资源,那么资源优先级是
-
classpath:/META-INF/resources/
-
classpath:/resources/
-
classpath:/static/
-
classpath:/public/
从 WebMvcAutoConfiguration
的 WebMvcAutoConfigurationAdapter
内部类的 addResourceHandlers
方法可以得知
@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/");
// 默认的静态资源位置的配置
// this.mvcProperties.getStaticPathPattern() 中,对应的配置是 spring.mvc.static-path-pattern ,默认值是 "/**"
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
// this.resourceProperties.getStaticLocations() 中,如果用户没有设置 spring.web.resources.static-locations 则默认值是 { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" }
// 因为资源的添加顺序就是查找顺序,所以,默认的资源查找路径的查找顺序,是
// "classpath:/META-INF/resources/"
// "classpath:/resources/"
// "classpath:/static/"
// "classpath:/public/"
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
添加配置,自定义静态资源位置
server:
# 当前应用所在的Web服务器监听的本地端口
port: 8081
servlet:
# 应用的上下文路径
context-path: /SpringBoot-WebSimple
# 启用默认的Servlet
register-default-servlet: true
spring:
web:
resources:
# 这里可以传入单个,也可以传入列表
static-locations: classpath:/myResources/
注意,每一个路径都需要指定是 classpath:
开头还是以 file:
开头,否则找不到资源。当然最后后面带个 /
,这样表义明确一些。
很奇怪的一点是,配置了
spring.web.resources.static-locations
之后,默认静态资源位置中的/static
、/public
、/resources
下面的资源已经无法访问了,但是META-INF/resources
依然有效,下面的资源依然可以访问。而且优先级依然排在自定义配置的位置的前面。
添加配置,自定义静态资源的 URL 匹配模板,不自定义的时候是 /**
,直接从应用上下文路径后面开始匹配,这样不方便通过路径进行拦截。静态资源的访问都带一个前缀是最好的,这样可以方便根据路径做拦截判断,比如静态资源就不需要拦截做登录判断。
server:
# 当前应用所在的Web服务器监听的本地端口
port: 8081
servlet:
# 应用的上下文路径
context-path: /SpringBoot-WebSimple
# 启用默认的Servlet
register-default-servlet: true
spring:
mvc:
static-path-pattern: /resources/**
# web:
# resources:
# # 这里可以传入单个,也可以传入列表
# static-locations: classpath:/myResources/
现在需要通过 http://localhost:8081/SpringBoot-WebSimple/resources/image/aaa.jpg
才能访问到资源
额外注意一点:
如果有 Controller 的映射路径跟静态资源的路径重复了,那么此 URL 会访问 Controller 而不会访问静态资源,这是因为 SimpleUrlHandlerMapping
排在 RequestMappingHandlerMapping
的后面,因此,如果 url 同时匹配控制器方法和 ResourceHttpRequestHandler
,那么会优先匹配控制器方法。
ResourceHttpRequestHandler
通常由SimpleUrlHandlerMapping
进行映射。
详细分析请看《SpringMVC 控制器方法(handler)的映射 - HandlerMapping.md》
欢迎页支持 & 自定义 Favicon
官方文档:欢迎页,自定义Favicon
Favicon 就是浏览器标签页的图标 ,例如
![]()
Spring Boot 既支持静态欢迎页面,也支持模板化欢迎页面(模板指的是视图模板,需要控制器方法跳转或者 ViewController
跳转)。SpringBoot 系统首先在配置的静态资源位置中查找 index.html
文件。如果没有找到,就到 templates
目录下查找 index
视图模板。如果找到其中一个,它将自动用作应用程序的欢迎页面。
在 static
目录下创建 index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>Hello World</h1>
Spring Boot 真的和好用!
</body>
</html>
访问 http://localhost:8081/SpringBoot-WebSimple/
注意,此时不能指定静态资源的 URL 映射模板 spring.mvc.static-path-pattern
,否则,静态资源目录下的 index.html
无法生效。因此,我们只能尝试通过编写控制器方法处理 /index
在 templates
创建 index
视图,来设置欢迎页。
这个我们在《SpringBoot-Web 相关自动配置类源码解析 -WebMvcAutoConfiguration.md》中的
welcomePageHandlerMapping
小节有解释
与其他静态资源一样,Spring Boot 在配置的静态资源位置中检查 favicon.ico
。如果存在这样一个文件,它将自动用作应用程序的 favicon。
访问首页

注意,此时,前端对 favicon.ico
的请求路径是 http://localhost:8081/favicon.ico
,也就是说,要想让静态资源目录下的 favicon.ico
生效,不能指定应用的请求的上下文路径 server.servlet.context-path
,也不能指定静态资源的 URL 映射模板 spring.mvc.static-path-pattern
,所以这个功能有点鸡肋。
对 favicon 的请求是浏览器的默认行为,发送的请求的 URL 也是固定的,当然也是可以改的,有时间再研究吧,TODO
相关源码分析
请看《SpringBoot-Web 相关自动配置类源码解析 -WebMvcAutoConfiguration.md》