由于效率的缘故,浏览器通常会缓存js文件,这就给我们带了一个问题:当服务器端部署的项目中的js文件进行了修改后,如果再客户端不手动去刷新一次页面,js的修改效果就不会起作用,因为浏览器还是用的缓存在本地的js文件。
为了解决这个问题,我们采用了这个方案,每当发布新的版本部署到服务器上的时候,我们给html页面中引用的js增加一个新的后缀,形如版本号的东西。
<script language="javascript" src="view/shell/login.js?version=20081112050245"></script>
为了自动完成这一功能,我们使用了ant,写了一个ant task来完成该项功能。
/**
* 该任务遍历web目录,找出所有的模板文件,给js和css的引用加上版本号
*
* @version 1.0 2008-07-02
* @author huangyuanmu
* @since JDK 1.5.0_8
*/
public class AddJsAndCssVersionToVm extends Task {
private String path;
public void execute() throws BuildException {
Date date = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
String version = df.format(date);
addVersionToVm(path, version);
}
/**
* 遍历web目录中的vm文件,给js和css的引用加上版本号
*
* @author huangyuanmu 2008-07-02
* @param path
*/
private void addVersionToVm(String path, String version) {
File dir = new File(path);
File[] files = dir.listFiles();
if (files == null)
return;
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
addVersionToVm(files[i].getAbsolutePath(), version);
} else {
String strFileName = files[i].getAbsolutePath().toLowerCase();
// 如果是符合条件的文件,则添加版本信息
if (strFileName.endsWith(".vm")
|| strFileName.endsWith(".html")
|| strFileName.endsWith(".jsp")) {
// RandomAccessFile raf = null;
InputStream is = null;
OutputStream os = null;
List<String> contentList = new ArrayList<String>();
// 读文件
try {
is = new FileInputStream(files[i]);
Reader r = new InputStreamReader(is);
BufferedReader br = new BufferedReader(r);
String line = null;
while ((line = br.readLine()) != null) {
String modLine = getModLine(line, version);
if (modLine != null) {
line = modLine;
}
line = line + "\r\n";
contentList.add(line);
}
// 关闭流
br.close();
r.close();
} catch (Exception e) {
System.out.println("读文件失败");
e.printStackTrace();
} finally {
if (null != is) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 写文件
try {
os = new FileOutputStream(files[i]);
Writer w = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(w);
for (Iterator<String> it = contentList.iterator(); it
.hasNext();) {
String line = it.next();
bw.write(line);
}
// 更新到文件
bw.flush();
// 关闭流
bw.close();
w.close();
} catch (Exception e) {
System.out.println("写文件失败");
e.printStackTrace();
} finally {
if (null != os) {
try {
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
/**
* 查找行中是否有js或css的引用,如果有,则加上版本号
*
* @author huangyuanmu 2008-07-03
* @param line
*/
private String getModLine(String line, String version) {
// 增加js版本
line.trim();
if (line.startsWith("<script") && line.endsWith("</script>")) {
int pos = line.indexOf(".js");
String modLine = line.substring(0, pos) + ".js?version="
+ version + "\"></script>";
return modLine;
} else if (line.startsWith("<link")
&& line.endsWith("rel=\"stylesheet\" type=\"text/css\">")) {
int pos = line.indexOf(".css");
String modLine = line.substring(0, pos) + ".css?version="
+ version
+ "\" rel=\"stylesheet\" type=\"text/css\">";
return modLine;
} else {
return null;
}
}
public void setPath(String path) {
this.path = path;
}
}
当然,这个程序的实现还有一些缺点。首先,模板文件中对js和css的引用必须规范,符合程序代码中描述的格式。另外,不管文件内容有没有改变,都加上了新的版本号,这会用户访问时不必要的网络流量,可能会对页面展现的速度产生一些影响。
ant的build脚本文件在另外一篇中(http://huangyuanmu.iteye.com/admin/blogs/493144)。