前言
在前面的章节中,壹哥 跟大家说过,现在Java中的项目,有的是前后端分离的,页面和静态资源都是分离出去的,与后端的Java代码都不在一起。当然也有一些前后端不分离的项目,页面和静态资源是与Java代码存放在一个jar或war包中的,那如果是SpringBoot开发的前后端不分离项目,对这些静态资源该如何处理呢?
啥?你别告诉我,你连静态资源是什么都不知道哦!
如果你对静态资源没有清晰的认识,那我就说一下吧。一般我们说的静态资源,指的是项目中用到的图片、js、css、纯html等资源。其实在SpringBoot中,对静态资源的访问有着比较好的支持,基本使用默认配置就能满足我们的开发需求了。
一. 静态资源处理机制简介
接下来 壹哥 就带大家学习一下SpringBoot中对静态资源的处理机制,看看SpringBoot对不同的静态资源是如何处理的,本章节的重点其实就是掌握静态资源的存储位置和加载路径。
1. 默认的静态资源映射
SpringBoot对Web的开发支持,主要是基于SpringMVC模块来实现的,而SpringMVC主要是利用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()源码
这是SpringBoot中的addResourceHandlers()源码方法。
publicvoidaddResourceHandlers(ResourceHandlerRegistryregistry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } DurationcachePeriod=this.resourceProperties.getCache().getPeriod(); CacheControlcacheControl=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的值是 /**StringstaticPathPattern=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项目,带各位做一个小实验,创建项目的过程请参考之前的案例,此处略过。
4. 项目结构图
我这里在resources目录下,分别新建resources、static、public、/META-INF/resources 4个目录,并分别放入a.png,b.png,c.png,d.png 4张图片。
5. 启动项目测试
然后我们在浏览器中,分别输入各个静态资源的地址,这里我们直接通过URL地址即可访问不同的静态资源。
5.1 访问a.png
我们先来访问第一个图片a.png,地址如下:
可以看到如下效果:
5.2 访问b.png
接下来再访问第2个图片b.png,地址如下:
5.3 访问c.png
然后再访问第3个图片c.png,地址如下:
5.4 访问d.png
最后再来访问第4个图片d.png,地址如下:
最终我们会发现,这4个存放在不同位置下的静态资源,都可以被我们顺利的访问到。
二. 自定义静态资源访问路径
1. 概述
除了可以把静态资源存放在默认的路径下之外,有时候我们也需要自定义静态资源的存放路径。
那么什么情况下,需要自定义静态资源存放路径呢?
比如我们开发一个项目,里面有文件上传功能,那么直接把上传的文件存放在上述那些文件夹中合适吗?
如果那样干的话,可能会存在如下问题:
- 静态内容与项目代码不能有效分离;
- 当项目被打包成一个.jar文件部署时,再将上传的文件放到这个.jar包中效率低下;
- 备份网站数据的会很麻烦。
2. 自定义位置的实现方式
那么此时我们能不能自定义静态资源的存放位置,把静态资源的访问路径映射到磁盘的某个目录里呢?这当然是可以的,接下来 壹哥 就讲解如何实现自定义静态资源的存放位置,这里我给大家提供了2种方式进行实现。
- 代码中配置实现;
- 配置文件配置实现。
接下来我分别讲解两种实现方式。
3. 代码中配置实现
这种方式中,需要我们自定义WebMvcConfigurerAdapter类,并覆写addResourceHandlers()方法来改变默认情况下加载静态文件的行为,这其实是通过Spring MVC的提供的ResourceHttpRequestHandler来实现的。
3.1 创建存放资源的目录
我们可以先在自己的某个盘符下创建一个资源文件夹,里面存放一些自己的资源,比如我的:
3.2 编写实现代码
因为在Spring Boot 2.x的版本中使用的是Spring5,WebMvcConfigurerAdapter已经过时,可以直接实现WebMvcConfigurer接口,或者继承WebMvcConfigurationSupport 类来代替,都要实现addResourceHandlers()方法。
packagecom.yyg.boot.config; importorg.springframework.context.annotation.Configuration; importorg.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; importorg.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; importorg.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; /*** @Description Description* @Author 一一哥Sun* @Date Created in 2020/3/21*/publicclassMyWebMvcConfigextendsWebMvcConfigurationSupport { publicvoidaddResourceHandlers(ResourceHandlerRegistryregistry) { //将所有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
此时只要我们在访问资源时,路径中匹配了“code”,就可以访问里面的资源。
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指的是系统环境变量。
4.2 重启项目测试
重启项目后,请输入网址,此时因为我的F:/resources/目录下有logo01.png资源,所以此时可以直接访问该资源。
接下来我们访问如下地址:
http://localhost:8080/res/logo02.png
这时会发现我们的资源依然可以被访问到。
结语
至此,壹哥 就把SpringBoot中该如何存放和处理静态资源,详细的给各位讲解了,你可以按照我的讲解试试,把一些静态资源存放到不同的目录下,看看能不能正常访问到。
今日小作业:
把苍老师的靓照,通过今天的访问路径加载到themeleaf页面中显示出来。