如何将字符串作为Velocity模板使用?

66

如何从字符串创建Velocity模板是最佳方式?

我知道可以使用Velocity.evaluate方法传递String或StringReader来实现,但我想知道是否有更好的方法(例如创建Template实例有什么优势)。

7个回答

88

解析模板会有一些开销。如果你的模板很大并且需要重复使用,预先解析模板可能会带来性能提升。你可以像这样操作:

RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(bufferForYourTemplate);
Template template = new Template();
template.setRuntimeServices(runtimeServices);

/*
 * The following line works for Velocity version up to 1.7
 * For version 2, replace "Template name" with the variable, template
 */
template.setData(runtimeServices.parse(reader, "Template name")));

template.initDocument();

然后,您可以反复调用template.merge()而无需每次解析它。

顺便说一句,您可以直接将字符串传递给Velocity.evaluate()


正是我所需要的。谢谢。 供其他人参考,runtimeServices 是 org.apache.velocity.runtime.RuntimeInstance 的一个实例。 - tomsame
漏掉了一行代码,为了完整性,我添加了它。 - ZZ Coder
17
谢谢提到Velocity.Evaluate,这正是我在寻找的。 - Bernhard Hofmann
编译错误是由于括号过多导致的。应该是 template.setData(runtimeServices.parse(reader, "模板名称")); StackOverflow 抱怨 编辑必须至少为 6 个字符;在此帖子中是否有其他可以改进的内容? - joseph

21

上述示例代码对我有效。它使用Velocity版本1.7和log4j。

private static void velocityWithStringTemplateExample() {
    // Initialize the engine.
    VelocityEngine engine = new VelocityEngine();
    engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.Log4JLogChute");
    engine.setProperty("runtime.log.logsystem.log4j.logger", LOGGER.getName());
    engine.setProperty(Velocity.RESOURCE_LOADER, "string");
    engine.addProperty("string.resource.loader.class", StringResourceLoader.class.getName());
    engine.addProperty("string.resource.loader.repository.static", "false");
    //  engine.addProperty("string.resource.loader.modificationCheckInterval", "1");
    engine.init();

    // Initialize my template repository. You can replace the "Hello $w" with your String.
    StringResourceRepository repo = (StringResourceRepository) engine.getApplicationAttribute(StringResourceLoader.REPOSITORY_NAME_DEFAULT);
    repo.putStringResource("woogie2", "Hello $w");

    // Set parameters for my template.
    VelocityContext context = new VelocityContext();
    context.put("w", "world!");

    // Get and merge the template with my parameters.
    Template template = engine.getTemplate("woogie2");
    StringWriter writer = new StringWriter();
    template.merge(context, writer);

    // Show the result.
    System.out.println(writer.toString());
}

一个类似的问题,在这里


哇,这是一种独特的方法。Velocity引擎如何加载资源似乎是内部实现,属性"string.resource.loader.class"是否可能会发生变化? - Ben.Yan

9

这适用于Velocity 2.1

// Initialize the engine
VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(Velocity.RESOURCE_LOADERS, "string");
velocityEngine.setProperty("resource.loader.string.class", StringResourceLoader.class.getName());
velocityEngine.setProperty("resource.loader.string.cache", true);
velocityEngine.setProperty("resource.loader.string.modification_check_interval", 60);
velocityEngine.init();

// Add template to repository
StringResourceRepository repository = StringResourceLoader.getRepository();
repository.putStringResource("hello_world", "Hello $w");

// Set parameters
VelocityContext context = new VelocityContext();
context.put("w", "world!");

// Process the template
StringWriter writer = new StringWriter();
velocityEngine.getTemplate("hello_world").merge( context, writer );

System.out.println(writer.toString());

1
你在 Velocity.RESOURCE_LOADERS 中似乎有一个拼写错误 - 可能应该是 Velocity.RESOURCE_LOADER - vektor
RuntimeConstants 接口由 Velocity 类实现,其中包含两个常量 - RESOURCE_LOADERSRESOURCE_LOADER。我测试过的是 RESOURCE_LOADERS - devatherock
这个方法在一段时间内对我有效。但后来我在日志文件中发现了内部Velocity异常。我改用以下解决方案,现在一切都正常了:Java中的Velocity模板字符串。它使用了Velocity#evaluate(context, out, logTag, instring),正如另一个答案中提到的那样。 - ltlBeBoy

2
RuntimeServices rs = RuntimeSingleton.getRuntimeServices();            
StringReader sr = new StringReader("Username is $username");
SimpleNode sn = rs.parse(sr, "User Information");

Template t = new Template();
    t.setRuntimeServices(rs);
    t.setData(sn);
    t.initDocument();

VelocityContext vc = new VelocityContext();
vc.put("username", "John");

StringWriter sw = new StringWriter();
t.merge(vc, sw);

System.out.println(sw.toString());

1
如果您只是在寻找变量替换,则以下内容适用。
public String velocityEvaluate(final String template, final NotificationDTO notificationDTO) {
    final Map<String, String> context = getContextMap(notificationDTO);
    final VelocityContext velocityContext = new VelocityContext(context);
    final StringWriter stringWriter = new StringWriter();
    final StringReader reader = new StringReader(template);
    Velocity.evaluate(velocityContext, stringWriter, "Velocity String Template Evaluation", reader);
    return stringWriter.toString();
}

1

Velocity 2可以集成到JSR223 Java Scripting Language Framework中,这使得将字符串转换为模板的另一个选项变得可能:

ScriptEngineManager manager = new ScriptEngineManager();
manager.registerEngineName("velocity", new VelocityScriptEngineFactory());
ScriptEngine engine = manager.getEngineByName("velocity");


System.setProperty(VelocityScriptEngine.VELOCITY_PROPERTIES, "path/to/velocity.properties");
String script = "Hello $world";
Writer writer = new StringWriter();
engine.getContext().setWriter(writer);
Object result = engine.eval(script);
System.out.println(writer);

0

如果有人想要将JSON字符串转换为JSON对象,那么需要将JSON字符串转换为JsonNode并将其存储在上下文中。

例如:

String jsonDataAsString = "{"name": "Aps"}";
JsonNode nodes = new ObjectMapper().readTree(jsonDataAsString );
VelocityContext velocityContext = new VelocityContext();
velocityContext.put("root", nodes);

然后在您的模板中,您可以通过"$root."+属性引用被设置为"root"的原始数据

$root.name

希望能对某些人有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接