这次主要是因为后期需要在项目里对js和css添加版本号,防止一些缓存的问题。页面比较多,就不能对每个页面引用的js和css添加版本号了,那样太累,对后期的更新也不方便。
你可能专门做了js和css的模板文件,其他页面引入就好了,但是每个页面也有其自己的资源文件,要是加在页面,这个文件你手动换了,另外一个页面忘记了,也都是麻烦。
你也可以增加FreeMarkerView,在里边增加一个自定义的类似${version}的东西,但在每个页面不还得xxx.js?v=${version}吗?太麻烦。
所以我就想,能不能把freemarker获取到的模板文件字符串的时候,用正则给给它加上,这样维护起来也方便。
由于项目时springboot,就拿他当例子搞了。如果你用的spring,直接配置xml会更简单。
直接贴代码了:
首先继承TemplateLoaer类,这个类里边有个getReader方法,是获取模板文件的,我们可以在这里进行加工。
package com.xyauto.qa.core.processor;
import com.xyauto.qa.util.SpringIocUtil;
import com.xyauto.qa.util.TemplateUtils;
import freemarker.cache.TemplateLoader;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
/**
* Created by shiqm on 2017-06-30.
*/
public class ResourceTemplateLoader implements TemplateLoader {
private final TemplateLoader delegate;
public ResourceTemplateLoader(TemplateLoader delegate) {
this.delegate = delegate;
}
@Override
public Object findTemplateSource(String s) throws IOException {
return delegate.findTemplateSource(s);
}
@Override
public long getLastModified(Object o) {
return delegate.getLastModified(o);
}
@Override
public Reader getReader(Object o, String s) throws IOException {
Reader reader = delegate.getReader(o, s);
TemplateUtils templateUtils= (TemplateUtils) SpringIocUtil.getBean("templateUtils");
String content= IOUtils.toString(reader);
content = templateUtils.getScriptSrcList(content);
content = templateUtils.getLinkHrefList(content);
return new StringReader(content);
}
@Override
public void closeTemplateSource(Object o) throws IOException {
delegate.closeTemplateSource(o);
}
}
上边注意需要引入一个工具类,主要是用它把reader转成字符串,当然你也可以根据实现自己写,但要注意原格式必须正确,回车空格不能少。不然浏览器不会有问题,但是你看页面源代码的source肯定是乱的。我比较懒,就直接用工具类走了。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
下一步就将这个类替换freemarker本身的Loader类,在Application运行文件里添加
import freemarker.template.Configuration;
@Bean
public CommandLineRunner customFreemarkerTemplateLoader(Configuration configuration) {
return new CommandLineRunner() {
@Override
public void run(String... strings) throws Exception {
ResourceTemplateLoader resourceTemplateLoader = new ResourceTemplateLoader(configuration.getTemplateLoader());
configuration.setTemplateLoader(resourceTemplateLoader);
}
};
}
看代码就看出来的,从Configuration中取出默认的来,set进去替换就好了。
之后这里贴上正则的方法,有需要的拿去,自己根据需求写也可以。这个只是个思路,做其他需求也可以往这考虑。当然这里用做给资源文件加版本号也有弊端,就是更新的时候会整体更新。没有更改的也会重新加载。因为改的急,我就先这么动了代码。
public String getScriptSrcList(String content) {
Map map = new HashMap();
Pattern p_script = Pattern.compile("(?<=script)(.*?)(?=></script>|/>)");
Matcher m_script = p_script.matcher(content);
while (m_script.find()) {
String temp = m_script.group();
Pattern p_src = Pattern.compile("(?<=src=\")(.*?)(?=\")");
Matcher m_src = p_src.matcher(temp);
while (m_src.find()) {
String tempSrc = m_src.group();
if (tempSrc.indexOf("?v=") > -1) {
continue;
}
if (!StringUtils.isEmpty(map.get(tempSrc))) {
continue;
}
content = content.replace(tempSrc, tempSrc + qcdqcdnStatic.getResourceVersion());
map.put(tempSrc, "1");
}
}
map.clear();
return content;
}
public String getLinkHrefList(String content) {
Map map = new HashMap();
Pattern p_script = Pattern.compile("(?<=link)(.*?)(?=></link>|/>|>)");
Matcher m_script = p_script.matcher(content);
while (m_script.find()) {
String temp = m_script.group();
Pattern p_src = Pattern.compile("(?<=href=\")(.*?)(?=\")");
Matcher m_src = p_src.matcher(temp);
while (m_src.find()) {
String tempSrc = m_src.group();
if (tempSrc.indexOf("?v=") > -1) {
continue;
}
if (!StringUtils.isEmpty(map.get(tempSrc))) {
continue;
}
content = content.replace(tempSrc, tempSrc + qcdqcdnStatic.getResourceVersion());
map.put(tempSrc, "1");
}
}
map.clear();
return content;
}
replace替换那里,我是把版本号控制放在配置文件里的,这个根据自己吧,你直接写也没人管你,不过还是希望透明一些,能让同事看懂。