Creating your first FreeMarker Template

Exclusive offer: get 50% off this eBook here
Instant FreeMarker Starter [Instant]

Instant FreeMarker Starter [Instant] — Save 50%

Structure your enterprise-class projects with FreeMarker! with this book and ebook

$14.99    $7.50
by Charles Forsythe | July 2013 | Open Source Web Development

In this article created by Charles Forsythe, the author of Instant FreeMarker Starter we'll write a small Java application that will process a template and send the results to the console. There are several goals to this exercise. The first is to get you up and running with FreeMarker quickly. The second is to provide a clear demonstration about what FreeMarker does by showing it in operation outside of any other application framework. Finally, you'll see how little effort is actually required to generate a working FreeMarker application.

(For more resources related to this topic, see here.)

Step 1 – setting up your development directory

If you haven't done so, create a directory to work in. I'm going to keep this as simple as possible, so we won't need a complicated directory structure. Everything can be done in one directory.Put the freemarker.jar in the directory. All future talk about files and running from the command-line will refer to your working directory. If you want to, you can set up a more advanced project-like set of directories.

Step 2 – writing your first template

This is a quick start, so let's just dive in and write the template. Open a file for editing called hello.ftl. The ftl extension is customary for FreeMarker Template Language files, but you are free to name your template files anything you want. Put this line in your file:

Hello, ${name}!

FreeMarker will replace the ${name} expression with the value of an element called name in the model. FreeMarker calls this an interpolation. I prefer to refer to this as "evaluating an expression", but you will encounter the term interpolation in the documentation.

Everything else you have put in this initial template is static text. If name contained the value World, then this template would evaluate to:

Hello, World!

Step 3 – writing the Java code

Templates are not scripts that can be run, so we need to write some Java code to invoke the FreeMarker engine and combine the template with a populated model. Here is that code:

import java.io.*;
import java.util.*;
import freemarker.template.*;
public class HelloFreemarker {

public static void main(String[] args)
throws IOException, TemplateException {
Configuration cfg = new Configuration();
cfg.setObjectWrapper(new DefaultObjectWrapper());
cfg.setDirectoryForTemplateLoading(new File("."));
Map<String, Object> model = new HashMap<String, Object>();
model.put("name", "World");
Template template = cfg.getTemplate("hello.ftl");
template.process(model,
new OutputStreamWriter(System.out));
}
}

The highlighted line says that FreeMarker should look for FTL files in the "working directory" where the program is run as a simple Java application. If you set your project up differently, or run in an IDE, you may need to change this to an absolute path.

The first thing we do is create a FreeMarker freemarker.template.Configuration object. This acts as a factory for freemarker.template.Template objects.

FreeMarker has its own internal object types that it uses to extract values from the model.In order to use the objects that you supply, it must wrap these in its own native types. The job of doing this is done by an object wrapper. You must provide an object wrapper. It will always be FreeMarker's own freemarker.template.DefaultObjectWrapper unless you havespecial object wrapping requirements.

Finally, we set the root directory for loading templates. For the purposes of our sample code, everything is in the same directory so we just set it to ".". Setting the template directory can throw an java.lang.IOException exception in this code. We simply allow that to be thrown out of the method.

Next, we create our model, which is a simple map of java.lang.String keys to java.lang.Object values. The values can be simple object types such as String or java.lang.Number, or they can be complex object types, including arrays and collections. Our needs are simple here, so we're going to map "name" to the string "World".

The next step is to get a Template object. We ask the Configuration instance to load the template into a Template object. This can also throw an IOException.

The magic finally happens when we ask the Template instance to process the model and create an output. We already have the model, but where does the output go? For this, we need an implementation of java.io.Writer. For convenience, we are going to wrap the java.io.PrintWriter in java.lang.System.out with a java.io.OutputStreamWriter and give that to the template.

After compiling this program, we can run it from the command line:

java -cp .;freemarker.jar HelloFreemarker

For Linux or OSX, you would use a ":" instead of a ";" in the command:

java -cp .:freemarker.jar HelloFreemarker

The result should be that the program prints out:

Hello, World!

Step 4 – moving beyond strings

If you plan to create simple templates populated with preformatted text, then you now know all you need to know about FreeMarker. Chances are that you will, so let's take a look at how FreeMarker handles formatting other types and complex objects.

Let's try binding the "name" object in our model to some other types of objects. We can replace:

model.put("name", "World");

with:

model.put("name", 123456789);

The output format of the program will depend on the default locale, so if you are in the United States, you will see this:

Hello, 123,456,789!

If your default locale was set to Germany, you would see this:

Hello, 123.456.789!

FreeMarker does not call toString() method on instances of Number types it employs java.text.DecimalFormat. Unless you want to pass all of your values to FreeMarker as preformatted strings, you are going to need to understand how to control the way FreeMarker converts values to text.

If preformatting all of the items in your model sounds like a good idea, it isn't. Moving "view" logic into your "controller" code is a sure-fre way to make updating the appearance of your site into a painful experience.

Step 5 – formatting different types

In the previous section, we saw how FreeMarker will choose a default method of formatting numbers. One of the features of this method is that it employs grouping separators: a comma or a period every three digits. It may also use a comma rather than a period to denote the decimal portion of the number. This is great for humans who may expect these formatting details, but if your number is destined to be parsed by a computer, it needs to be free of grouping separators and it must use a period as a decimal point. In this case, you need a way to control how FreeMarker decides to format a number.

