web-dev-qa-db-ja.com

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のドキュメントは次のように述べています:

「セキュリティ上の理由により、含まれるファイルはTEMPLATE_ROOTの下にのみ存在する可能性があります」

これが間違いなく私の問題の原因である可能性がありますが、TEMPLATE_ROOTが実際に何であるかについて、これ以上の情報を見つけることができませんでした。

それは環境変数のように聞こえますが、ClasspathResourceLoaderを使用しているため、何に設定すべきかわかりません。インクルードされるファイルは、フォルダーにある実際のファイルではなく、JAR内にあります。テンプレートとJavaクラス(およびすべて同じパッケージ内))を含みます。

別の質問で言及されているTEMPLATE_ROOTを見つけました Mavenで構築されたコマンドラインユーティリティのVelocityテンプレートファイルはどこに置くべきですか? ですが、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>

18
SantiBailors

サンプルコードについては、エンジンの初期化に使用するPropertiesインスタンスにプロパティをもう1つ追加することで問題が解決します。

_properties.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, IncludeRelativePath.class.getName());
_

これにより、インクルードするテンプレートがあるフォルダーからの相対パスとして、インクルードするファイルのパスを参照できます。したがって、両方のファイルが同じフォルダーにある場合、_#include_ディレクティブでパスを指定する必要はありません。#include("MyInclude.vm")だけです。

私はまた、(たとえば)_TEMPLATE_ROOT_のあいまいさについて何かを学びたいと思っていました。どこに文書化されているこの情報を見つけるのは驚くほど難しいので、それは何ですか。しかし、それが何であれ、少なくとも私の場合はJavaプロジェクト(「デフォルト」パッケージ)のルートパッケージに対応します。これは、前述の追加のプロパティを使用しない場合上記の場合、ルートパッケージにファイル_MyInclude.vm_を配置すると機能します。

20
SantiBailors