当我们使用 SpringMVC 框架时,静态资源会被拦截,需要添加额外配置,之前老有小伙伴在微信上问松哥 Spring Boot 中的静态资源加载问题:“松哥,我的 HTML 页面好像没有样式?”,今天我就通过一篇文章,来和大伙仔细聊一聊这个问题。

1. SSM 中的配置

要讲 Spring Boot 中的问题,我们得先回到 SSM 环境搭建中,一般来说,我们可以通过 <mvc:resources /> 节点来配置不拦截静态资源,如下:

<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/html/**" location="/html/"/>

由于这是一种Ant风格的路径匹配符,/** 表示可以匹配任意层级的路径,因此上面的代码也可以像下面这样简写:

<mvc:resources mapping="/**" location="/"/>

这种配置是在 XML 中的配置,大家知道,SpringMVC 的配置除了在XML中配置,也可以在 Java 代码中配置,如果在 Java 代码中配置的话,我们只需要自定义一个类,继承自 WebMvcConfigurationSupport 即可:

@Configuration
@ComponentScan(basePackages = "org.javaboy.javassm")
public class SpringMVCConfig extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("/");
}
}

重写 WebMvcConfigurationSupport 类中的 addResourceHandlers 方法,在该方法中配置静态资源位置即可,这里的含义和上面 xml 配置的含义一致,因此无需多说。

这是我们传统的解决方案,在 Spring Boot 中,其实配置方式和这个一脉相承,只是有一些自动化的配置了。

2. Spring Boot 中的配置

在 Spring Boot 中,如果我们是从 https://start.spring.io 这个网站上创建的项目,或者使用 IntelliJ IDEA 中的 Spring Boot 初始化工具创建的项目,默认都会存在 resources/static 目录,很多小伙伴也知道静态资源只要放到这个目录下,就可以直接访问,除了这里还有没有其他可以放静态资源的位置呢?为什么放在这里就能直接访问了呢?这就是本文要讨论的问题了。

2.1 整体规划

首先,在 Spring Boot 中,默认情况下,一共有 5 个位置可以放静态资源,五个路径分别是如下 5 个:

  1. classpath:/META-INF/resources/
  2. classpath:/resources/
  3. classpath:/static/
  4. classpath:/public/
  5. /

前四个目录好理解,分别对应了 resources 目录下不同的目录,第 5 个 / 是啥意思呢?我们知道,在 Spring Boot 项目中,默认是没有 webapp 这个目录的,当然我们也可以自己添加(例如在需要使用JSP的时候),这里第 5 个 / 其实就是表示 webapp 目录中的静态资源也不被拦截。如果同一个文件分别出现在五个目录下,那么优先级也是按照上面列出的顺序。

不过,虽然有 5 个存储目录,除了第 5 个用的比较少之外,其他四个,系统默认创建了 classpath:/static/ , 正常情况下,我们只需要将我们的静态资源放到这个目录下即可,也不需要额外去创建其他静态资源目录,例如我在 classpath:/static/ 目录下放了一张名为 1.png 的图片,那么我的访问路径是:

http://localhost:8080/1.png

这里大家注意,请求地址中并不需要 static,如果加上了 static 反而多此一举会报 404 错误。很多人会觉得奇怪,为什么不需要添加 static 呢?资源明明放在 static 目录下。其实这个效果很好实现,例如在 SSM 配置中,我们的静态资源拦截配置如果是下面这样:

<mvc:resources mapping="/**" location="/static/"/>

如果我们是这样配置的话,请求地址如果是 http://localhost:8080/1.png 实际上系统会去 /static/1.png 目录下查找相关的文件。

所以我们理所当然的猜测,在 Spring Boot 中可能也是类似的配置。

2.2 源码解读

胡适之先生说:“大胆猜想,小心求证”,我们这里就通过源码解读来看看 Spring Boot 中的静态资源到底是怎么配置的。

首先我们在 WebMvcAutoConfiguration 类中看到了 SpringMVC 自动化配置的相关的内容,找到了静态资源拦截的配置,如下:

可以看到这里静态资源的定义和我们前面提到的 Java 配置 SSM 中的配置非常相似,其中,this.mvcProperties.getStaticPathPattern() 方法对应的值是 /**,this.resourceProperties.getStaticLocations() 方法返回了四个位置,分别是:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/

然后在 getResourceLocations 方法中,又添加了 / ,因此这里返回值一共有 5 个。其中, / 表示 webapp 目录,即 webapp 中的静态文件也可以直接访问。静态资源的匹配路径按照定义路径优先级依次降低。因此这里的配置和我们前面提到的如出一辙。这样大伙就知道了为什么 Spring Boot 中支持 5 个静态资源位置,同时也明白了为什么静态资源请求路径中不需要 /static ,因为在路径映射中已经自动的添加上了 /static 了。

2.3 自定义配置

当然,这个是系统默认配置,如果我们并不想将资源放在系统默认的这五个位置上,也可以自定义静态资源位置和映射,自定义的方式也有两种,可以通过 application.properties 来定义,也可以在 Java 代码中来定义,下面分别来看。

2.3.1 application.properties

在配置文件中定义的方式比较简单,如下:

spring.resources.static-locations=classpath:/
spring.mvc.static-path-pattern=/**

第一行配置表示定义资源位置,第二行配置表示定义请求 URL 规则。以上文的配置为例,如果我们这样定义了,表示可以将静态资源放在 resources 目录下的任意地方,我们访问的时候当然也需要写完整的路径,例如在 resources/static 目录下有一张名为 1.png 的图片,那么访问路径就是 http://localhost:8080/static/1.png ,注意此时的 static 不能省略。

2.3.2 Java 代码定义

当然,在 Spring Boot 中我们也可以通过 Java 代码来自定义,方式和 Java 配置的 SSM 比较类似,如下:

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/aaa/");
}
}

这里代码基本和前面一致,比较简单,不再赘述。

3. 总结

这里需要提醒大家的是,松哥见到有很多人用了 Thymeleaf 之后,会将静态资源也放在 resources/templates 目录下,注意,templates 目录并不是静态资源目录,它是一个放页面模板的位置(你看到的 Thymeleaf 模板虽然后缀为 .html,其实并不是静态资源)。好了,通过上面的讲解,相信大家对 Spring Boot 中静态资源的位置有一个深刻了解了,应该不会再在项目中出错了吧!

关注公众号【江南一点雨】,专注于 Spring Boot+微服务以及前后端分离等全栈技术,定期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

Spring Boot2 系列教程(十一)Spring Boot 中的静态资源配置的更多相关文章

  1. Spring Boot2 系列教程(八)Spring Boot 中配置 Https

    https 现在已经越来越普及了,特别是做一些小程序或者公众号开发的时候,https 基本上都是刚需了. 不过一个 https 证书还是挺费钱的,个人开发者可以在各个云服务提供商那里申请一个免费的证书 ...

  2. Spring Boot2 系列教程(五)Spring Boot中的 yaml 配置

    搞 Spring Boot 的小伙伴都知道,Spring Boot 中的配置文件有两种格式,properties 或者 yaml,一般情况下,两者可以随意使用,选择自己顺手的就行了,那么这两者完全一样 ...

  3. Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理

    在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案.Spring Boot 中,对异常的处理有 ...

  4. Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker

    今天来聊聊 Spring Boot 整合 Freemarker. Freemarker 简介 这是一个相当老牌的开源的免费的模版引擎.通过 Freemarker 模版,我们可以将数据渲染成 HTML ...

  5. Spring Boot2 系列教程(九)Spring Boot 整合 Thymeleaf

    虽然现在慢慢在流行前后端分离开发,但是据松哥所了解到的,还是有一些公司在做前后端不分的开发,而在前后端不分的开发中,我们就会需要后端页面模板(实际上,即使前后端分离,也会在一些场景下需要使用页面模板, ...

  6. Spring Boot2 系列教程 (十一) | 整合数据缓存 Cache

    如题,今天介绍 SpringBoot 的数据缓存.做过开发的都知道程序的瓶颈在于数据库,我们也知道内存的速度是大大快于硬盘的,当需要重复获取相同数据时,一次又一次的请求数据库或者远程服务,导致大量时间 ...

  7. Spring Boot2 系列教程(二十)Spring Boot 整合JdbcTemplate 多数据源

    多数据源配置也算是一个常见的开发需求,Spring 和 SpringBoot 中,对此都有相应的解决方案,不过一般来说,如果有多数据源的需求,我还是建议首选分布式数据库中间件 MyCat 去解决相关问 ...

  8. Spring Boot2 系列教程(三十)Spring Boot 整合 Ehcache

    用惯了 Redis ,很多人已经忘记了还有另一个缓存方案 Ehcache ,是的,在 Redis 一统江湖的时代,Ehcache 渐渐有点没落了,不过,我们还是有必要了解下 Ehcache ,在有的场 ...

  9. Spring Boot2 系列教程(三十一)Spring Boot 构建 RESTful 风格应用

    RESTful ,到现在相信已经没人不知道这个东西了吧!关于 RESTful 的概念,我这里就不做过多介绍了,传统的 Struts 对 RESTful 支持不够友好 ,但是 SpringMVC 对于 ...

随机推荐

  1. Visual Studio 调试 —— 附加到进程(远程服务器)

    一般在部署环境下不会有 Visual Studio 开发工具的,所以需要有 Remote Debugger(远程调试器) 才可以进行远程调试. Remote Debugger 获取 方法一:Visua ...

  2. Netty源码分析 (七)----- read过程 源码分析

    在上一篇文章中,我们分析了processSelectedKey这个方法中的accept过程,本文将分析一下work线程中的read过程. private static void processSele ...

  3. Android开发必看知识

    奇艺高清UI界面源代码 http://www.eoeandroid.com/thread-160824-1-1.html 搜索关键字飞入飞出效果 http://www.eoeandroid.com/t ...

  4. 大数据平台搭建 - cdh5.11.1 - hue安装及集成其他组件

    一.简介 hue是一个开源的apache hadoop ui系统,由cloudear desktop演化而来,最后cloudera公司将其贡献给了apache基金会的hadoop社区,它基于pytho ...

  5. 03 jvm的组成

    声明:本博客仅仅是一个初学者的学习记录.心得总结,其中肯定有许多错误,不具有参考价值,欢迎大佬指正,谢谢!想和我交流.一起学习.一起进步的朋友可以加我微信Liu__66666666 这是简单学习一遍之 ...

  6. PTA A1005&A1006

    第三天 A1005 Spell It Right (20 分) 题目内容 Given a non-negative integer N, your task is to compute the sum ...

  7. ReactNative之Redux详解

    用redux有一段时间了,感觉还是有必要把其相关的知识点系统的总结一下的,毕竟好记性不如烂笔头.上篇博客更新了关于<ES6中的迭代器.Generator函数以及Generator函数的异步操作& ...

  8. [PySpark] 01 - Preview parquet files in S3 ×××

    本系列基于实际测试数据,质量保证,不自欺欺人. 实践是检验真理的唯一标准. Swipejobs is all about matching Jobs to Workers. Your challeng ...

  9. C++基础之泛型算法

    标准库并未给每个容器添加大量功能,因此,通过大量泛型算法,来弥补.这些算法大多数独立于任何特定的容器,且是通用的,可用于不同类型的容器和不同的元素. 迭代器使得算法不依赖容器,但是算法依赖于元素的类型 ...

  10. 【Java】SpringBoot 中从application.yml中获取自定义常量

    由于这里我想通过java连接linux,connection连接需要host.port.username.password及其他路径等等.不想每次修改的时候都去改源文件,所以想写在applicatio ...