2010-05-28 4 views
41

J'ai un projet dans lequel je veux charger un modèle de vélocité pour le compléter avec des paramètres. L'application entière est empaquetée en tant que fichier jar. Ce que je pensais initialement faire était:Chargement d'un modèle de vélocité dans un fichier jar

VelocityEngine ve = new VelocityEngine(); 

    URL url = this.getClass().getResource("/templates/"); 

    File file = new File(url.getFile()); 

    ve = new VelocityEngine(); 
    ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "file"); 
    ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, file.getAbsolutePath()); 
    ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true"); 

    ve.init(); 

    VelocityContext context = new VelocityContext(); 

    if (properties != null) { 
    stringfyNulls(properties); 
    for (Map.Entry<String, Object> property : properties.entrySet()) { 
    context.put(property.getKey(), property.getValue()); 
    } 
    } 

    final String templatePath = templateName + ".vm"; 
    Template template = ve.getTemplate(templatePath, "UTF-8"); 
    String outFileName = File.createTempFile("report", ".html").getAbsolutePath(); 
    BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outFileName))); 

    template.merge(context, writer); 

    writer.flush(); 
    writer.close(); 

Et cela fonctionne très bien quand je l'exécute en éclipse. Cependant, une fois que j'ai empaqueté le programme et essaye de l'exécuter en utilisant la ligne de commande j'obtiens une erreur parce que le dossier n'a pas pu être trouvé.

Je suppose que le problème est dans cette ligne:

ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, file.getAbsolutePath()); 

Parce que dans un pot absolu du fichier n'existe pas, car il est à l'intérieur d'un zip, mais je ne pouvais pas encore trouver une meilleure façon de le faire .

Quelqu'un a des idées?

+2

pour l'amour de Dieu, mettre en évidence le code dans votre message et cliquez sur le bouton de code afin qu'il soit correctement formaté! :) – vicatcu

+0

Êtes-vous certain que le répertoire/templates/est exporté dans votre jar? Vous devez le marquer dans le cadre de vos paramètres de construction et d'autres choses. – vicatcu

+0

ne savait pas sur le bouton de code, merci. Oui, le répertoire templates est dans le fichier jar. – Rafael

Répondre

67

Si vous souhaitez utiliser les ressources de classpath, vous devez utiliser chargeur de ressources pour classpath:

ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); 
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); 
+0

Je vais le tester! Savez-vous où je peux trouver de la documentation pour chaque RuntimeContants et ses valeurs possibles? – Rafael

+0

Impossible de le faire fonctionner, il ne trouve pas le fichier dans ni éclipse ni dans le pot. – Rafael

+0

@Rafael: Correction. 'ClasspathResourceLoader' n'est pas enregistré par défaut. – axtavt

7

À moins JAR explose, vous ne pouvez pas lire la ressource dans le JAR sous forme de fichier. Utilisez un flux d'entrée.

Voir ci-dessous des extraits de code,

InputStream input = classLoader.getResourceAsStream(fileName); 
    if (input == null) { 
     throw new ConfigurationException("Template file " + 
       fileName + " doesn't exist");   
    } 

    InputStreamReader reader = new InputStreamReader(input);    
     Writer writer = null; 

     try { 
      writer = new OutputStreamWriter(output);   

      // Merge template 
      if (!engine.evaluate(context, writer, fileName, reader)) 
       ...... 
17

code final, développé en utilisant les idées présentées dans les deux réponses ci-dessus:

VelocityEngine ve = new VelocityEngine(); 
      ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); 
      ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); 

      ve.init(); 

      final String templatePath = "templates/" + templateName + ".vm"; 
      InputStream input = this.getClass().getClassLoader().getResourceAsStream(templatePath); 
      if (input == null) { 
       throw new IOException("Template file doesn't exist"); 
      } 

      InputStreamReader reader = new InputStreamReader(input); 

      VelocityContext context = new VelocityContext(); 

      if (properties != null) { 
       stringfyNulls(properties); 
       for (Map.Entry<String, Object> property : properties.entrySet()) { 
        context.put(property.getKey(), property.getValue()); 
       } 
      } 

      Template template = ve.getTemplate(templatePath, "UTF-8"); 
      String outFileName = File.createTempFile("report", ".html").getAbsolutePath(); 
      BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outFileName))); 

      if (!ve.evaluate(context, writer, templatePath, reader)) { 
       throw new Exception("Failed to convert the template into html."); 
      } 

      template.merge(context, writer); 

      writer.flush(); 
      writer.close(); 
+0

Merci, cela m'a aidé beaucoup! Peut-être que mon adaptation fonctionne un peu différemment, mais en utilisant VelocityEngine # evaluate (...), je pourrais omettre l'instanciation du Template et l'appel à Template # merge (...) – Argelbargel

+0

fonctionne comme un charme. RuntimeInstance a résolu mon problème en me permettant de charger le template dans mon bundle.Meilleure solution pour OSGI – iberbeu

1

Pour faire paraître de vitesse pour les modèles à classpath:

VelocityEngine ve = new VelocityEngine(); 
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); 
ve.setProperty("classpath.resource.loader.class",ClasspathResourceLoader.class.getName()); 
ve.init(); 
+0

Cela ressemble exactement à la réponse acceptée. – JKirchartz

+7

Je pense que vous êtes un peu en retard à la fête. –

Questions connexes