如何基于一个 Freemarker 模板创建多个文件
How to create multiple files based on one Freemarker Template
我现在在使用 freemarker 时遇到了一些问题。我基本上想在我的模板中做的事情:遍历元素列表并为每个元素创建一个新文件。
<#assign x=3>
<#list 1..x as i>
${i}
...create a new file with the output of this loop iteration...
</#list>
我在 freemarker 手册或 google 中没有找到任何相关信息。有办法吗?
您不能仅使用 FreeMarker 来执行此操作。它的想法是从您的模板中生成单个输出流。它甚至不关心你是否将结果保存到文件、直接传递给 TCP 套接字、作为字符串存储在内存中或做任何其他事情。
如果你真的想实现这个,你必须自己处理文件分离。例如,您可以插入这样的特殊行:
<#assign x=3>
<#list 1..x as i>
${i}
%%%%File=output${i}.html
...
</#list>
之后你应该 post 自己处理 FreeMarker 输出寻找以 %%%%File=
开头的行并在此时创建一个新文件。
您可以使用自定义指令来实现它。请参阅 freemarker.template.TemplateDirectiveModel
,尤其是 TemplateDirectiveBody
。自定义指令可以指定在其嵌套内容中使用的 Writer
。因此,您可以执行类似 <@output file="...">...</@output>
的操作,其中嵌套内容将写入您在 TemplateDirectiveModel
实现中提供的 Writer
,在本例中应写入指定的文件。 (FMPP 也这样做:http://fmpp.sourceforge.net/qtour.html#sect4)
正如 ddekany 所说,您可以执行指令。我编写了一个小例子:
package spikes;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import freemarker.core.Environment;
import freemarker.template.Configuration;
import freemarker.template.SimpleScalar;
import freemarker.template.Template;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
class OutputDirective implements TemplateDirectiveModel {
@Override
public void execute(
Environment env,
@SuppressWarnings("rawtypes") Map params,
TemplateModel[] loopVars,
TemplateDirectiveBody body)
throws TemplateException, IOException {
SimpleScalar file = (SimpleScalar) params.get("file");
FileWriter fw = new FileWriter(new File(file.getAsString()));
body.render(fw);
fw.flush();
}
}
public class FreemarkerTest {
public static void main(String[] args) throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
cfg.setDefaultEncoding("UTF-8");
JsonObject model = new JsonObject()
.put("entities", new JsonArray()
.add(new JsonObject()
.put("name", "Entity1"))
.add(new JsonObject()
.put("name", "Entity2")));
Template template = new Template("Test", "<#assign model = model?eval_json><#list model.entities as entity><@output file=entity.name + \".txt\">This is ${entity.name} entity\n</@output></#list>", cfg);
Map<String, Object> root = new HashMap<String, Object>();
root.put("output", new OutputDirective());
root.put("model", model.encode());
Writer out = new OutputStreamWriter(System.out);
template.process(root, out);
}
}
这将生成两个文件:
"Entity1.txt":这是 Entity1 实体
"Entity2.txt": 这是 Entity2 实体
:-)
我现在在使用 freemarker 时遇到了一些问题。我基本上想在我的模板中做的事情:遍历元素列表并为每个元素创建一个新文件。
<#assign x=3>
<#list 1..x as i>
${i}
...create a new file with the output of this loop iteration...
</#list>
我在 freemarker 手册或 google 中没有找到任何相关信息。有办法吗?
您不能仅使用 FreeMarker 来执行此操作。它的想法是从您的模板中生成单个输出流。它甚至不关心你是否将结果保存到文件、直接传递给 TCP 套接字、作为字符串存储在内存中或做任何其他事情。
如果你真的想实现这个,你必须自己处理文件分离。例如,您可以插入这样的特殊行:
<#assign x=3>
<#list 1..x as i>
${i}
%%%%File=output${i}.html
...
</#list>
之后你应该 post 自己处理 FreeMarker 输出寻找以 %%%%File=
开头的行并在此时创建一个新文件。
您可以使用自定义指令来实现它。请参阅 freemarker.template.TemplateDirectiveModel
,尤其是 TemplateDirectiveBody
。自定义指令可以指定在其嵌套内容中使用的 Writer
。因此,您可以执行类似 <@output file="...">...</@output>
的操作,其中嵌套内容将写入您在 TemplateDirectiveModel
实现中提供的 Writer
,在本例中应写入指定的文件。 (FMPP 也这样做:http://fmpp.sourceforge.net/qtour.html#sect4)
正如 ddekany 所说,您可以执行指令。我编写了一个小例子:
package spikes;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import freemarker.core.Environment;
import freemarker.template.Configuration;
import freemarker.template.SimpleScalar;
import freemarker.template.Template;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
class OutputDirective implements TemplateDirectiveModel {
@Override
public void execute(
Environment env,
@SuppressWarnings("rawtypes") Map params,
TemplateModel[] loopVars,
TemplateDirectiveBody body)
throws TemplateException, IOException {
SimpleScalar file = (SimpleScalar) params.get("file");
FileWriter fw = new FileWriter(new File(file.getAsString()));
body.render(fw);
fw.flush();
}
}
public class FreemarkerTest {
public static void main(String[] args) throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
cfg.setDefaultEncoding("UTF-8");
JsonObject model = new JsonObject()
.put("entities", new JsonArray()
.add(new JsonObject()
.put("name", "Entity1"))
.add(new JsonObject()
.put("name", "Entity2")));
Template template = new Template("Test", "<#assign model = model?eval_json><#list model.entities as entity><@output file=entity.name + \".txt\">This is ${entity.name} entity\n</@output></#list>", cfg);
Map<String, Object> root = new HashMap<String, Object>();
root.put("output", new OutputDirective());
root.put("model", model.encode());
Writer out = new OutputStreamWriter(System.out);
template.process(root, out);
}
}
这将生成两个文件:
"Entity1.txt":这是 Entity1 实体
"Entity2.txt": 这是 Entity2 实体
:-)