我正在尝试使用FreeMarker来呈现来自CMS路径的一些模板,这些模板恰好包含符号链接(在Linux下)。我们的CMS代码处理模板的路径,例如,此路径:
/var/cms/live/display/main.html
真指出:
/var/cms/trunk/127/display/main.html
/var/cms/live
是基本目录,而/display/main.html
是路径。
就我而言,live
是一个符号链接 - 在本例中是trunk/127
。仅供参考:主干是我们的SVN分支。当我们的CMS系统下载新版本的CMS文件(例如)trunk-128.zip
时,它会将其解压缩到trunk/128
,然后将符号链接(原子地)更改为trunk/128
。大。
问题是FreeMarker似乎缓存了trunk/127
路径。它无法识别文件/var/cms/live/display/main.html
已更新,如果删除trunk/127
树,则会生成500错误。
500 Unable to load template: /display/main.html
如何让FreeMarker缓存正确的路径?
答案 0 :(得分:2)
问题原来是FreeMarker的FileTemplateLoader
课程。它对传递给构造函数的基目录进行baseDir.getCanonicalFile(...)
调用。当我们的应用程序启动时,基本目录/var/cms/live
将被/var/cms/trunk/127/
解析为真实路径getCanonicalFile(...)
,因此将忽略对符号链接的任何未来更改。
它在构造函数中执行此操作,因此我们不得不创建自己的LocalFileTemplateLoader
,如下所示。
它只是TemplateLoader
的基本弹簧加载实现。然后,当我们构建FreeMarker配置时,我们设置了模板加载器:
Configuration config = new Configuration();
LocalTemplateLoader loader = new LocalTemplateLoader();
// this is designed for spring
loader.setBaseDir("/var/cms/live");
config.setTemplateLoader(loader);
...
这是我们的LocalFileTemplateLoader
代码。 Full class on pastebin:
public class LocalFileTemplateLoader implements TemplateLoader {
public File baseDir;
@Override
public Object findTemplateSource(String name) {
File source = new File(baseDir, name);
if (source.isFile()) {
return source;
} else {
return null;
}
}
@Override
public long getLastModified(Object templateSource) {
if (templateSource instanceof File) {
return new Long(((File) templateSource).lastModified());
} else {
throw new IllegalArgumentException("templateSource is an unknown type: " + templateSource.getClass());
}
}
@Override
public Reader getReader(Object templateSource, String encoding) throws IOException {
if (templateSource instanceof File) {
return new InputStreamReader(new FileInputStream((File) templateSource), encoding);
} else {
throw new IllegalArgumentException("templateSource is an unknown type: " + templateSource.getClass());
}
}
@Override
public void closeTemplateSource(Object templateSource) {
// noop
}
@Required
public void setBaseDir(File baseDir) {
this.baseDir = baseDir;
// it may not exist yet because CMS is going to download and create it
}
}