写在最前面
犹记毕业第一年时, 公司每次发布完成后, 都会在一个群里通知 [版本更新, 各部门清理缓存, 有问题及时反馈] 之类的话. 归根结底就是资源缓存的问题, 浏览器会将请求到的静态资源, 如 JS,CSS 等文件缓存到用户本地, 当用户再次访问时就不需要再次请求这些资源了, 以此也是提升了用户体验. 但是也正是因为这些资源缓存, 导致客户端的静态文件往往不是当前最新版本. 后来有同事增加了时间戳, 随机数等, 确实这也解决了客户端缓存的问题, 但是却又带来了新的麻烦, 导致每次访问都要请求服务器, 无形中增加了服务器的压力.
那么有什么办法可以让客户端当需要更新时才去请求, 不需更新就不请求吗? 当然有, 实现方式很多种, 像前端实现, webjars 实现等都可以, 但是麻烦还是麻烦, 太烧脑. 介绍一种 Spring 自身提供的方式, 也是我目前所应用的方式,.
ResourceUrlProvider 的实现效果有两种, 大家可以在后文中看到.
第一种, MD5 实现
首先在 application.YAML 或者 application.properties 中增加配置文件
- spring:
- resources:
- chain:
- strategy:
- content:
- enabled: true
- paths: /**
其次, 如果您恰巧和我一样使用 Thymeleaf 作为模板引擎, 则可以和我一样使用 @bean 语法直接从模板访问 ResourceUrlProviderbean.
<script th:src="${@mvcResourceUrlProvider.getForLookupPath('/mods/admin/login.js')}"></script>
如果您使用的模板引擎无法直接访问 Spring bean, 则可以将 ResourceUrlProvider 添加到 Spring 中. 使用 ControllerAdvice, 代码如下:
- @ControllerAdvice
- public class ControllerConfig {
- @Autowired
- ResourceUrlProvider resourceUrlProvider;
- @ModelAttribute("urls")
- public ResourceUrlProvider urls() {
- return this.resourceUrlProvider;
- }
- }
然后在页面上通过下述代码引用:
<script th:src="${urls.getForLookupPath('/mods/admin/login.js')}"></script>
此方法应适用于支持方法调用的所有模板引擎.
下面我们来看看具体的实现效果吧, 前台访问后 html 页面显示为:
<script src="/mods/admin/login-96d770c87905659930c9786eaa08d710.js"></script>
注意: 如果你的 JS 文件没有修改, 或者修改没重启, MD5 的值可能不会改变, 当你重启服务后你会看到你修改过后的文件 MD5 也随之改变了.
简单看了下源代码, MD5 的计算是通过 ContentVersionStrategy 这个类实现的. 此 VersionStrategy 实现根据资源的内容计算 MD5 哈希值, 并将其附加到文件名后面, 也就是你不改变内容 MD5 值是不会变的哦, 一度让我以为这种方法有 BUG(。•ˇˇ•。).
第二种, 版本号实现
同样在 application.YAML 或者 application.properties 中增加配置文件
- spring:
- resources:
- chain:
- strategy:
- fixed:
- enabled: true
- paths: /mods/admin/*.JS
- version: 20181128
后续操作同上, 此时我们看下页面显示的效果:
<script src="/20181128/mods/admin/login.js"></script>
在文件路径的最前面增加了版本号, 当我们每次修改只需要更新版本号的设置, 客户端就会自动请求最新的数据了.
同样的看了下此 VersionStrategy 的实现是 FixedVersionStrategy 类, 来使固定版本字符串作为资源路径的前缀.
总结
相比其他方式的静态资源控制, 这种方式是我目前发现最简便的了, 尤其是在 SpringBoot 项目中的使用. 在这两种方式中, 我更倾向于方法一的 MD5 方式, 可以让我们不必太过于关注静态资源问题. 当然上述讲的两个实现类, 在传统 SpringMVC 项目中也是有的, 所以传统项目也是可以使用的, 具体的使用方法大家可以研究研究.
随笔小记, 喜欢帮忙点个赞吧. 实现思路来自 Michael Scharhag:https://www.mscharhag.com/spring/resource-versioning-with-spring-mvc
来源: https://www.cnblogs.com/laoyeye/p/10034617.html