Java 在 jar 文件中加载速度模板

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2931516/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 14:36:38  来源:igfitidea点击:

Loading velocity template inside a jar file

javatemplatesjarclasspathvelocity

提问by Rafael

I have a project where I want to load a velocity template to complete it with parameters. The whole application is packaged as a jar file. What I initially thought of doing was this:

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

And this works fine when I run it in eclipse. However, once I package the program and try to run it using the command line I get an error because the file could not be found.

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

I imagine the problem is in this line:

我想问题出在这一行:

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

Because in a jar the absolute file does not exist, since it's inside a zip, but I couldn't yet find a better way to do it.

因为在 jar 中绝对文件不存在,因为它在 zip 中,但我还找不到更好的方法来做到这一点。

Anyone has any ideas?

任何人有任何想法?

采纳答案by axtavt

If you want to use resources from classpath, you should use resource loader for classpath:

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

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

回答by ZZ Coder

Unless JAR is exploded, you can't read the resource in JAR as file. Use an input stream.

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

See following code snippets,

请参阅以下代码片段,

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

回答by Rafael

Final code, developed using the ideas presented in both answers above:

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

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

回答by Mahesh Lavannis

To make Velocity look for the templates in classpath:

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

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

回答by Ignacio Tomas Crespo

Maybe I have an old version, this is the only thing that worked for me

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

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