Struts2 – Maven – SVN – Comment éviter les problèmes de cache des ressources statiques lors des changements de version ?

De iMDEO dans Technique

14 juin 2012

Introduction

Cette article traite de la problématique du cache des navigateurs web sur les ressources statiques (css, js,…) alors que de nouvelles versions de celles-ci sont disponibles sur le serveur d’application. La solution présentée rajoute le numéro de révision SVN dans l’url d’accès aux ressources statiques. Cette solution permet d’avoir une url unique par ressource et par version.

Rajout de la révision SVN dans le build

2 étapes sont nécessaires :

  • Rajouter le numéro de révision dans les variables Maven
  • Inclure cette variable dans le build

Ces deux étapes s’effectuent en modifiant le fichier pom.xml du project war.

Rajout du numéro de révision dans les variables Maven

<plugin>

<groupId>org.codehaus.mojo</groupId>

<artifactId>buildnumber-maven-plugin</artifactId>

<executions>

<execution>

<phase>validate</phase>

<goals>

<goal>create</goal>

</goals>

</execution>

</executions>

<configuration>

<doCheck>false</doCheck>

<doUpdate>true</doUpdate>

</configuration>

</plugin>

Inclure cette variable dans le build

<plugin>

<artifactId>maven-war-plugin</artifactId>

<configuration>

<archive>

<manifestEntries>

<SCM-Revision>${buildNumber}</SCM-Revision>

</manifestEntries>

</archive>

</configuration>

</plugin>

Après cette opération le fichier /META-INF/MANIFEST.MF contient :

  • Manifest-Version: 1.0
  • Archiver-Version: Plexus Archiver
  • Created-By: Apache Maven
  • Built-By: XXXXX Build-Jdk: 1.6.0_30
  • SCM-Revision: 48249

Rajout du buildNumber dans la stack Struts 2

Cette opération ce fait par le biais d’un Interceptor.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletContext;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.opensymphony.xwork2.util.ValueStack;
public class BuildNumberInterceptor implements Interceptor {
@Autowired
ServletContext context;
private static final long serialVersionUID = -8274215226312625137L;
private final Logger LOG = Logger.getLogger(getClass());
private static final String SCMprefix = "SCM-Revision: ";
public static final String buildNumber = "buildNumber";
private String _buildNumber;
@Override
public void destroy() {
}
@Override
public void init() {
//Init the non cached path for the static resources
InputStream inputStream = context.getResourceAsStream("/META-INF/MANIFEST.MF");
if(inputStream != null) {
_buildNumber = getBuildFromManifest(inputStream);
}
/*
* The SCM-Revision is not present in dev environment.
* So we generate a random number...
*/
if(_buildNumber == null || StringUtils.isBlank(_buildNumber)) {
_buildNumber = Integer.toString(new Double(Math.ceil(Math.random()*100000)).intValue());
LOG.info("Build number random: " + _buildNumber);
}
else {
LOG.info("Build number from MANIFEST.MF: " + _buildNumber);
}
}
protected String getBuildFromManifest(InputStream inputStream) {
try {
List&lt;String&gt; lines = IOUtils.readLines(inputStream);
for(String line : lines ) {
if(line.startsWith(SCMprefix)) {
return line.substring(SCMprefix.length());
}
}
} catch (IOException e) {
LOG.error("Error getting Build from Manifest",e);
}
return null;
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ValueStack stack = ActionContext.getContext().getValueStack();
stack.set(BuildNumberInterceptor.buildNumber, _buildNumber);
return invocation.invoke();
}
}

Cette Interceptor charge le buildNumber à l’initialisation et le met dans la value stack à chaque appel. N’oubliez pas de déclarer cette Interceptor dans l’interceptor-stack pour que celui-ci soit appelé systématiquement.

Modification des liens des ressources statiques

Modifier vos liens vers les ressources statiques comme dans l’exemple suivant:

<script type=”text/javascript” src=”<%=request.getContextPath()%>/javascripts/pages/secure/dashboard.js?build=<s:property value=”buildNumber”/>“>

Conclusion

A chaque nouveau déploiement,  le buildNumber sera différent et vos ressources statiques automatiquement rechargées par le navigateur. On pourra perfectionner l’insertion des liens vers les ressources statiques par le biais d’une balise spécifique.

Commentaire

× 5 = quarante cinq

iMDEO recrute !

REJOIGNEZ-NOUS

A la recherche de nouveaux talents (développeurs web et mobile, chefs de projet,...)

Voir les annonces