【问题标题】:How to #include a file from a Velocity template using ClasspathResourceLoader如何使用 ClasspathResourceLoader #include 来自 Velocity 模板的文件
【发布时间】:2014-03-10 22:05:16
【问题描述】:

我正在处理一些 Java 代码,其中 Velocity 1.7 设置为通过 ClasspathResourceLoader 检索模板。下面是一个精简的代码示例。它来自在 Jetty 服务器上运行的 Tapestry Web 应用程序。

Java 类、模板和要包含的文件都在同一个文件夹“testpackage”中,因此在生成的 JAR 中它们都在同一个包“testpackage”中。

问题是如果模板包含一个

#include("MyInclude.vm")

指令,Velocity 找不到“MyInclude.vm”,并抛出 ResourceNotFoundException。

由于在 getTemplate 的参数中我必须在模板名称前面加上包名,我也尝试在模板内的#include 中做同样的事情:

#include("testpackage/MyInclude.vm")

但唯一的区别是,如果我从 Eclipse 运行 Web 应用程序,后者可以工作,而前者甚至不能从 Eclipse 运行。 如果我构建、部署 JAR 并从部署运行 Web 应用程序,两种语法都会失败并出现相同的 ResourceNotFoundException。

http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html#Include 的 Velocity 文档说:

"出于安全原因,要包含的文件只能在 TEMPLATE_ROOT"

这肯定是我的问题的原因,但我无法找到任何关于 TEMPLATE_ROOT 实际是什么的更多信息。

这听起来很像一个环境变量,但我不知道我应该将它设置为什么,因为我使用的是 ClasspathResourceLoader,并且要包含的文件不是位于文件夹中的实际文件,它是在包含模板和 Java 类的 JAR 中(并且都在同一个包中)。

我发现另一个问题Where should I put Velocity template files for a command line utility built with Maven? 中提到了 TEMPLATE_ROOT,但它与使用 FileResourceLoader 有关。我需要继续使用 ClasspathResourceLoader,并且我需要将所有文件都放在 JAR 中,而不是作为某个文件夹中的普通文件在 JAR 之外。

TestVelocity.java

package testpackage;

import java.io.StringWriter;
import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

public class TestVelocity
{
  public static String getText()
  {
    String text = "";

    Properties properties = new Properties();

    properties.setProperty("resource.loader", "class");

    properties.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");

    VelocityEngine engine = new VelocityEngine();

    VelocityContext context = new VelocityContext();

    StringWriter writer = new StringWriter();

    try
    {
      engine.init(properties);

      // This works because the template doesn't contain any #include
      Template template = engine.getTemplate("testpackage/TemplateWithoutInclude.vm");

      // This causes ResourceNotFoundException: Unable to find resource 'TemplateWithInclude.vm'
      // Template template = engine.getTemplate("testpackage/TemplateWithInclude.vm");

      template.merge(context, writer);

      text = writer.toString();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    return text;
  }
}

TemplateWithoutInclude.vm

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        <p>Hello</p>
    </body>
</html>

TemplateWithInclude.vm

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        #include("MyInclude.vm")
    </body>
</html>

MyInclude.vm

<p>
    Hello
</p>

【问题讨论】:

    标签: java templates velocity


    【解决方案1】:

    再看示例代码,通过向用于初始化引擎的Properties 实例添加一个属性来解决问题:

    properties.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, IncludeRelativePath.class.getName());
    

    这允许将要包含的文件的路径引用为相对于包含模板所在文件夹的路径。因此,如果两个文件都在同一个文件夹中,则无需在 #include 指令中指定路径:只需 #include("MyInclude.vm")

    我还希望了解一些关于(对我而言)晦涩难懂的 TEMPLATE_ROOT,比如前任。它是什么,因为我很难在任何地方找到记录的这些信息。但不管它是什么,至少在我的情况下它对应于 Java 项目的根包(“默认”包)。这意味着如果我不使用上面提到的附加属性,那么将文件MyInclude.vm 放在根包中就可以了。

    【讨论】:

    • 如何包含位于不同目录中的模板?我的 .vm 文件位于文件夹内(例如 mail-templates/template1/1.vm、mail-templates/template2/2.vm)。在 1.vm 我有 #include("../template2/2.vm") 但它抛出 ResourceNotFoundException
    • @vivek241 如果您按照这个答案设置属性并且文件的位置是您所说的,我不知道为什么您显示的语法不起作用。据我记得这个问题,它应该有效。也许尝试将两个文件暂时放在同一个文件夹中,以确保您正确设置了该属性;如果它也不能以这种方式工作,则很可能是该属性设置不正确。
    猜你喜欢
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 2013-07-03
    • 2012-11-09
    • 2017-01-24
    • 1970-01-01
    • 2011-09-28
    • 2022-09-27
    相关资源
    最近更新 更多