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:hrefth: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 电流控制器和动作

Spring MVC、Tiles2、ThymeLeaf 和自然模板

springboot 1.5.2 thymeleaf 添加templates 静态资源访问路径