web-dev-qa-db-fra.com

Comment #inclure un fichier d'un modèle Velocity à l'aide de ClasspathResourceLoader

J'ai affaire à du code Java où Velocity 1.7 est configuré pour récupérer des modèles via ClasspathResourceLoader. Ci-dessous, un exemple de code simplifié. Il provient d'une application Web Tapestry exécutée sur un serveur Jetty. .

La classe Java, les modèles et le fichier à inclure sont tous dans le même dossier "testpackage", donc dans le JAR résultant, ils sont tous dans le même package "testpackage".

Le problème est que si le modèle contient un

#include("MyInclude.vm")

directive, Velocity ne peut pas trouver "MyInclude.vm", et il lève une ResourceNotFoundException.

Étant donné que dans l'argument de getTemplate, je dois ajouter le nom du package au nom du modèle, j'ai également essayé de faire de même dans le #include à l'intérieur du modèle:

#include("testpackage/MyInclude.vm")

mais la seule différence est que ce dernier fonctionne si j'exécute l'application Web depuis Eclipse, tandis que le premier ne fonctionne même pas depuis Eclipse. Si je crée, déploie les JAR et exécute l'application Web à partir du déploiement, les deux syntaxes échouent avec la même ResourceNotFoundException.

Le document Velocity sur http://velocity.Apache.org/engine/releases/velocity-1.7/user-guide.html#Include dit:

"Pour des raisons de sécurité, le fichier à inclure ne peut être que sous TEMPLATE_ROOT"

Cela pourrait certainement être la cause de mon problème, mais je n'ai pas été en mesure de trouver plus d'informations sur ce qu'est réellement TEMPLATE_ROOT.

Cela ressemble beaucoup à une variable d'environnement, mais je ne sais pas à quoi je dois le définir, car j'utilise un ClasspathResourceLoader, et le fichier à inclure n'est pas un fichier réel situé dans un dossier, il est à l'intérieur du JAR contenant les modèles et la classe Java (et tous dans le même package).

J'ai trouvé TEMPLATE_ROOT mentionné dans une autre question, Où dois-je mettre les fichiers de modèle Velocity pour un utilitaire de ligne de commande construit avec Maven? , mais il est lié à l'utilisation d'un FileResourceLoader. Je dois continuer à utiliser le ClasspathResourceLoader et j'ai besoin que tous les fichiers soient dans le JAR, pas à l'extérieur comme des fichiers normaux dans un dossier.

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

Concernant l'exemple de code, le problème est résolu en ajoutant une propriété supplémentaire à l'instance Properties utilisée pour initialiser le moteur:

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

Cela permet de référencer le chemin du fichier à inclure comme chemin relatif au dossier où se trouve le modèle d'inclusion. Donc, si les deux fichiers sont dans le même dossier, aucun chemin ne doit être spécifié dans la directive #include: Juste #include("MyInclude.vm").

J'espérais aussi apprendre quelque chose sur l'obscur (pour moi) TEMPLATE_ROOT, Comme par exemple. ce que c'est, car il est étonnamment difficile pour moi de trouver cette information documentée n'importe où. Mais quoi qu'il en soit, au moins dans mon cas, il correspond au package racine du projet Java) (le package "par défaut"). Cela signifie que si je n'utilise pas la propriété supplémentaire mentionnée ci-dessus, puis placer le fichier MyInclude.vm dans le package racine fonctionne.

20
SantiBailors