Question

I'm trying to find the best solution to manage browser cache to reload modified JavaScript/CSS resources in a Java/Maven project. The most widespread solution seems be Maven filtering to add a timestamp to the resource URL at build-time. For instance:

<script type="text/javascript" src="resource.js?v=${maven.build.timestamp}"></script>

But the most efficient way would be to add a checksum/hash of the file (aka fingerprint) instead of the build date so that the resource is not reloaded after each deployment but only when necessary. I'm looking desperately for the correct/generic implementation of this model using Java or a Maven plugin.

Any ideas?

Thanks.

No correct solution

OTHER TIPS

You do want to use fingerprinting vs a query param. The query param method doesn't always works and most proxies won't cache it. Changing the URL or actual file names works better.

So here's how I'm dealing with this in a Maven, Git, Tomcat, Dojo project. I use http://mojo.codehaus.org/buildnumber-maven-plugin/ to get my Git rev. And then use filtering when building my WAR to inject the value into my JSPs.

pom.xml

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>buildnumber-maven-plugin</artifactId>
        <version>1.1</version>
        <executions>
            <execution>
                <phase>validate</phase>
                <goals>
                    <goal>create</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <doCheck>false</doCheck>
            <doUpdate>false</doUpdate>
            <shortRevisionLength>8</shortRevisionLength>
            <revisionOnScmFailure></revisionOnScmFailure>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.3</version>
        <configuration>
            <warName>${project.name}-${project.version}-${buildNumber}</warName>
            <webResources>
                <resource>
                    <directory>src/main/webapp/WEB-INF/views/includes</directory>
                    <targetPath>WEB-INF/views/includes</targetPath>
                    <filtering>true</filtering>
                </resource>
            </webResources>                  
            ......
        </configuration>
    </plugin>

In my main JSP include I have

<script src="${pageContext.request.contextPath}/${buildNumber}/static/js/ckeditor/ckeditor.js"></script>
<script src="${pageContext.request.contextPath}/${buildNumber}/static/js/build/dojo/dojo.js"  data-dojo-config="parseOnLoad: true"></script>

To do the rewrite i'm using http://tuckey.org/urlrewrite/. I just have one simple rule.

my first filter entry web.xml

<filter>
    <filter-name>UrlRewriteFilter</filter-name>
    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    <init-param>
        <param-name>logLevel</param-name>
        <param-value>WARN</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

urlrewrite.xml

<rule match-type="regex">
    <from>^/[0-9A-Za-z_.\-]+/static/(.*)$</from>
    <to>/static/$1</to>
</rule>

I don't have use it yet, but the maven-fingerprint-plugin seems nice.

It requires just a bit of maven configuration, and then it will automatically rebuild all urls in your files to fingered versions.

No need to manually keep ${buildNumber}, ${hashVersion} or other fingerprint choice in your resources URLs.

From the repository:

<pluginRepositories>
    <pluginRepository>
        <id>fprint-repo</id>
        <url>https://raw.github.com/dernasherbrezon/maven-fingerprint-plugin/master/maven-fingerprint-plugin/mvn-repo</url>
    </pluginRepository>
</pluginRepositories>

then

<executions>
    <execution>
        <phase>package</phase>
        <goals>
            <goal>generate</goal>
        </goals>
    </execution>
</executions>
<configuration>
    <excludeResources>
        <excludeResource>://</excludeResource>
        <excludeResource>//</excludeResource>
    </excludeResources>
    <!-- ${basedir}/src/main/webapp by default -->
    <sourceDirectory>${basedir}/target/webcombined</sourceDirectory>
    <!-- ${project.build.directory}/fingered-web by default -->
    <outputDirectory>${basedir}/target/fingered</outputDirectory>
    <!-- Remove unnecessary spaces between tags. Make single line page.
    Takes into consideration <pre> tags -->
    <trimTagExtensions>
        <trimTagExtension>html</trimTagExtension>
    </trimTagExtensions>
    <extensionsToFilter>
        <extensionToFilter>html</extensionToFilter>
        <extensionToFilter>jsp</extensionToFilter>
        <extensionToFilter>tag</extensionToFilter>
        <extensionToFilter>css</extensionToFilter>
        <extensionToFilter>js</extensionToFilter>
    </extensionsToFilter>
    <!-- cdn host. Not required. For example using
    "//accountname.r.worldssl.net": /css/bootstrap.css =>
    //accountname.r.worldssl.net/css/<md5>bootstrap.css -->
    <cdn>${cdn}</cdn>
</configuration>

and that's it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top