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:
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.
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.
Anyone has any ideas?
A Velocity variable can be either a referenced Java object or a declared variable inside a template. A Velocity variable begins with $ followed by the name of the variable.
Velocity is a server-side template language used by Confluence to render page content. Velocity allows Java objects to be called alongside standard HTML.
Velocity can be used to generate web pages, SQL, PostScript and other output from templates. It can be used either as a standalone utility for generating source code and reports, or as an integrated component of other systems.
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());
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With