作者:一一哥
一.概述我们在进行web开发的时候,一些静态资源的访问一般都是必需的,比如图片、js、css等资源的访问。在Spring Boot中对静态资源的访问实现了很好的支持,基本使用默认配置就能满足我们的开发需求。
1.默认的静态资源映射Spring Boot中的Spring MVC模块利用ResourceHttpRequestHandler来处理静态内容,对静态资源的映射提供了默认的配置。默认情况下,SpringBoot按如下优先级,从上到下将 /** 所有的资源访问映射到以下目录:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
/:当前项目的根路径
如果我们在上面几个目录下存放同一份静态资源,比如在/static里面有个a.png,/public下面也有个a.png,则优先会加载/static下面的a.png。
对于资源目录下的资源,我们此时可以直接通过url地址访问http://localhost:8080/a.png,也就是说类似于以前web项目中的webapp目录,而放到其他目录下默认是无法被访问的。
为什么以上的几个文件夹,是Spring Boot中默认的存放静态资源的目录呢?我们可以看看addResourceHandlers()方法源码。
2.addResourceHandlers()源码public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePerio))
.setCacheControl(cacheControl));
}
//staticPathPattern的值是 /**
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
}
从上面的源码中可以解读出两点关键信息:
- 所有的"/webjars/**都去classpath:/META-INF/resources/webjars/路径下找静态资源;
- 如果路径是/**时,就去以下路径加载资源。
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
3.加载静态资源实验
为了验证上面的结论,我们可以创建一个新的web项目,做一个小实验,创建项目的过程参考之前的案例,此处略过。
在resources目录下分别新建resources、static、public、/META-INF/resources 4个目录,并分别放入a.png,b.png,c.png,d.png 4张图片。
项目结构图:
我们在浏览器中,分别输入资源地址。
http://localhost:8080/a.png 可以看到如下效果:
http://localhost:8080/b.png
http://localhost:8080/c.png
http://localhost:8080/d.png
我们除了可以把静态资源存放在默认的路径下之外,有时候我们也需要自定义静态资源的存放路径。
那么什么情况下,需要自定义静态资源存放路径呢?
比如我们开发一个项目,里面有文件上传功能,那么直接把上传的文件存放在上述那些文件夹中合适吗?
如果那样干的话,可能会存在如下问题:
- 静态内容与项目代码不能有效分离;
- 当项目被打包成一个.jar文件部署时,再将上传的文件放到这个.jar包中效率低下;
- 备份网站数据的会很麻烦。
那么此时我们能不能自定义静态资源的存放位置,把静态资源的访问路径映射到磁盘的某个目录里呢?这当然是可以的,接下来我们就讲解如何实现自定义静态资源的存放位置,我们有2种方式可以实现。
- 代码中配置实现;
- 配置文件配置实现;
接下来我们分别讲解两种实现方式。
3.代码中配置实现这种方式中,需要我们自定义WebMvcConfigurerAdapter类,并覆写addResourceHandlers()方法来改变默认情况下加载静态文件的行为,这其实是通过Spring MVC的提供的ResourceHttpRequestHandler来实现的。
3.1 创建存放资源的目录我们可以先在自己的某个盘符下创建一个资源文件夹,里面存放一些自己的资源,比如我的:
因为在Spring Boot 2.x的版本中使用的是Spring5,WebMvcConfigurerAdapter已经过时,可以直接实现WebMvcConfigurer接口,或者继承WebMvcConfigurationSupport 类来代替,都要实现addResourceHandlers()方法。
package com.yyg.boot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/21
*/
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//将所有F:/resources/目录下的资源,访问时都映射到/res/** 路径下
registry.addResourceHandler("/code/**")
.addResourceLocations("classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/", "file:F:/resources/");
}
}
注意:
当我们指定了静态文件目录之后,在页面中引用时,必须加上code,例如 等。
这其中的原因,可以去看看 WebMvcConfigurationSupport 和 WebMvcConfigurerAdapter 源码。
3.3 重新项目,访问测试输入网址进行测试:http://localhost:8080/code/logo02.png
此时只要我们在访问资源时,路径中匹配了“res”,就可以访问里面的资源。
4.配置文件设置实现接下来我们讲解在properties配置文件中的实现方式。
注意:记得我们把之前代码方式的实现先注释点,如果两种方式都配置的话,会以代码方式配置为准!
4.1 创建application.properties配置文件内容如下:
#自定义的属性,指定了一个路径,注意要以/结尾
web.upload-path=F:/resources/
#表示所有的访问都经过静态资源路径
spring.mvc.static-path-pattern=/res/**
#配置所有的静态资源路径,要将默认的也加上否则static、public等这些路径将不能被当作静态资源路径.末尾是我们自己的自定义资源路径
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${web.upload-path}
注意:
- web.upload-path:自定义属性,指定了我们静态资源的存放路径,注意要以/结尾;
- spring.mvc.static-path-pattern=/**:表示所有的访问都经过静态资源路径的匹配规则;
- spring.resources.static-locations:在这里配置静态资源路径,前面说了这里的配置是覆盖默认配置,所以需要将默认的也加上否则static、public等这些路径将不能被当作静态资源路径,在这个最末尾的file:${web.upload-path}之所有要加file:是因为指定的是一个具体的硬盘路径,其他的使用classpath指的是系统环境变量。
输入网址,此时因为我的F:/resources/目录下有logo01.png资源,所以此时可以直接访问该资源。
http://localhost:8080/res/logo02.png