如何使用ClasspathResourceLoader从Velocity模板中#include一个文件

我正在处理一些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 doc说:

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

这肯定可能是我的问题的原因,但我还没有找到任何关于TEMPLATE_ROOT实际上是什么的进一步信息。

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

我在另一个问题中找到了TEMPLATE_ROOT, 我应该在哪里为使用Maven构建的命令行实用程序放置Velocity模板文件? ,但它与使用FileResourceLoader有关。 我需要继续使用ClasspathResourceLoader,我需要所有文件都在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

     

Hello


TemplateWithInclude.vm

     #include("MyInclude.vm")   

MyInclude.vm

 

Hello


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

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

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

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