考虑以下模板:
<#include "../header.txt"/>
<#list items as item>
Item name is: ${item.name}<br/>
</#list>
header.txt
包含的地方:
<html>
<head>
</head>
<body>
我想“预处理”此模板,以便得到的结果是:
<html>
<head>
</head>
<body>
<#list items as item>
Item name is: ${item.name}<br/>
</#list>
我希望能够扩展包含但不解析变量。我怎么能用Freemarker做到这一点?
答案 0 :(得分:1)
FreeMarker不支持这样做(仅解析模板的某些部分)。您可以做的是使用您自己的解析器预处理模板。通过使用您自己的TemplateLoader
实施代表支持另一个TemplateLoader
(原始版本)并过滤内容来支持这一点。因此,当第一次需要模板时,您可以即时应用转换,结果将被缓存(在FreeMarker的标准模板缓存中)。我建议使用你自己的语法(比如<%include '...'>
),这样每个人都会看到那里有特别的东西。
答案 1 :(得分:0)
我最终不得不创建自己的扩展器。我希望它对某人有用:
/**
* Utility class to perform Freemarker template expansion.
*
* @author Chris Mepham
*/
public class FreemarkerTemplateExpander implements ApplicationAware {
static final String INCLUDE_REGEX = "<#include \\\"\\S+\\\"\\/>";
static final String PATH_REGEX = "\\\"\\S+\\\"";
private ModuleStateHolder moduleStateHolder;
/**
* Takes the Freemarker template String input and
*
* recursively expands all of the includes.
*
* @param input The String value of a Freemarker template.
*
* @return The expanded version of the Freemarker template.
*/
public final String expand(String module, String path, String input) {
Assert.notNull(module, "module cannot be null");
Assert.notNull(path, "path cannot be null");
Assert.notNull(input, "input cannot be null");
if (!hasText(input)) return input;
// See if there is an include
int indexOfNextInclude = getIndexOfNextInclude(Pattern.compile(INCLUDE_REGEX), input);
// If there is no include just return the input text
if (indexOfNextInclude == -1) return input;
StringBuffer buffer = new StringBuffer();
// Otherwise, get all the text up to the next include and add it to buffer
String prefix = input.substring(0, indexOfNextInclude);
if (hasText(prefix)) buffer.append(prefix);
// Then get the contents of the include as a String
String includeContents = getIncludeContents(module, path, input);
if (hasText(includeContents)) buffer.append(includeContents);
// Then get all the text after the next include
int includeLastCharacterIndex = indexOfNextInclude + matchRegexPattern(input, INCLUDE_REGEX).length();
String suffix = input.substring(includeLastCharacterIndex + 1);
buffer.append(suffix);
input = buffer.toString();
return expand(module, path, input);
}
final String getIncludeContents(String module, String path1, String input) {
// Get next include file relative path
String nextIncludePath = getNextIncludePath(input);
String resourcePath = getResourcePath(nextIncludePath);
// Get file name
String filename = getFilename(nextIncludePath);
// Get file contents here
String path = "templates." + resourcePath;
InputStream resource = ClasspathResourceUtils.getClassPathResource(path, filename, getClassLoader(module));
StringWriter writer = new StringWriter();
try {
IOUtils.copy(resource, writer, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
return writer.toString();
}
static final int getIndexOfNextInclude(Pattern pattern, String input) {
Matcher matcher = pattern.matcher(input);
return matcher.find() ? matcher.start() : -1;
}
private static final String getNextIncludePath(String input) {
String include = matchRegexPattern(input, INCLUDE_REGEX);
if (include == null) return null;
String path = matchRegexPattern(include, PATH_REGEX);
path = path.replace("\"", "");
return path;
}
private static final String matchRegexPattern(String input, String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
while(matcher.find()) {
return matcher.group(0);
}
return null;
}
private String getResourcePath(String path) {
if (!path.contains("/")) return path;
String resourcePath = path.substring(path.indexOf("/") + 1, path.lastIndexOf("/"));
return resourcePath;
}
private String getFilename(String path) {
if (!path.contains("/")) return path;
return path.substring(path.lastIndexOf("/") + 1);
}
}