【问题标题】:Loading velocity template inside a jar file在 jar 文件中加载速度模板
【发布时间】:2011-02-25 06:25:39
【问题描述】:

我有一个项目,我想加载一个速度模板来完成它的参数。整个应用程序被打包为一个 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();

当我在 Eclipse 中运行它时,它工作得很好。但是,一旦我打包程序并尝试使用命令行运行它,我就会收到错误,因为找不到文件。

我想问题出在这一行:

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

因为在 jar 中绝对文件不存在,因为它在 zip 中,但我还没有找到更好的方法。

有人有什么想法吗?

【问题讨论】:

  • 看在上帝的份上,突出显示您帖子中的代码并单击代码按钮,使其格式正确! :)
  • 您确定 /templates/ 目录正在导出到您的 jar 中吗?您必须将其标记为构建设置和内容的一部分。
  • 不知道代码按钮,谢谢。是的,模板目录正在进入 jar 文件。

标签: java templates jar classpath velocity


【解决方案1】:

如果你想使用类路径中的资源,你应该使用类路径的资源加载器:

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

【讨论】:

  • 我会测试它!你知道我在哪里可以找到每个 RuntimeContants 及其可能值的文档吗?
  • 无法正常工作,在 Eclipse 和 jar 中都找不到文件。
  • @Rafael:已修复。 ClasspathResourceLoader 默认不注册。
  • 谢谢,当我将它与下面 ZZ Coder 提出的想法一起使用时,它确实有效。
  • 不幸的是,Javadocs of ClasspathResourceLoader 错误地说资源加载器的值应该是“类”——我试过了,但是没有用,后来才发现它应该是“类路径”,如这个答案
【解决方案2】:

使用上述两个答案中提出的想法开发的最终代码:

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();

【讨论】:

  • 谢谢,这对我帮助很大!可能是我的适应工作有点不同,但是使用 VelocityEngine#evaluate(...),我可以省略模板的实例化和对 Template#merge(...) 的调用
  • 就像一个魅力。 RuntimeInstance 解决了我的问题,允许我将模板加载到我的包中。 OSGI 的最佳解决方案
  • 这个解决方案效果很好,除了最后我不需要合并部分。
【解决方案3】:

除非 JAR 被分解,否则您无法将 JAR 中的资源作为文件读取。使用输入流。

见以下代码sn-ps,

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

【讨论】:

    【解决方案4】:

    让 Velocity 在类路径中查找模板:

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

    【讨论】:

    • 我觉得你来晚了。
    【解决方案5】:

    也许我有一个旧版本,这是唯一对我有用的东西

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

    【讨论】:

      猜你喜欢
      • 2013-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      • 2021-06-14
      • 1970-01-01
      • 2011-05-31
      相关资源
      最近更新 更多