Java 如何使用 ClasspathResourceLoader #include Velocity 模板中的文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21730335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:23:40  来源:igfitidea点击:

How to #include a file from a Velocity template using ClasspathResourceLoader

javatemplatesvelocity

提问by SantiBailors

I'm dealing with some Java code where Velocity 1.7 is set to retrieve templates through the ClasspathResourceLoader. Below is a stripped down sample of the code. It's from a Tapestry web application running on a Jetty server.

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

The Java class, the templates and the file to be included are all are in the same folder "testpackage", so in the resulting JAR they are all in the same package "testpackage".

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

The problem is that if the template contains an

问题是,如果模板包含

#include("MyInclude.vm")

directive, Velocity cannot find "MyInclude.vm", and it throws a ResourceNotFoundException.

指令,Velocity 找不到“MyInclude.vm”,它会抛出一个 ResourceNotFoundException。

Since in the argument of getTemplate I must prepend the package name to the template name, I also tried to do the same in the #include inside the template:

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

#include("testpackage/MyInclude.vm")

but the only difference is that the latter works if I run the web app from Eclipse, while the former doesn't work not even from Eclipse. If I build, deploy the JARs and run the web app from the deployment, both syntaxes fail with the same ResourceNotFoundException.

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

The Velocity doc at http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html#Includesays:

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

"For security reasons, the file to be included may only be under TEMPLATE_ROOT"

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

This definitely could be the cause of my problem, but I haven't been able to find any further information about what TEMPLATE_ROOT actually is.

这绝对可能是我的问题的原因,但我无法找到有关 TEMPLATE_ROOT 实际是什么的任何进一步信息。

It sounds a lot like an environment variable, but I don't know what I should set it to, since I'm using a ClasspathResourceLoader, and the file to be included is not an actual file located in a folder, it's inside the JAR containing the templates and the Java class (and all in the same package).

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

I found TEMPLATE_ROOT mentioned in another question, Where should I put Velocity template files for a command line utility built with Maven?, but it's related to using a FileResourceLoader. I need to keep using the ClasspathResourceLoader and I need all the files to be in the JAR, not outside it as normal files in some folder.

我发现在另一个问题中提到了 TEMPLATE_ROOT,我应该将使用 Maven 构建的命令行实用程序的 Velocity 模板文件放在哪里?,但它与使用 FileResourceLoader 有关。我需要继续使用 ClasspathResourceLoader 并且我需要所有文件都在 JAR 中,而不是像某些文件夹中的普通文件那样在它之外。

TestVelocity.java

测试速度.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

不包含模板.vm

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


TemplateWithInclude.vm

包含模板的.vm

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


MyInclude.vm

我的包含文件

<p>
    Hello
</p>


采纳答案by SantiBailors

Re the sample code, the problem is solved by adding one more property to the Propertiesinstance used to initialize the engine:

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

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

This allows to reference the path of the file to be included as a path relative to the folder where the including template is. So if both files are in the same folder then no path needs to be specified in the #includedirective: just #include("MyInclude.vm").

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

I was also hoping to learn something about the obscure (to me) TEMPLATE_ROOT, like for ex. what it is, since it is surprisingly difficult for me to find this info documented anywhere. But whatever it is, at least in my case it corresponds to the root package of the Java project (the "default" package). This means that if I don't use the additional property mentioned above, then placing the file MyInclude.vmin the root package works.

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