我正在处理一些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,并且要包含的文件不是文件夹中的实际文件,因此它位于JAR内包含模板和Java类(并且都在同一包中)。
我发现在另一个问题中提到了TEMPLATE_ROOT,对于使用Maven构建的命令行实用程序,应该将Velocity模板文件放在哪里?,但与使用FileResourceLoader有关。我需要继续使用ClasspathResourceLoader,我需要所有文件都放在JAR中,而不是像某些文件夹中的普通文件一样位于JAR之外。
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; } }
<!DOCTYPE html> <html> <head></head> <body> <p>Hello</p> </body> </html>
<!DOCTYPE html> <html> <head></head> <body> #include("MyInclude.vm") </body> </html>
<p> Hello </p>
返回示例代码,可通过在Properties用于初始化引擎的实例中添加更多属性来解决该问题:
Properties
properties.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, IncludeRelativePath.class.getName());
这允许引用要包含的文件的路径,作为相对于包含模板所在文件夹的路径。因此,如果两个文件都在同一文件夹中,则无需在#include指令中指定路径:just #include("MyInclude.vm")。
#include
我也希望(对我)了解一些晦涩难懂的东西(例如对我来说)TEMPLATE_ROOT。是什么,因为我很难在任何地方找到记录的信息。但是无论如何,至少在我看来,它对应于Java项目的根软件包(“默认”软件包)。这意味着如果我不使用上面提到的其他属性,则将文件MyInclude.vm放在根包中即可。
TEMPLATE_ROOT
MyInclude.vm