在 Apache FreeMarker 中,如何获取包含当前
.ftl
文件的目录的绝对路径?
例如,如果我正在处理文件
/path/to/template.ftl
,那么我正在寻找一种方法将 /path/to
放入 /path/to/template.ftl
中。
我已经尝试过
.current_template_name
和朋友,但这些实际上只包含文件的名称,而不是它的绝对路径(我可以从中获取父目录)。我也尝试过 absolute_template_name ,但这似乎只是在名称前面加上 /
以使路径看起来是绝对的,但它并没有解析为真正的绝对路径。
背景:我正在使用 Freemarker 模板化 Asciidoc 文件,并且 Asciidoc 文件必须包含驻留在
.flt
文件的原始目录下的其他 Asciidoc 文件,因此不得相对于临时“扩展”Asciidoc 文件搜索它们.
模板使用的模板路径始终是虚拟的,并由
TemplateLoader
中设置的 Configuration
对象解析。 TemplateLoader
只是一个接口,有多种实现,对于FreeMarker来说也是一个黑盒子。模板的实际位置可以在 jar 文件内,甚至可以在数据库表中,因此通常模板在文件系统上没有路径。
通常,您设置
TemplateLoader
,以便它可以访问您需要的所有模板。那么你不需要任何技巧,只需使用模板路径即可。
另一种可能性是使用
FileTemplateLoader
将根目录用作基目录。对于大多数应用程序来说,这当然是一个坏主意(特别是出于安全原因,对于 Web 应用程序)。
请务必阅读已接受答案中的解释,因为您很可能还需要其他内容。话虽如此,您可以使用反射深入了解 freemarker 的内部工作原理。以下代码获取给定 templateName 的绝对路径。
private String getAbsolutePath(String inputFilePath, Configuration freeMarkerConfiguration) {
String absolutePath = null;
try {
TemplateCache templateCache = getField(freeMarkerConfiguration, "cache", TemplateCache.class);
Locale locale = freeMarkerConfiguration.getLocale();
TemplateLookupResult lookup = callMethod(templateCache, "lookupTemplate", TemplateLookupResult.class, new Object[] {inputFilePath, locale, null});
Object templateSource = callMethod(lookup, "getTemplateSource", Object.class, new Object[] {});
File source = getField(templateSource, "source", File.class);
absolutePath = source.getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
}
return absolutePath;
}
private <T> T callMethod(Object source, String methodName, Class<T> claz, Object[] methodInput)
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?>[] inputTypes = Arrays.asList(methodInput).stream().map(t -> t == null ? Object.class : t.getClass()).toArray(Class[]::new);
return callMethod(source, methodName, claz, methodInput, inputTypes);
}
private <T> T callMethod(Object source, String methodName, Class<T> claz, Object[] methodInput, Class<?>[] inputTypes)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Method method = source.getClass().getDeclaredMethod(methodName, inputTypes);
method.setAccessible(true);
Object result = method.invoke(source, methodInput);
return claz.cast(result);
}
private <T> T getField(Object source, String fieldName, Class<T> claz)
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Field field = source.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(source);
return claz.cast(value);
}