63

Just a simple velocity standalone app based on maven structure. Here is the code snippet written in Scala to render the template helloworld.vm in ${basedir}/src/main/resources folder:

com.ggd543.velocitydemo

import org.apache.velocity.app.VelocityEngine
import org.apache.velocity.VelocityContext
import java.io.StringWriter

/**
 * @author ${user.name}
 */
object App {

  def main(args: Array[String]) {
    //First , get and initialize an engine
    val ve = new VelocityEngine();
    ve.init();

    //Second, get the template
    val resUrl = getClass.getResource("/helloworld.vm")
    val t = ve.getTemplate("helloworld.vm");   // not work 
//    val t = ve.getTemplate("/helloworld.vm");  // not work
//    val t = ve.getTemplate(resUrl.toString);  // not work yet
    //Third, create a context and add data
    val context = new VelocityContext();
    context.put("name", "Archer")
    context.put("site", "http://www.baidu.com")
    //Finally , render the template into a StringWriter
    val sw = new StringWriter
    t.merge(context, sw)
    println(sw.toString);
  }

}

when to compile and run the program, I got the following error:

2012-1-29 14:03:59 org.apache.velocity.runtime.log.JdkLogChute log
严重: ResourceManager : unable to find resource '/helloworld.vm' in any resource loader.
Exception in thread "main" org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource '/helloworld.vm'
    at org.apache.velocity.runtime.resource.ResourceManagerImpl.loadResource(ResourceManagerImpl.java:474)
    at org.apache.velocity.runtime.resource.ResourceManagerImpl.getResource(ResourceManagerImpl.java:352)
    at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1533)
    at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1514)
    at org.apache.velocity.app.VelocityEngine.getTemplate(VelocityEngine.java:373)
    at com.ggd543.velocitydemo.App$.main(App.scala:20)
    at com.ggd543.velocitydemo.App.main(App.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Process finished with exit code 1
Mat
  • 202,337
  • 40
  • 393
  • 406
Archer
  • 631
  • 1
  • 5
  • 4

14 Answers14

108

Great question - I solved my issue today as follows using Ecilpse:

  1. Put your template in the same folder hierarchy as your source code (not in a separate folder hierarchy even if you include it in the build path) as below: Where to put your template file

  2. In your code simply use the following lines of code (assuming you just want the date to be passed as data):

    VelocityEngine ve = new VelocityEngine();
    ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
    ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
    ve.init();
    VelocityContext context = new VelocityContext();
    context.put("date", getMyTimestampFunction());
    Template t = ve.getTemplate( "templates/email_html_new.vm" );
    StringWriter writer = new StringWriter();
    t.merge( context, writer );
    

See how first we tell VelocityEngine to look in the classpath. Without this it wouldn't know where to look.

Sameer Technomark
  • 1,399
  • 1
  • 10
  • 12
  • 1
    lines 2+3 was what i was missing. but i had to do /templates for it to work. – Or Gal Apr 15 '13 at 07:36
  • And of course the templates can live under the resource path. It should be part of the classpath which you can easily achieve in Eclipse with a 'new > Source Folder'. You can check this by looking at Project (right-click) > Properties > Java Build Path > Source (tab) - the folder should be listed. Thanks user168... for your tip! – HankCa Nov 14 '13 at 00:14
  • @Archer please accept the answer if this suggestion helped you. Certainly this suggestion help me – Selvakumar Esra Apr 26 '14 at 06:15
  • I got exception: `"java.lang.ClassCastException: com.ggd543.velocitydemo.App cannot be cast to org.apache.velocity.runtime.resource.loader.ResourceLoader"` . Do you have idea how I can extend my class? – Gleb Belyaev Mar 30 '15 at 17:23
  • I am skeptical about the step 1 keeping the same hierarchy. You can just mark the directory as test resources root and perform step 2. Things will work. I myself tested it by keeping different hierarchy. – iec2011007 Jun 16 '17 at 11:54
34

I put my .vm under the src/main/resources/templates, then the code is :

Properties p = new Properties();
p.setProperty("resource.loader", "class");
p.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init( p );       
VelocityContext context = new VelocityContext();           
Template template = Velocity.getTemplate("templates/my.vm");

this works in web project.

In eclipse Velocity.getTemplate("my.vm") works since velocity will look for the .vm file in src/main/resources/ or src/main/resources/templates, but in web project, we have to use Velocity.getTemplate("templates/my.vm");

frank
  • 1,169
  • 18
  • 43
9

You can just use it like this:

Template t = ve.getTemplate("./src/main/resources/templates/email_html_new.vm");

It works.

Danny Beckett
  • 20,529
  • 24
  • 107
  • 134
Guernize
  • 123
  • 1
  • 1
  • 5
    Be careful, this should only work in a (Maven) development environment. – sp00m Dec 14 '15 at 11:05
  • 4
    I can't imagine that this would work if the jar was packaged and then consumed externally because the "src/main/java" directory would no longer exist. – dsingleton Sep 15 '16 at 16:26
  • 5
    This solution will only works in your IDE otherwise it will not work. – Bhavesh Feb 27 '17 at 06:28
5

I faced the similar problem with intellij IDEA. you can use this

 VelocityEngine ve = new VelocityEngine();
    Properties props = new Properties();
    props.put("file.resource.loader.path", "/Users/Projects/Comparator/src/main/resources/");
    ve.init(props);

    Template t = ve.getTemplate("helloworld.vm");
    VelocityContext context = new VelocityContext();
Vishal
  • 1,442
  • 3
  • 29
  • 48
3

Make sure you have a properly configured resource loader. See Velocity documentation for help selecting and configuring a resource loader: https://velocity.apache.org/engine/1.7/developer-guide.html#configuring-resource-loaders

lipeiran
  • 526
  • 13
  • 33
wau
  • 830
  • 7
  • 20
2

you can try to add these code:

VelocityEngine ve = new VelocityEngine();
String vmPath = request.getSession().getServletContext().getRealPath("${your dir}");
Properties p = new Properties();
p.setProperty("file.resource.loader.path", vmPath+"//");
ve.init(p);

I do this, and pass!

xDemon
  • 23
  • 3
2
VelocityEngine velocityEngin = new VelocityEngine();
velocityEngin.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
velocityEngin.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());

