[英]Is it possible to “pre-process” Freemarker templates?
考虑以下模板:
<#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做到这一点?
FreeMarker不支持这样做(仅解决模板的某些部分)。 您可以做的是使用自己的解析器预处理模板。 通过使用您自己的TemplateLoader
实现(将其委派给另一个TemplateLoader
(原始的)并过滤内容)来支持该功能。 因此,当您第一次需要模板时,您可以即时应用转换,并且结果将被缓存(在FreeMarker的标准模板缓存中)。 我建议您使用自己的语法(例如<%include '...'>
),以便每个人都可以看到特殊的内容。
我最终不得不创建自己的扩展器。 我希望这对某人有用:
/**
* 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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.