The simplest template is a plain HTML file (or whatever text file; FreeMarker is not confined to HTML). When the client visits that page, FreeMarker will send that HTML to the client as is. However if you want that page to be more dynamic then you begin to put special parts into the HTML which will be understood by FreeMarker:
-
${...}
: FreeMarker will replace it in the output with the actual value of the expression inside the curly brackets. They are called interpolations. -
FTL tags (for FreeMarker Template Language tags): FTL tags are a bit similar to HTML tags, but they are instructions to FreeMarker and will not be printed to the output. The name of these tags start with
#
. (User-defined FTL tags use@
instead of#
, but they are an advanced topic.) -
Comments: Comments are similar to HTML comments, but they are delimited by
<#--
and-->
. Unlike HTML comments, FTL comments won't get into the output (won't be visible in the page source for the visitor), because FreeMarker skips them.
Anything not an FTL tag or an interpolation or comment is considered static text and will not be interpreted by FreeMarker; it is just printed to the output as-is.
With FTL tags you refer to so-called directives. This is the same kind of
relationship as between HTML tags (e.g.:
<table>
and
</table>
) and HTML elements (e.g., the
table
element) to which you refer to with the HTML
tags. (If you don't understand this difference then consider "FTL tag"
and "directive" synonyms.)
You can easily try writing templates on http://freemarker-online.kenshoo.com/
Some basic directives
Here we will look at some of the most commonly used directives (but there are much more).
The if directive
With the if
directive you can
conditionally skip a section of the template. For example, assume
that in the very first
example you want to greet your boss, Big Joe, differently
than other users:
<html> <head> <title>Welcome!</title> </head> <body> <h1> Welcome ${user}<#if user == "Big Joe">, our beloved leader</#if>! </h1> <p>Our latest product: <a href="${latestProduct.url}">${latestProduct.name}</a>! </body> </html>
Here you have told FreeMarker that the ", our beloved
leader" should be there only if the value of the variable
user
is equal to the string "Big
Joe"
. In general, things between <#if
condition>
and
</#if>
tags are skipped if
condition
is false
(the boolean value).
Let's look at
condition
more
closely: ==
is an operator that tests if the
values at its left and right side are equivalent, and the results
is a boolean value, true or false accordingly. On the left side of
==
I have referenced a
variable with the syntax that should be already familiar;
this will be replaced with the value of the variable. In general,
unquoted words inside directives or interpolations are treated as
references to variables. On the right side I have specified a
literal string. Literal strings in templates must
always be put inside quotation marks.
This will print "Pythons are free today!" if their price is 0:
<#if animals.python.price == 0> Pythons are free today! </#if>
Similarly as earlier when a string was specified directly,
here a number is specified directly (0
). Note
that the number is not quoted. If you quoted
it ("0"
), FreeMarker would misinterpret it as a
string literal, and because the price to compare it to is a
number, you get an error.
This will print "Pythons are not free today!" if their price is not 0:
<#if animals.python.price != 0> Pythons are not free today! </#if>
As you probably guessed, !=
means
"not equals".
You can write things like this too (using the data-model used to demonstrate hashes):
<#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. </#if>
With the <#else>
tag you can
specify what to do if the condition is false. For example:
<#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. <#else> Pythons are not cheaper than elephants today. </#if>
This prints "Pythons are cheaper than elephants
today." if the price of python is less than the price of
elephant, or else it prints "Pythons are not cheaper than
elephants today." You can refine this further by using
elseif
:
<#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. <#elseif animals.elephant.price < animals.python.price> Elephants are cheaper than pythons today. <#else> Elephants and pythons cost the same today. </#if>
If you have a variable with boolean value (a true/false
thing) then you can use it directly as the
condition
of
if
:
<#if animals.python.protected> Pythons are protected animals! </#if>
The list directive
This is needed when you want to list something. For example if you merge this template with the data-model used earlier to demonstrate sequences:
<p>We have these animals: <table border=1> <#list animals as animal> <tr><td>${animal.name}<td>${animal.price} Euros </#list> </table>
then the output will be:
<p>We have these animals: <table border=1> <tr><td>mouse<td>50 Euros <tr><td>elephant<td>5000 Euros <tr><td>python<td>4999 Euros </table>
The generic form of the list
directive
is: <#list sequence as
loopVariable>repeatThis</#list>
.
The repeatThis
part
will be repeated for each item in the sequence that you have
specified with
sequence
, one after
the other, starting from the first item. In all repetitions
loopVariable
will
hold the value of the current item. This variable exists only
between the <#list
...>
and
</#list>
tags.
The sequence
can be any kind of expression. For example we could list the
fruits of the example data model like this:
<ul> <#list misc.fruits as fruit> <li>${fruit} </#list> </ul>
The misc.fruits
expression should be
familiar to you; it references a variable in
the data-model.
A problem with the above example is that if we happen to
have 0 fruits, it will still print an empty
<ul></ul>
instead of just nothing.
To avoid that, you can use this form of
list
:
<#list misc.fruits> <ul> <#items as fruit> <li>${fruit} </#items> </ul> </#list>
Here, the list
directive represents the
listing as a whole, and only the part inside the
items
directive is repeated for each fruit. If
we have 0 fruits, everything inside list
is
skipped, hence we will not have ul
tags in
case.
Another frequent listing-related task: let's list the fruits separating them with something, like a comma:
<p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, </#list>
<p>Fruits: orange, banana
The section covered by sep
(which we
could be written like this too:
...<#sep>,
</#sep></#list>
) will be only executed when
there will be a next item. Hence there's no comma after the last
fruit.
Here again, what if we have 0 fruits? Just printing
"Fruits:" and then nothing is awkward. A
list
, just like an if
, can
have an else
, which is executed if there were 0
list items:
<p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, <#else>None</#list>
As a matter of fact, this simplistic example could be written like this, but it uses language devices that are off topic here:
<p>Fruits: ${fruits?join(", ", "None")}
All these directives (list
,
items
, sep
,
else
) can be used together:
<#list misc.fruits> <p>Fruits: <ul> <#items as fruit> <li>${fruit}<#sep> and</#sep> </#items> </ul> <#else> <p>We have no fruits. </#list>
You can read more about these directives in the Reference.
The include directive
With the include
directive you can insert
the content of another file into the template.
Suppose you have to show the same copyright notice on
several pages. You can create a file that contains the copyright
notice only, and insert that file everywhere where you need that
copyright notice. Say, you store this copyright notice in
copyright_footer.html
:
<hr> <i> Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, <br> All Rights Reserved. </i>
Whenever you need that file you simply insert it with the
include
directive:
<html> <head> <title>Test page</title> </head> <body> <h1>Test page</h1> <p>Blah blah... <#include "/copyright_footer.html"> </body> </html>
and the output will be:
<html> <head> <title>Test page</title> </head> <body> <h1>Test page</h1> <p>Blah blah... <hr> <i> Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, <br> All Rights Reserved. </i> </body> </html>
If you change the copyright_footer.html
,
then the visitor will see the new copyright notice on all
pages.
A much more powerful way of reusing snippets is using macros, but that's an advanced topic discussed later.
Using directives together
You can use directives as many times on a page as you want,
and you can nest directives into each other freely. For example,
here you nest if
directive inside a
list
directive:
<#list animals as animal> <div<#if animal.protected> class="protected"</#if>> ${animal.name} for ${animal.price} Euros </div> </#list>
Note that since FreeMarker does not interpret text outside FTL tags, interpolations and FTL comments, above you could use the FTL tags inside HTML attributes without problem.
Using built-ins
The so-called built-ins are like subvariables (or rather like
methods, if you know that Java term) that aren't coming from the
data-model, but added by FreeMarker to the values. In order to make
it clear where subvariables comes from, you have to use
?
(question mark) instead of .
(dot) to access them. Examples with some of the most
commonly used built-ins:
-
user?upper_case
gives the upper case version of the value ofuser
(like "JOHN DOE" instead of "John Doe") -
animal.name?cap_first
give theanimal.name
with its first letter converted to upper case (like "Mouse" instead of "mouse") -
user?length
gives the number of characters in the value ofuser
(8 for "John Doe") -
animals?size
gives the number of items in theanimals
sequence (3 in our example data-model) -
If you are between
<#list animals as animal>
and the corresponding</#list>
tag:-
animal?index
gives the 0-based index ofanimal
insideanimals
-
animal?counter
is likeindex
, but gives the 1-based index -
animal?item_parity
gives the strings "odd" or "even", depending on the current counter parity. This is commonly used for coloring rows with alternating colors, like in<td class="${animal?item_parity}Row">
.
-
Some built-ins require parameters to specify the behavior more, for example:
-
animal.protected?string("Y", "N")
return the string "Y" or "N" depending on the boolean value ofanimal.protected
. -
animal?item_cycle('lightRow', 'darkRow')
is the more generic variant ofitem_parity
from earlier. -
fruits?join(", ")
: converts the list to a string by concatenating items, and inserting the parameter separator between each items (like "orange, banana") -
user?starts_with("J")
gives boolean true of false depending on ifuser
starts with the letter "J" or not. -
animals?filter(it -> it.protected)
gives the list of protected animals. To list protected animals only, you could use<#list animals?filter(it -> it.protected) as animal>...</#list>
.
Built-in applications can be chained, like
fruits?join(", ")?upper_case
will first convert
the list a to a string, then converts it to upper case. (This is
just like you can chain .
-s (dots) too.)
You can find the full set of built-ins in the Reference.
Dealing with missing variables
The data-model often has variables that are optional (i.e., sometimes missing). To spot some typical human mistakes, FreeMarker doesn't tolerate references to missing variables unless you tell explicitly what to do if the variable is missing. Here we will show the two most typical ways of doing that.
Note for programmers: A
non-existent variable and a variable with null
value is the same for FreeMarker. The "missing" term used here
covers both cases.
Wherever you refer to a variable, you can specify a default
value for the case the variable is missing by following the variable
name with a !
and the default value. Like in the
following example, when user
is missing from data
model, the template will behave like if user
's
value were the string "visitor"
. (When
user
isn't missing, this template behaves exactly
like with ${user}
):
<h1>Welcome ${user!"visitor"}!</h1>
You can ask whether a variable isn't missing by putting
??
after its name. Combining this with the
already introduced if
directive you can skip the
whole greeting if the user
variable is
missing:
<#if user??><h1>Welcome ${user}!</h1></#if>
Regarding variable accessing with multiple steps, like
animals.python.price
, writing
animals.python.price!0
is correct only if
animals.python
is never missing and only the last
subvariable, price
, is possibly missing (in which
case here we assume it's 0
). If
animals
or python
is missing,
the template processing will stop with an "undefined variable"
error. To prevent that, you have to write
(animals.python.price)!0
. In that case the
expression will be 0
even if
animals
or python
is missing.
Same logic goes for ??
;
animals.python.price??
versus
(animals.python.price)??
.
Escaping for HTML, XML and other markup
Let's say the template generates HTML, and you insert values
with ${...}
that are
plain text (not HTML), like company names coming from a database.
Characters that has special meaning in HTML must be
escaped in such values, like if
name
is "Someone & Co." then
${name}
should print "Someone
& Co.".
FreeMarker automatically escapes all values printed with
${...}
if
it's properly configured (that's the responsibility of
the programmers; see here how). The
recommended practice is using ftlh
file extension
to activate HTML auto-escaping, and ftlx
file
extension to activate XML auto-escaping.
You can try if auto-escaping is on like
${"<"}
and then checking the raw output (for
HTML or XML escaping). If it's not, and the configuration won't be
adjusted, add this as the very first line of the template:
<#ftl output_format="HTML">
(Use "XML"
instead of
"HTML"
above if you generate XML.)
If the string value to print deliberately contains markup,
auto-escaping must be prevented like
${value?no_esc}
.
You can find out much more about auto-escaping and output formats here...
The kind of automatic escaping described here requires at
least FreeMarker 2.3.24. If you have to use an earlier version,
use the deprecated escape
directive instead.