As per the Q&A here, I'd like to implement a similar auto-versioning system for a web app running in JBoss 5. Is there anything already out there to do this sort of thing, or will I need to write something myself? To be clear: I am not using PHP.
Not knowing much about PHP, I'm not sure what the Tomcat/JBoss analogs of PHP's .htaccess
, etc. are. If I do have to write my own auto-versioning, where would I start? The principle is clear to me - rewriting the URL using the file's timestamp, but I don't know much about URL rewriting with JBoss/Tomcat.
Combining the approaches recommended by Pascal and novice, here's what I ended up with:
1. Custom <my:script/>
and <my:style/>
tags, so I wouldn't have to see <c:url/>
tags everywhere.
<%@ tag body-content="empty" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ attribute name="src" required="true" rtexprvalue="true" %>
<script src="<c:url value="${src}" />"></script>
2. Following fairly closely to novice's steps, but mapping UrlRewriteFilter
to /*
in web.xml:
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3. Injecting a CACHE_BUST variable to every new session (more or less...), an application deploy
timestamp:
// On application deploy:
long CACHE_BUST = System.currentTimeMillis() / 1000;
// later...
session.setAttribute("cacheBust", CACHE_BUST);
4. ...so that I can use these rules in urlrewrite.xml
:
<outbound-rule>
<from>^/static/(css|js|images)/(.*)$</from>
<to>%{context-path}/static/%{session-attribute:cacheBust}/$1/$2</to>
</outbound-rule>
<rule>
<from>^/static/\d{10}/(css|js|images)/(.*)$</from>
<to>/static/$1/$2</to>
</rule>
Many thanks to Pascal and novice for their help.
Following solution is better suited in production environment as you would be incrementing the version number for each release.
Approach:
Steps:
update web.xml with the url pattern, for e.g,
<filter>
<filter-name>urlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>urlRewriteFilter</filter-name>
<url-pattern>/v/*</url-pattern>
</filter-mapping>
update 'abc.js' in the jsp file, for e.g.,
<html>
<head>
<script type="text/javascript" src="<c:url value="/v/js/abc.js"/>"></script>
</head>
</html>
write urlrewritefilter.xml, for e.g.,
<outbound-rule>
<from>^/v/(css|js|static)/(.*)$</from>
<to>%{context-path}/v/updateVersionNumberHere/$1/$2</to>
</outbound-rule>
<rule>
<from>^/v/updateVersionNumberHere/(css|js|static|images)/(.*)$</from>
<to>/$1/$2</to>
</rule>
Explanation:
when jsp is served to client
when browser makes a call for js/css/static files
Points:
If you don't want to front your application with Apache HTTPD, then you could use a custom servlet filter or reuse the existing Url Rewrite Filter. This filter is based on Apache's mod_rewrite
and offers similar capabilities. In other words, it would allow to implement the same solution than the PHP one of the other answer.
I've seen the URL rewrite filter before. Could you elaborate on how I'd use that? I'm really not clear on how I'd apply a filter to this problem, since I wouldn't exactly be calling a JSP/JSTL function wrapped around each included JS/CSS file, and I have no idea about how to get the date modified from a file that's in a WAR.
Well, the idea was to mimic exactly the "PHP solution" of the answer you linked to (let's call this option 1):
/css/my.123456.css
into /css/my.css
Servlet
that would get a File
object for a given resource inside the WAR and insert File#lastModified()
in the returned path to that resource.Servlet
from the JSP for the CSS.Another approach (option 2) would be to append an unique query string to the URL of the static content, e.g. the server startup time:
ServletContextListener
(say under the key "key"
).In you JSP
<link rel="stylesheet" type="text/css" href="/css/my.css?${key.startupTime}">
Pro: no url rewrite stuff anymore. Con: Less optimal (content will be request on restart) but acceptable.
While searching the web for some code that could help to implement the step #2 of option 1, I found Spring's o.s.w.s.ResourceServlet
that is doing something similar, you could look at its source code. But, while reading its javadoc more carefully, I realized that this servlet is actually exactly what you're looking for. Map it like this:
<servlet>
<servlet-name>Resource Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ResourceServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Resource Servlet</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
And set its applyLastModified
property to true
. My understanding of the javadoc is that it should do the trick. This is option 3 and this is IMO the best option if adding a dependency on this servlet in not an issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With