Reputation: 224
I am trying resource versioning with Spring Mvc 4.I use thymeleaf template engine.But doesnt work with the following code.When load the page I cant see new version Url when i view the page source. So what's the problem in my code? What do I miss?
@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();
}
I am using with expression in script tag. th:src="@{/resources/static/js/companyList.js}"
Upvotes: 9
Views: 7846
Reputation: 2045
The following worked for me:
application.yml
...
resources:
chain:
strategy:
content:
enabled: true
paths: /js/**,/css/**
...
index.html
...
<script th:src=@{/js/home.js}></script>
...
Result
This renders something like this:
...
<script src=/js/home-440273f30b71d3cf4184b48ce5e10b94.js></script>
...
Upvotes: 3
Reputation: 2168
1. Create Thymeleaf LinkBuilder
that uses Spring's ResourceUrlProvider
to create versioned links:
@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. Use thymeleaf tags th:href
and th:src
<link th:href="@{/main.css}" rel="stylesheet" type="text/css"/>
<script th:src="@{/js/main.js}" type="text/javascript"></script>
It will be converted to:
<link href="/main-0c362e5c8643b75ddf64940262b219f7.css" rel="stylesheet" type="text/css"/>
<script src="/js/main-c13acb86fa1012e27bbb01a7c4a9bf7f.js" type="text/javascript"></script>
3.(Optional) It is also recommended to add browser cache headers. Add to your 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
Or if you use application.yml
:
spring:
resources:
chain:
strategy:
content:
enabled: true
paths: /**
cache:
cachecontrol:
max-age: 365d
no-cache: false
no-store: false
cache-public: true
Upvotes: 7
Reputation: 11
The usage of ResourceUrlEncodingFilter filters all urls in the page, which is not desirable and causes performance issues. My solution is the following:
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("/**"));
and inside the page using the below function to lookup the static resource
<script th:src="${@mvcResourceUrlProvider.getForLookupPath('/javascript/app.js')}"></script>
Upvotes: 0
Reputation: 2981
I managed it with no code, only config in 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=/**
I didn't need to add any other code to get the hash version in the URLs for CSS and JS.
Upvotes: 13
Reputation: 224
Here is the my solution.I debug source code of Spring.ServletContextResource class create a relativeRelative.Then check whether resource is exists.
Resource location : /resources/static/
Path : /static/css/login.css
pathToUse : /resources/static/static/css/login.css --> this resource url not exists so return null.
ServletContextResource class
@Override
public Resource createRelative(String relativePath) {
String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
return new ServletContextResource(this.servletContext, pathToUse);
}
Solution: Resource location : /resources/static/
Path : /css/login.css
pathToUse : /resources/static/css/login.css
Now I include this format.Remove /resources from path.
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/**");
}
Upvotes: 1