First steps with FreeMarker


About FreeMarker


FreeMarker is a Java template engine. It is mostly used to make web pages. Using a template engine you can design a document containing placeholders, which is processed by the engine to "fill the blanks". Depending on the power and flexibility of the template engine you can do more or less with it. FreeMarker ranks high on both accounts.


To get started, download the latest FreeMarker from the official download page:


FreeMarker: Java Template Engine Library - Download FreeMarker


FreeMarker comes in a .tar.gz format, which is understood by most archive tools (you can use 7-Zip).


Next we will write a few examples that will introduce you to FreeMarker. You will need Java installed on your computer to run them. For the examples copy freemarker.jar located in the lib directory of FreeMarker to the Java extension folder, which is under lib/ext in the Java home folder. This document can help you locate it:


Java: The Extension Mechanism


On Mac OS X it is /Library/Java/Home/lib/ext.


Example 1: Web page


Open your favourite Web editor and enter the following text in the page:


${pet} does ${number} little hops :)


For the title of the page enter:


Page for ${pet}!


Save the document as example1.html. Then open a text editor and enter the following Java program:


import freemarker.template.Template;

import freemarker.template.Configuration;

import java.io.OutputStreamWriter;

import java.util.HashMap;

import java.util.Map;


public class Example1

{

public static void main(String[] args)

{

// Add the values in the datamodel

Map datamodel = new HashMap();

datamodel.put("pet", "Bunny");

datamodel.put("number", new Integer(6));


// Process the template using FreeMarker

try {

freemarkerDo(datamodel, "example1.html");

}

catch(Exception e) {

System.out.println(e.getLocalizedMessage());

}

}


// Process a template using FreeMarker and print the results

static void freemarkerDo(Map datamodel, String template) throws Exception

{

Configuration cfg = new Configuration();

Template tpl = cfg.getTemplate(template);

OutputStreamWriter output = new OutputStreamWriter(System.out);


tpl.process(datamodel, output);

}

}


In FreeMarker lingo, the datamodel is a Java variable that contains all the values used to fill in the blanks. The program builds the datamodel, then calls a helper function to process the template with the FreeMarker engine. This helper function initialises the engine by creating a new configuration. Then it reads the template file (example1.html) into a Template variable. Finally it processes the template using the datamodel.


Save the Java program as "Example1.java" and compile it in a command window:


javac Example1.java


You will need to navigate to the directory containing Example1.java and Example1.html before running the compiler. When the file compiles successfully (ignore the "unchecked" warnings) run the program with the command:


java Example1


You should get a result like:


<html>

   <head>

      <title>Page for Bunny!</title>

   </head>

   <body>

      Bunny does 6 little hops :)

   </body>

</html>


That is the code of the processed Web page. You can save the output in a file to see what the actual generated Web page looks like:


java Example1 > example1out.html


Open example1out.html in a Web browser to view the results. You will see the placeholders filled with the actual values that you entered in the Java program. Experiment with different values and different variable names to see what you can do.


Example 2: Mail merge


For this example we will make a file which contains the person's data. Open a plain text editor and enter:


recipient=John Smith

address=3033 Long Drive, Houston, TX


Save the file as "example2.dat". Next create a letter template with the following:


To: ${recipient}

    ${address}



                      Dear ${recipient},


Thank you for your interest in our products. We will be sending you a catalog shortly.

To take advantage of our free gift offer, please fill in the survey attached to this

letter and return it to the address on the reverse. Only one participant is allowed for

each household.


Sincere salutations,



     D. H.


Save the file as "example2.txt". Finally write a Java program that will merge the two files together using FreeMarker:


import freemarker.template.Template;

import freemarker.template.Configuration;

import java.io.OutputStreamWriter;

import java.io.FileInputStream;

import java.util.Properties;

import java.util.Map;


public class Example2

{

public static void main(String[] args)

{

Properties data = new Properties();


// Read the data file and process the template using FreeMarker

try {

data.load(new FileInputStream("example2.dat"));

freemarkerDo(data, "example2.txt");

}

catch(Exception e) {

System.out.println(e.getLocalizedMessage());

}

}


// Process a template using FreeMarker and print the results

static void freemarkerDo(Map datamodel, String template) throws Exception

{

Configuration cfg = new Configuration();

Template tpl = cfg.getTemplate(template);

OutputStreamWriter output = new OutputStreamWriter(System.out);


tpl.process(datamodel, output);

}

}


