FreeMarker tutorial

This is an introductory tutorial of the FreeMarker Java template engine. We introduce the FreeMarker template engine and create several console and web applications. Maven is used to build our examples. NetBeans is used to manage the applications.

FreeMarker is a template engine for the Java programming language. Templates are written in the FreeMarker Template Language (FTL). FreeMarker's home page is freemarker.org.

A template engine combines static data with dynamic data to produce content. A template is an intermediate representation of the content; it specifies how the output will be generated.

The advantages of a template engine are:

A FreeMarker template has by convention a .ftl extension.

FreeMarker is not restricted to templates for HTML pages; it can be used to generate e-mails, configuration files, source code etc.

Console applications

The first two applications are console applications. We create new Maven Java Applications in NetBeans. They use the following Maven build file:

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.25-incubating</version>
</dependency>       

In the Maven pom.xml file, we specify the FreeMarker dependency.

Interpolations

Interpolations are expressions put between the ${ } characters. FreeMarker will replace an interpolation in the output with the actual value of the expression inside the curly brackets.

In the following example, we use a FreeMarker template file to generate simple text output.

Java console project structure in NetBeans
Figure: Java console project structure in NetBeans

This is the project structure in NetBeans.

FreeMarkerConsoleEx.java
package com.zetcode;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.Version;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

public class FreeMarkerConsoleEx {

    public static void main(String[] args) throws IOException,
            TemplateException {

        Configuration cfg = new Configuration(new Version("2.3.25-incubating"));

        cfg.setClassForTemplateLoading(FreeMarkerConsoleEx.class, "/");
        cfg.setDefaultEncoding("UTF-8");

        Template template = cfg.getTemplate("test.ftl");

        Map<String, Object> templateData = new HashMap<>();
        templateData.put("msg", "Today is a beautiful day");

        try (StringWriter out = new StringWriter()) {
            
            template.process(templateData, out);
            System.out.println(out.getBuffer().toString());

            out.flush();
        }
    }
}

The example prints a simple text to the console. The final text was processed by a template engine.

Configuration cfg = new Configuration(new Version("2.3.25-incubating"));

Configuration is used to set the FreeMarker settings; it takes the version of the FreeMarker library as a parameter.

cfg.setClassForTemplateLoading(FreeMarkerConsoleEx.class, "/");

The setClassForTemplateLoading() sets the class whose method will be used to load templates.

Template template = cfg.getTemplate("test.ftl");

With the getTemplate() method, we retrieve the test.ftl template file.

Map<String, Object> templateData = new HashMap<>();
templateData.put("msg", "Today is a beautiful day");

The data model is created. The data from the model will be dynamically placed into the FreeMarker template file.

try (StringWriter out = new StringWriter()) {
    
    template.process(templateData, out);
    System.out.println(out.getBuffer().toString());

    out.flush();
}

The process() method executes the template, using the provided data model and writing the generated output to the supplied writer.

test.ftl
The message is: ${msg}

The test.ftl template file contains one interpolation; it will be replaced with the generated string.

The message is: Today is a beautiful day

This is the output of the application.

Listing a collection

The #list directive lists a collection of data.

The next example produces a list of cars.

Car.java
package com.zetcode.bean;

public class Car {

    private String name;
    private int price;

    public Car() {
    }