In order to control exactly how model objects are converted to text FreeMarker provides operators called built-ins. Let's create a new template called types.ftl and put in some expressions that use built-ins to control formatting:

String: ${string?html}
Number: ${number?c}
Boolean: ${boolean?string("+++++", "-----")}
Date: ${.now?time}
Complex: ${object}

The value .now come is a special variable that is automatically provided by FreeMarker. It contains the date and time when the Template began processing. There are other special variables, but this is the only one you're likely to use.

This template is a little more complicated than the last template. The " ?" at the end of a variable name denotes the use of a built-in. Before we explore these particular built-ins, let's see them in action. Create a java program, FreemarkerTypes, which populates a model with values for our new template:

import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import freemarker.template.*;
public class FreemarkerTypes {
public static void main(String[] args)
throws IOException, TemplateException {
Configuration cfg = new Configuration();
cfg.setObjectWrapper(new DefaultObjectWrapper());
cfg.setDirectoryForTemplateLoading(new File("."));

Map<String, Object> model = new HashMap<String, Object>();
model.put("string", "easy & fast ");
model.put("number", new BigDecimal("1234.5678"));
model.put("boolean", true);
model.put("object", Locale.US);
Template template = cfg.getTemplate("types.ftl");
template.process(model, new OutputStreamWriter(System.out));
}
}

Run the FreemarkerType program the same way you ran HelloFreemarker. You will see this output:

String: easy &amp; fast
Number: 1234.5678
Boolean: +++++
Date: 9:12:33 AM
Complex: en_US

Let's walk through the template and see how the built-ins affected the output. Our purpose is to get a solid foundation in the basics. We'll look at more details about how to use FreeMarker features in later articles.

  • First we output a String modified with the html built-in. This encoded the string for HTML, turning the & into the &amp; HTML entity. You will want this applied to a lot of your expressions on HTML pages in order to ensure proper display of your text and to prevent cross-site scripting ( XSS ) attacks.
  • The second line outputs a number with the c built-in. This tells FreeMarker that the number should be written for parsing by computers. As we saw in the previous section, FreeMarker will by default format numbers with grouping separators. It will also localize the decimal point, using a comma instead of a period. This is great when you are displaying numbers to humans, but not computers. If you want to put an ID number in a URL or a price in an XML document, you will want to use this built-in to format it.
  • Next, we format a Boolean. It may surprise you to learn that unless you use the string built-in, FreeMarker will not format a Boolean value at all. In fact, it throws an exception. Conceptually, "true" and "false" have no universal text representation. If you use string with no arguments, the interpolation will evaluate to either "true" or "false", but this is a default you can change. Here, we have told the built-in to use a series of + characters for "true" and a series of – characters for "false".
  • Another type which FreeMarker will not process without a built-in is java.util.Date. The main issue here is that FreeMarker doesn't know whether you want to display a date, a time, or both. By specifying the time built-in we are letting FreeMarker know that we want to display a time. The output shown previously was generated shortly past nine o'clock in the morning.
  • Finally, we see a complex object converted to text with no built-ins. Complex objects are turned into text by calling their toString() method, so you can use string built-ins on them.

Step 6 – where do we go from here?

We've reached the end of the Quick start section. You've created two simple templates and worked with some of the basic features of FreeMarker. You might be wondering what are the other built-ins, or what options they offer. In the upcoming sections we'll look at these options and also ways to change the default behavior.

Another issue we've glossed over is errors. Once you have applied some of these built-ins, you must make sure that you supply the correct types for the named model elements. We also haven't looked at what happens when a referenced model element is missing. The FreeMarker manual provides excellent reference for all of this. Rather than trying to find your way around on your own, we'll take a guided tour through the important features in the Top Features section of the article.

Quick start versus slow start

A key difference between the Quick start and Top Features sections is that we'll be starting with the sample output. In this article, we created templates and evaluated them to see what we would get. In a real-world project, you will get better results if you worked backwards from the desired result.

In many cases, you won't have a choice. The sample output will be generated by web designers and you will be expected to produce the same HTML with dynamic content. In other cases, you will need to work from mock-ups and decide the HTML for yourself. In these cases, it is still worth creating a static sample document. These static samples will show you where you need to apply some of the techniques.

Summary

In this article, we discussed how to create a freemarker template.

Resources for Article:


Further resources on this subject:


Instant FreeMarker Starter [Instant] Structure your enterprise-class projects with FreeMarker! with this book and ebook
Published: April 2013
eBook Price: $14.99
See more
Select your format and quantity:

About the Author :


Charles Forsythe

Charles Forsythe is a Systems Architect who works primarily in Java. Since graduating from the Massachusetts Institute of Technology in 1987, he has developed solutions for industries including Telecommunications, Health Care, Travel, Defense, and more. The projects ranged from embedded systems to global e-commerce systems. In the e-commerce sphere, Charles has used FreeMarker in several large projects. He currently lives in Saint Louis, Missouri.

Books From Packt


Alfresco Share
Alfresco Share

Alfresco 3 Web Content Management
Alfresco 3 Web Content Management

Apache Struts 2 Web Application Development
Apache Struts 2 Web Application Development

OpenCart 1.4 Template Design Cookbook
OpenCart 1.4 Template Design Cookbook

Alfresco Developer Guide
Alfresco Developer Guide

Alfresco 3 Records Management
Alfresco 3 Records Management

Apache Solr 3 Enterprise Search Server
Apache Solr 3 Enterprise Search Server

Apache Tomcat 7 Essentials
Apache Tomcat 7 Essentials


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software