如何使用ClasspathResourceLoader从Velocity模板中#include一个文件 [英] How to #include a file from a Velocity template using ClasspathResourceLoader

查看:872
本文介绍了如何使用ClasspathResourceLoader从Velocity模板中#include一个文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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类,模板和要包含的文件都在同一文件夹testpackage中,所以在生成的JAR中,它们都在同一个包testpackage中。

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".

问题是如果模板包含

#include("MyInclude.vm")

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

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

因为在getTemplate的参数中我必须将包名前缀到模板名称,我也尝试在模板内的#include中做同样的事情:

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:

#include("testpackage/MyInclude.vm")

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

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.

http://velocity.apache.org/engine/releases/velocity- 1.7 / user-guide.html #include 说:


出于安全考虑,要包含的文件可能只是在
下TEMPLATE_ROOT

"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.

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

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).

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

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.

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




TemplateWithoutInclude.vm

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






TemplateWithInclude.vm




TemplateWithInclude.vm

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






MyInclude.vm




MyInclude.vm

<p>
    Hello
</p>






推荐答案

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

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

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

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

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 #include directive: just #include("MyInclude.vm").

我也希望了解一些关于模糊的内容(对我来说) TEMPLATE_ROOT ,和ex一样。它是什么,因为我很难在任何地方找到这些信息。但不管它是什么,至少在我的情况下它对应于Java项目的根包(默认包)。这意味着如果我不使用上面提到的附加属性,那么在根包中放置文件 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.vm in the root package works.

这篇关于如何使用ClasspathResourceLoader从Velocity模板中#include一个文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