Spring MVC 和 Thymeleaf 资源版本控制
Posted
技术标签:
【中文标题】Spring MVC 和 Thymeleaf 资源版本控制【英文标题】:Spring MVC and Thymeleaf Resource Versioning 【发布时间】:2018-07-21 19:42:47 【问题描述】:我正在尝试使用 Spring Mvc 4 进行资源版本控制。我使用 thymeleaf 模板引擎。但不适用于以下代码。加载页面时,当我查看页面源时看不到新版本的 Url。那么我的问题是什么代码?我想念什么?
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry)
registry.addResourceHandler("/static/theme*//**").addResourceLocations("/resources/static/theme/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
registry.addResourceHandler("/static*//**").addResourceLocations("/resources/static/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
registry.addResourceHandler("/static/js*//**").addResourceLocations("/resources/static/js/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
@Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter()
return new ResourceUrlEncodingFilter();
我在脚本标签中使用 with 表达式。 th:src="@/resources/static/js/companyList.js"
【问题讨论】:
我有非常相似的非工作代码;对我来说,它没有设置缓存控制标头,表明它没有使用处理程序。您的版本是否将标头设置为 365 天? 我的问题是相关的资源路径。错误创建的 url 导致了问题。当你查看页面的源代码时你能看到带有 md5 的版本控制 url 吗?如果你看到问题仍然存在?我的问题解决了,现在我可以看到 365 天的缓存头了。 【参考方案1】:我没有代码管理它,只在 application.properties 中配置:
# Enable html5 application cache manifest rewriting.
spring.resources.chain.html-application-cache=true
# Enable the Spring Resource Handling chain. Disabled by default unless at least one strategy has been enabled.
spring.resources.chain.enabled=true
# Enable the content Version Strategy.
spring.resources.chain.strategy.content.enabled=true
# Comma-separated list of patterns to apply to the Version Strategy.
spring.resources.chain.strategy.content.paths=/**
我不需要添加任何其他代码来获取 CSS 和 JS 的 URL 中的哈希版本。
【讨论】:
如果你给我们指出这个文档会更棒 好建议,完全同意。 docs.spring.io/spring-boot/docs/current/reference/html/… 和 github.com/spring-projects/spring-boot/blob/v2.1.3.RELEASE/… ?这就是我能找到的所有内容,作为参考有用,但没有解释每个设置的真正作用或如何组合它们。 请务必使用th:href="@/css/app.css"
而不仅仅是href
,以便Thymeleaf 可以在href 链接中放置正确的路径。【参考方案2】:
1. 创建 Thymeleaf LinkBuilder
,使用 Spring 的 ResourceUrlProvider
创建版本化链接:
@Configuration
public class TemplateEngineConfig
@Autowired
public void configureTemplateEngine(SpringTemplateEngine engine,
ResourceUrlProvider urlProvider)
engine.setLinkBuilder(new VersioningLinkBuilder(urlProvider));
class VersioningLinkBuilder extends StandardLinkBuilder
private final ResourceUrlProvider urlProvider;
VersioningLinkBuilder(ResourceUrlProvider urlProvider)
this.urlProvider = urlProvider;
@Override
public String processLink(IExpressionContext context, String link)
String lookedUpLink = urlProvider.getForLookupPath(link);
if (lookedUpLink != null)
return super.processLink(context, lookedUpLink);
else
return super.processLink(context, link);
2.使用百里香标签th:href
和th:src
<link th:href="@/main.css" rel="stylesheet" type="text/css"/>
<script th:src="@/js/main.js" type="text/javascript"></script>
它将被转换为:
<link href="/main-0c362e5c8643b75ddf64940262b219f7.css" rel="stylesheet" type="text/css"/>
<script src="/js/main-c13acb86fa1012e27bbb01a7c4a9bf7f.js" type="text/javascript"></script>
3.(可选)还建议添加浏览器缓存头。添加到您的application.properties
:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.cache.cachecontrol.max-age=365d
spring.resources.cache.cachecontrol.no-cache=false
spring.resources.cache.cachecontrol.no-store=false
spring.resources.cache.cachecontrol.cache-public=true
或者如果你使用application.yml
:
spring:
resources:
chain:
strategy:
content:
enabled: true
paths: /**
cache:
cachecontrol:
max-age: 365d
no-cache: false
no-store: false
cache-public: true
【讨论】:
我在上下文中部署了我的应用程序,因此在链接处理期间,我不得不删除并最近附加了上下文路径。思路如下: if (linkToProcess.startsWith(servletContext.getContextPath())... ... return super.processLink(context, servletContext.getContextPath() + linkToProcess); 这在 Spring Boot 2.4 上对我有用,感谢您的撰写!【参考方案3】:以下内容对我有用:
application.yml
...
resources:
chain:
strategy:
content:
enabled: true
paths: /js/**,/css/**
...
index.html
...
<script th:src=@/js/home.js></script>
...
结果
这会呈现如下内容:
...
<script src=/js/home-440273f30b71d3cf4184b48ce5e10b94.js></script>
...
【讨论】:
【参考方案4】:这是我的解决方案。我调试Spring.ServletContextResource类的源代码创建一个relativeRelative。然后检查资源是否存在。
资源位置:/resources/static/
路径:/static/css/login.css
pathToUse : /resources/static/static/css/login.css --> 这个资源url不存在所以返回null。
ServletContextResource 类
@Override
public Resource createRelative(String relativePath)
String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
return new ServletContextResource(this.servletContext, pathToUse);
解决方案: 资源位置:/resources/static/
路径:/css/login.css
pathToUse : /resources/static/css/login.css
现在我包含这种格式。从路径中删除 /resources。
th:src="@/css/login.css"
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry)
registry.addResourceHandler("/theme*//**").addResourceLocations("/resources/static/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
registry.addResourceHandler("/css*//**").addResourceLocations("/resources/static/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
registry.addResourceHandler("/js*//**").addResourceLocations("/resources/static/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(false)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
@Override
public void configure(final WebSecurity web) throws Exception
web.ignoring().antMatchers("/theme/**").antMatchers("/js/**").antMatchers("/css/**");
【讨论】:
【参考方案5】:ResourceUrlEncodingFilter 的使用过滤了页面中的所有 url,这是不可取的并且会导致性能问题。我的解决方案如下:
registry.addResourceHandler("/javascript/*.js", "/css/*.css", "/img/*")
.addResourceLocations("classpath:/static/javascript/", "classpath:/static/css/", "classpath:/static/img/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
并在页面内部使用以下函数查找静态资源
<script th:src="$@mvcResourceUrlProvider.getForLookupPath('/javascript/app.js')"></script>
【讨论】:
以上是关于Spring MVC 和 Thymeleaf 资源版本控制的主要内容,如果未能解决你的问题,请参考以下文章
Thymeleaf 和 Spring MVC 的表单参数为空
Thymeleaf (Java Spring):无法让 mvc.uri 工作
Spring MVC 和 Thymeleaf 自定义错误消息类型转换
Thymeleaf 和 Spring MVC 电流控制器和动作