FreeMarker Tutorial. This tutorial explains how can you define FreeMarker templates and how can you generate output based on these templates. It also demonstrates the usage of macros.
1. Introduction to FreeMarker
FreeMarker is a Java-based template engine which can be used in stand-alone or servlet-based Java programs.
In FreeMarker
you define templates, which are text files that contain
the desired output,
except that they contain placeholders like
${name}
, and even some
logic like conditionals, loops, etc. In your Java program
you
supply the actual
values for these placeholders
and the final
output is
generated based on
this input.
The input of templates is a bunch of named variables that you usually
provide
as a
Map<String, Object>
(the
Map
entries will be
the variables) or as a JavaBean (the JavaBean
properties will be the
variables).
The variable values can be simple
strings, numbers and such primitive
values,
but also lists, maps, or
arbitrary Java objects whose methods
you can call from the template.
Note that when accessing JavaBean
properties,
myObject.myProperty
syntax should be used instead of
myObject.getMyProperty()
.
The output of templates is written into a
Writer
that you provide,
so it can go into a HTTP response (for dynamic web
pages), into a local
file,
into a
String
, etc.
It is configurable from where FreeMarker reads the templates;
commonly
used options are
loading from a file-system directory,
from the
class-path, from
the servlet context (
WEB-INF/templates
or such),
or even from a database table.
It’s also possible to "load"
templates directly from
String
objects.
2. Installation of FreeMarker
To use FreeMarker download the latest version of it from the following webpage and add it to the classpath of your Java project.
http://freemarker.org/freemarkerdownload.html
3. Eclipse Integration
FreeMarker code completion and syntax highlighting is part of the JBoss Tools. Add the following update site to your Eclipse installation via
http://download.jboss.org/jbosstools/updates/stable/kepler/
4. Basic example
Create a new Java project called com.vogella.freemarker.first.
Create a new folder called lib
and add the Freemarker library to it.
Add this library to the classpath for your project.
If you don’t know how to achieve that, please see the Eclipse IDE Tutorial for instructions on the required steps.
Create a new folder called
templates
inside the folder of the
com.vogella.freemarker.first
package. Inside that, create the following file with name
helloworld.ftl
.
<html>
<head>
<title>${title}
</head>
<body>
<h1>${title}</h1>
<p>${exampleObject.name} by ${exampleObject.developer}</p>
<ul>
<#list systems as system>
<li>${system_index + 1}. ${system.name} from ${system.developer}</li>
</#list>
</ul>
</body>
</html>
Create the following class which demonstrates the usage of Java objects in templates.
package com.vogella.freemarker.first;
public class ValueExampleObject {
private String name;
private String developer;
public ValueExampleObject(String name, String developer) {
this.name = name;
this.developer = developer;
}
public String getName() {
return name;
}
public String getDeveloper() {
return developer;
}
}
Create the following class which creates the input for this template and creates the output.
package com.vogella.freemarker.first;
import java.io.File;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.Version;
public class MainTest {
public static void main(String[] args) throws Exception {
// 1. Configure FreeMarker
//
// You should do this ONLY ONCE, when your application starts,
// then reuse the same Configuration object elsewhere.
Configuration cfg = new Configuration();
// Where do we load the templates from:
cfg.setClassForTemplateLoading(MainTest.class, "templates");
// Some other recommended settings:
cfg.setIncompatibleImprovements(new Version(2, 3, 20));
cfg.setDefaultEncoding("UTF-8");
cfg.setLocale(Locale.US);
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// 2. Proccess template(s)
//
// You will do this for several times in typical applications.
// 2.1. Prepare the template input:
Map<String, Object> input = new HashMap<String, Object>();
input.put("title", "Vogella example");
input.put("exampleObject", new ValueExampleObject("Java object", "me"));
List<ValueExampleObject> systems = new ArrayList<ValueExampleObject>();
systems.add(new ValueExampleObject("Android", "Google"));
systems.add(new ValueExampleObject("iOS States", "Apple"));
systems.add(new ValueExampleObject("Ubuntu", "Canonical"));
systems.add(new ValueExampleObject("Windows7", "Microsoft"));
input.put("systems", systems);
// 2.2. Get the template
Template template = cfg.getTemplate("helloworld.ftl");
// 2.3. Generate the output
// Write output to the console
Writer consoleWriter = new OutputStreamWriter(System.out);
template.process(input, consoleWriter);
// For the sake of example, also write output into a file:
Writer fileWriter = new FileWriter(new File("output.html"));
try {
template.process(input, fileWriter);
} finally {
fileWriter.close();
}
}
}
5. Useful FTL tricks
5.1. Reuse common template fragments
When you find yourself copy-pasting common parts between templates a lot, you should probably use macros.
Continuing our last example, create a new folder called
lib
inside the
templates
directory, and there create a file called
utils.ftl
, with
this content:
<#macro page>
<html>
<head>
<title>${title}
</head>
<body>
<h1>${title}</h1>
<#-- This processes the enclosed content: -->
<#nested>
</body>
</html>
</#macro>
<#macro otherExample p1 p2>
<p>The parameters were: ${p1}, ${p2}</p>
</#macro>
Now you can simplify helloworld.ftl
like this:
<#import "lib/utils.ftl" as u>
<@u.page>
<p>${exampleObject.name} by ${exampleObject.developer}</p>
<ul>
<#list systems as system>
<li>${system_index + 1}. ${system.name} from ${system.developer}</li>
</#list>
</ul>
<#-- Just another example of using a macro: -->
<@u.otherExample p1=11 p2=22 />
</@u.page>
Another way of reusing template fragments is moving the common
fragment into
its own ftl file. Then just insert it with <#include "lib/myfragment.ftl">
. This is less flexible than macros,
but simpler in concept: it mimics copy-pasting.
5.2. Variables
You can define and assign content to variables inside the FTL files for easy reuse.
<#assign var_link = "https://www.vogella.com/people/larsvogel.html">
<a href="${var_link}">About Lars Vogel</a>
5.3. If then else
` You can handle if / else cases, see below for an example.
<#assign name = "${article.getName()}">
<#if name?starts_with("https")>
<a href="http://www.learn.com</a>
<#else>
<a href="https://www.vogella.com/tutorials/${name}/article.html">${title}</a>
</#if>
5.4. Handling null/undefined values
FreeMarker requires you to provide an explicit default for variables, so avoid
values that are
null
or undefined:
<!-- Acts like if the color was N/A if there's no color: -->
<p>Color: ${color!'N/A'}</p>
<!-- Avoid the whole color row if there's no color: -->
<#if color??>
<p>Color: ${color}</p>
</#if>
5.5. Escape
When generating HTML, it’s important to escape <
, &
,
etc. in values that were not meant to store HTML and can contain these
problematic characters.
You can apply such escaping like
${message?html}
.
You can also ask FreeMarker to add
?html
to all
${}
-s in a section like this:
<#escape x as x?html>
<p>Sender: ${from}
<p>Title: ${title}
<p>Message: ${body}
</#escape>
It’s important to understand that
#escape
only affects the
${}
bits that are inside the enclosed section in the template file when you
look
at it in a text editor. That means,
${}
embracements which are in other templates or macros
called from there, won’t be affected.
6. Links and Literature
6.2. vogella Java example code
If you need more assistance we offer Online Training and Onsite training as well as consulting