velocityEngin.init();

Template template = velocityEngin.getTemplate("nameOfTheTemplateFile.vtl");

you could use the above code to set the properties for velocity template. You can then give the name of the tempalte file when initializing the Template and it will find if it exists in the classpath.

All the above classes come from package org.apache.velocity*

SheoSinha
  • 107
  • 4
2

I have put this working code snippet for future references. The code sample was written with Apache velocity version 1.7 with embedded Jetty.

Velocity template path is located at the resource folder email_templates subfolder.

enter image description here

Code Snippet in Java (Snippets are worked both running on eclipse and inside a Jar)

    templateName = "/email_templates/byoa.tpl.vm"
    VelocityEngine ve = new VelocityEngine();
    ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
    ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
    ve.init();
    Template t = ve.getTemplate(this.templateName);
    VelocityContext velocityContext = new VelocityContext();
    velocityContext.put("","") // put your template values here
    StringWriter writer = new StringWriter();
    t.merge(this.velocityContext, writer);

System.out.println(writer.toString()); // print the updated template as string

For OSGI plugging code snippets.

final String TEMPLATE = "resources/template.vm" // located in the resources folder
Thread current = Thread.currentThread();
       ClassLoader oldLoader = current.getContextClassLoader();
       try {
          current.setContextClassLoader(TemplateHelper.class.getClassLoader()); // TemplateHelper is a class inside your jar file
          Properties p = new Properties();
          p.setProperty("resource.loader", "class");
          p.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
          Velocity.init( p );       
          VelocityEngine ve = new VelocityEngine();
          Template template = Velocity.getTemplate( TEMPLATE );
          VelocityContext context = new VelocityContext();
          context.put("tc", obj);
          StringWriter writer = new StringWriter();
          template.merge( context, writer );
          return writer.toString() ;  
       }  catch(Exception e){
          e.printStackTrace();
       } finally {
          current.setContextClassLoader(oldLoader);
       }
Rob Evans
  • 2,822
  • 1
  • 9
  • 15
gihan-maduranga
  • 4,381
  • 5
  • 41
  • 74
1

The following code helped me resolve the issue. The path to the template needs to be provided as part of file.resource.loader path. By default it comes as "." . So setting the property explicitly will be required.

Print getClass().getClassLoader().getResource("resources") or getClass().getClassLoader().getResource("") to see where your template comes and based on that set it in the velocity template engine.

URL url = getClass().getClassLoader().getResource("resources");
//URL url = getClass().getClassLoader().getResource("");
File folder= new File(url.getFile());   
VelocityEngine ve = new VelocityEngine();
       
ve.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, folder.getAbsolutePath());
ve.init();

Template template = ve.getTemplate( "MyTemplate.vm" );
jwvh
  • 50,871
  • 7
  • 38
  • 64
Susan Liya
  • 11
  • 1
0

While using embedded jetty the property webapp.resource.loader.path should starts with slash:

webapp.resource.loader.path=/templates

otherwise templates will not be found in ../webapp/templates

SzB
  • 1,027
  • 10
  • 12
0

You can also put your templates folder under src/main/resources instead of src/main/java. Works for me and it's a preferable location since templates are not java source.

0

I faced a similar issue. I was copying the velocity engine mail templates in wrong folder. Since JavaMailSender and VelocityEngine are declared as resources under MailService, its required to add the templates under resource folder declared for the project.

I made the changes and it worked. Put the templates as

src/main/resources/templates/<package>/sampleMail.vm
Nikhil
  • 861
  • 11
  • 15
0

Using IntelIJ Idea community 2021.3, you just need to start your project with this config:

    VelocityEngine engine = new VelocityEngine();
    Properties props = new Properties();
    final String path = "src/main/resources/templates/";
    props.put("file.resource.loader.path", path);
    engine.init(props);

You can put whatever path you want but realize that it will start from the project_root defined in the idea.

DISCLAIMER This solution may NOT work outside the IDE

A.Casanova
  • 555
  • 4
  • 16
-1

Just a simple velocity standalone app based on maven structure. Here is the code snippet written in Scala to render the template helloworld.vm in

${basedir}/src/main/resources folder:
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135