This program uses the predefined Java class Properties to read the values from the data file. Then it proceeds as in the previous example.


Save the Java program as "Example2.java" and compile it in a command window:


javac Example2.java


Then run the program with the command:


java Example2


You should get a result like:


To: John Smith

    3033 Long Drive, Houston, TX



                      Dear John Smith,


Thank you for your interest in our products. We will be sending you a catalog shortly.

To take advantage of our free gift offer, please fill in the survey attached to this

letter and return it to the address on the reverse. Only one participant is allowed for

each household.


Sincere salutations,



     D. H.


That is the mailing letter with the placeholders filled with the actual values that you specified in the data file. 


Note that to use this example, you will need a separate data file for each person you are writing to. In the next example we will see a way to use a single file which contains all the recipients details.


Example 3: XML data source


FreeMarker includes powerful XML processing features. Here we will use only the simplest one to read a list of names and addresses from a XML file and insert them in the template.


Open a plain text editor and enter:


<recipients>

<person>

<name>John Smith</name>

<address>3033 Long Drive, Houston, TX</address>

</person>

<person>

<name>Janet Mason</name>

<address>11c Poplar Drive, Knoxville, TN</address>

</person>

</recipients>


Save the file as "example3.xml". Next create a new file with:


[#ftl]


[#foreach recipient in doc.recipients.person]


To: ${recipient.name}

    ${recipient.address}



                      Dear ${recipient.name},


Thank you for your interest in our products. We will be sending you a catalog shortly.

To take advantage of our free gift offer, please fill in the survey attached to this

letter and return it to the address on the reverse. Only one participant is allowed for

each household.


Sincere salutations,



     D. H.


---------------------------------------------------------------------------------------

[/#foreach]


Save the file as "example3.ftl". This template uses more features of FreeMarker than previous examples. The first line contains [#ftl] to mark a FreeMarker file. Then it contains the directive [#foreach ... in ...] to repeat the enclosed template with each item in the list. The dots in doc.recipients.person denote a path, ie. we want "person" inside "recipients" itself inside "doc". Similarly recipient.name means the value of "name" in "recipient".


The following program will process the template:


import freemarker.template.Template;

import freemarker.template.Configuration;

import java.io.OutputStreamWriter;

import java.io.File;

import java.util.HashMap;

import java.util.Map;


public class Example3

{

public static void main(String[] args)

{

Map tree = new HashMap();

File document = new File("example3.xml");


// Read the XML file and process the template using FreeMarker

try {

tree.put("doc", freemarker.ext.dom.NodeModel.parse(document));

freemarkerDo(tree, "example3.ftl");

}

catch(Exception e) {

System.out.println(e.getLocalizedMessage());

}

}


// Process a template using FreeMarker and print the results

static void freemarkerDo(Map datamodel, String template) throws Exception

{

Configuration cfg = new Configuration();

Template tpl = cfg.getTemplate(template);

OutputStreamWriter output = new OutputStreamWriter(System.out);


tpl.process(datamodel, output);

}

}


This program uses class freemarker.ext.dom.NodeModel which comes with FreeMarker to read the XML document. The resulting tree is added to the datamodel.


Save the Java program as "Example3.java" and compile it in a command window:


javac Example3.java


Then run the program with the command:


java Example3


You should get a result like:


To: John Smith

    3033 Long Drive, Houston, TX



                      Dear John Smith,


Thank you for your interest in our products. We will be sending you a catalog shortly.

To take advantage of our free gift offer, please fill in the survey attached to this

letter and return it to the address on the reverse. Only one participant is allowed for

each household.


Sincere salutations,



     D. H.


---------------------------------------------------------------------------------------


To: Janet Mason

    11c Poplar Drive, Knoxville, TN



                      Dear Janet Mason,


Thank you for your interest in our products. We will be sending you a catalog shortly.

To take advantage of our free gift offer, please fill in the survey attached to this

letter and return it to the address on the reverse. Only one participant is allowed for

each household.


Sincere salutations,



     D. H.


---------------------------------------------------------------------------------------



That is the mailing letter with the placeholders filled with the actual values that you specified in the XML file. 


Closing words


There is much more you can do with FreeMarker. Visit the FreeMarker web site and go through the documentation and examples to learn more about it.


FreeMarker: Java Template Engine Library - Overview


About the author: Denis Bredelet is a technical support engineer who likes to play with programming languages and Web technologies.