    public Car(String name, int price) {

        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

We have a Car bean. It has two attributes: name and price.

FreeMarkerConsoleEx2.java
package com.zetcode;

import com.zetcode.bean.Car;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.Version;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FreeMarkerConsoleEx2 {

    public static void main(String[] args) throws IOException,
            TemplateException {

        Configuration cfg = new Configuration(new Version("2.3.25-incubating"));

        cfg.setClassForTemplateLoading(FreeMarkerConsoleEx2.class, "/");
        cfg.setDefaultEncoding("UTF-8");

        Template template = cfg.getTemplate("test.ftl");

        Map<String, Object> templateData = new HashMap<>();

        Car c1 = new Car("Audi", 52642);
        Car c2 = new Car("Volvo", 29000);
        Car c3 = new Car("Skoda", 9000);
        
        List<Car> cars = new ArrayList<>();
        cars.add(c1);
        cars.add(c2);
        cars.add(c3);        

        templateData.put("cars", cars);

        try (StringWriter out = new StringWriter()) {

            template.process(templateData, out);
            System.out.println(out.getBuffer().toString());

            out.flush();
        }
    }
}

This example is a Java console program, which uses FreeMarker to dynamically create a text output containing a list of cars.

Map<String, Object> templateData = new HashMap<>();

Car c1 = new Car("Audi", 52642);
Car c2 = new Car("Volvo", 29000);
Car c3 = new Car("Skoda", 9000);

List<Car> cars = new ArrayList<>();
cars.add(c1);
cars.add(c2);
cars.add(c3);        

templateData.put("cars", cars);

Here we create an ArrayList of Car objects and put it into the data model.

test.ftl
<#list cars as car>
${car.name}: ${car.price}
</#list>  

The template file contains a #list directive which prints the attributes of the car objects; the attributes are accessed with the dot character.

Audi: 52,642
Volvo: 29,000
Skoda: 9,000

This is the output of the example.

FreeMarker servlet example

In the following example, we use FreeMarker in a standard Java web application. The application is packed into a war file and deployed on the NetBeans's build-in Tomcat server.

In NetBeans, we create a new Maven Web Application.

FreeMarker servlet project structure in NetBeans
Figure: FreeMarker servlet project structure in NetBeans

This is the project structure of the FreeMarker servlet example in NetBeans.

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.25-incubating</version>
</dependency>

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>

In the pom.xml file, we have these two dependencies.

context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/FreemarkerServletEx"/>

This is the context.xml file.

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    
    <servlet>
        <servlet-name>freemarker</servlet-name>
        <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>

        <init-param>
            <param-name>TemplatePath</param-name>
            <param-value>/</param-value>
        </init-param>
        <init-param>
            <param-name>NoCache</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>ResponseCharacterEncoding</param-name>
            <param-value>fromTemplate</param-value>
        </init-param>
        <init-param>
            <param-name>ExceptionOnMissingTemplate</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>incompatible_improvements</param-name>
            <param-value>2.3.25-incubating</param-value>
        </init-param>
        <init-param>
            <param-name>template_exception_handler</param-name>
            <param-value>html_debug</param-value>
        </init-param>
        <init-param>
            <param-name>template_update_delay</param-name>
            <param-value>0 s</param-value>
        </init-param>
        <init-param>
            <param-name>default_encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>output_encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>locale</param-name>
            <param-value>en_US</param-value>
        </init-param>
        <init-param>
            <param-name>number_format</param-name>
            <param-value>0.##########</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>freemarker</servlet-name>
        <url-pattern>*.ftl</url-pattern>
    </servlet-mapping>
    
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>FreeMarker MVC Views</web-resource-name>
            <url-pattern>*.ftl</url-pattern>
        </web-resource-collection>
        <auth-constraint>
        </auth-constraint>
    </security-constraint>
        
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

In the web.xml file, we set up and configure the FreeMarker servlet. Refer to the FreeMarker documentation for the explanation of each of the options.

Car.java
package com.zetcode.bean;

public class Car {

    private String name;
    private int price;

    public Car() {
    }

    public Car(String name, int price) {

        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

This is the Car bean having basic data about a car object.

MyServlet.java
package com.zetcode.web;

import com.zetcode.bean.Car;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "MyServlet", urlPatterns = {"/"})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        Car c1 = new Car("Audi", 52642);
        Car c2 = new Car("Volvo", 29000);
        Car c3 = new Car("Skoda", 9000);

        List<Car> cars = new ArrayList<>();
        cars.add(c1);
        cars.add(c2);
        cars.add(c3);

        request.setAttribute("cars", cars);

        request.getRequestDispatcher("/index.ftl").forward(request, response);

    }
}

We set up the servlet and dispatch to the template file. We create an ArrayList of cars and set it to the request.

index.ftl
<!DOCTYPE html>
<html>
    <head>
        <title>FreeMarker test</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
    <body>
        
        <table>
            <tr>
                <th>Name</th>  
                <th>Price</th>
            </tr>        

            <#list cars as car>
                <tr>
                    <td>${car.name}</td> 
                    <td>${car.price}</td>
                </tr>
            </#list>        
        </table>                
    </body>
</html>

The index.ftl file is located in the src/main/webapp directory. With the #list directive, we show all the elements of the cars collection.

FreeMarker servlet example
Figure: FreeMarker servlet example

We show the application output in the Opera web browser. The built-in Tomcat in NetBeans operates on the 8084 port.

Spring Boot web application

Spring is a popular Java application framework. Spring Boot is a product of an effort to create stand-alone, production-grade Spring based applications with minimal effort.

In the next application, we integrate FreeMarker into a Spring Boot web application.

Spring Boot web project structure in NetBeans
Figure: Spring Boot web project structure in NetBeans

This is the project structure of the Spring Boot web application using FreeMarker in NetBeans. Note that we are creating a Java SE Maven application in NetBeans, not a Java web Maven application. This is because we have Tomcat embedded into our JAR file.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>SpringBootFreemarkerEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.2.RELEASE</version>
    </parent>

    <dependencies>
      
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>        
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>       
</project>

This is the Maven build file. It includes dependencies for Spring Boot and FreeMarker. There is no need to configure the FreeMarker in Spring Boot. Upon finding the FreeMarker dependency in the POM file, Spring Boot automatically takes care of the configuration. The spring-boot-maven-plugin creates an executable JAR with an embedded container (Tomcat by default).

SpringBootClient.java
package com.zetcode.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application  {
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

The Application sets up the Spring Boot application. The @EnableAutoConfiguration annotation enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that we are likely to need.

MyController.java
package com.zetcode.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class MyController {
      
    @GetMapping("/")
    public String index(Model model) {
        return "index";
    }    
    
    @GetMapping("/hello")
    public String hello(Model model, @RequestParam(value="msg", required=false, 
            defaultValue="Freemarker") String msg) {
        
        model.addAttribute("message", msg);
        return "hello";
    }    
}

This is the controller class for the Spring Boot web application. The controller has two mappings. The first mapping resolves to the index.ftl file and the second mapping to the hello.ftl file.

index.ftl
<!DOCTYPE html>
<html>
    <head>
        <title>Spring Boot Form</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <form action="/hello" method="get">
            <p>Message: <input type="text" name="msg"></p>
            <p>
                <input type="submit" value="Submit"> 
                <input type="reset" value="Reset">
            </p>
        </form>
    </body>
</html>

This is the index.ftl file. It has an HTML form which sends a message to the server.

hello.ftl
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Freemarker example</title>
</head>
<body>
    <p>${message}<p>
</body>
</html>

The server responds with a message back to the client. The response is created from the hello.ftl template file.

Spring Boot web example
Figure: Spring Boot web example

The Spring Boot starts an embedded Tomcat server, listening on port 8080.

This tutorial was dedicated to the FreeMarker template engine. You might also be interested in the related tutorials: Servlet FreeMarker JDBCTemplate tutorial, Jtwig tutorial, Java tutorial, Introduction to Play, Introduction to Spark, or Introduction to Stripes.