FreeMarker tutorial
last modified July 6, 2020
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.
Table of contents
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.
FreeMarker template engine
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:
- separation of concerns,
- avoiding repetition of code,
- easier switching between views,
- reusability.
A FreeMarker template file 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.
FreeMarker 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.23</version> </dependency>
In the Maven pom.xml
file, we specify the FreeMarker dependency.
FreeMarker 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.

This is the project structure in NetBeans.
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.23")); 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.23"));
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.
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 with FreeMarker
The #list
directive lists a collection of data.
The next example produces a list of cars.
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.
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.23")); 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.
<#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 directives
FreeMarker directives are special tags that perform an action. There are two kinds of directives: built-in and custom.
The <#assign>
tag creates a new plain variable.
It can be accessed with the ${}
construct. The variable
is created in the template. If there is an equally named variable
in the data model, the template variable hides it.
<#assign name = "Robert"> His name is ${name}.
The <#assign>
directive creates a new name
variable.
The value of the variable is printed with the ${name}
syntax.
His name is Robert.
The example prints this line.
Conditional processing of template sections can be done with he <#if>
,
<#elseif>
, and <#else>
directives.
<#assign value = 4> <#if value < 0> The number is negative <#elseif value == 0> The number is zero <#else> The number is positive </#if>
The example creates a new value
variable and uses conditional
directives to test the value.
The number is positive
This is the output.
The <#list>
directive is used for traversing a sequence.
<#assign colours = ["red", "green", "blue", "yellow"]> <#list colours as col> ${col} </#list>
In the example, we assing a new sequence of colour names to the
colours
variable. The <#list>
directive goes
through the collection and prints each item.
red green blue yellow
The example gives this output.
<#assign items = {"pens": 3, "cups": 2, "tables": 1}> <#list items?values as v> ${v} </#list> <#list items?keys as k> ${k} </#list>
In this example, we create a hash variable and use the <#list>
to output the values and the keys of the hash.
3 2 1 pens cups tables
The example gives this output.
The <#compress>
directive removes superfluous white-space when
we use a white-space insensitive format (e.g. HTML or XML)
<#assign value="\t\tweather\n\n"> <#compress> ${value} Today is a wonderful day. 1 2 3 4 5 </#compress>
We have text with spaces, tabs, and new lines.
weather Today is a wonderful day. 1 2 3 4 5
The program removed all superfluous white-space.
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.

This is the project structure of the FreeMarker servlet example in NetBeans.
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</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.
<?xml version="1.0" encoding="UTF-8"?> <Context path="/FreemarkerServletEx"/>
This is the context.xml
file.
<?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.23</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.
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.
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.
<!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.

We show the application output in the Opera web browser. The built-in Tomcat in NetBeans operates on the 8084 port.
FreeMarker with Spark
Spark is a simple and lightweight Java web framework built for rapid development.
Spark runs on an embedded Jetty web server by default, but can be configured to
run on other webservers.
To integrate FreeMarker with Spark, we use spark-template-freemarker
, the
Freemarker Template Engine implementation for Spark.
$ tree . ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ └── SparkFreeMarker.java │ └── resources │ └── views │ └── hello.ftl └── test └── java
This is the project structure.
<?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>SparkFreeMarker</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> <dependencies> <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-template-freemarker</artifactId> <version>2.5.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.24</version> </dependency> <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.5.5</version> </dependency> </dependencies> <build> <finalName>SparkFreeMarker</finalName> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>com.zetcode.SparkFreeMarker</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build> </project>
The pom.xml
file contains dependencies
for Spark modules and FreeMarker.
package com.zetcode; import freemarker.template.Configuration; import freemarker.template.Version; import java.io.IOException; import java.util.HashMap; import java.util.Map; import spark.ModelAndView; import spark.Request; import spark.Response; import static spark.Spark.get; import spark.template.freemarker.FreeMarkerEngine; public class SparkFreeMarker { public static void main(String[] args) throws IOException { Configuration conf = new Configuration(new Version(2, 3, 23)); conf.setClassForTemplateLoading(SparkFreeMarker.class, "/views"); get("/hello/:name", SparkFreeMarker::message, new FreeMarkerEngine(conf)); } public static ModelAndView message(Request req, Response res) { Map<String, Object> params = new HashMap<>(); params.put("name", req.params(":name")); return new ModelAndView(params, "hello.ftl"); } }
We set up the same application for FreeMarker.
Configuration conf = new Configuration(new Version(2, 3, 23)); conf.setClassForTemplateLoading(SparkFreeMarker.class, "/views");
We configure FreeMarker with the Configuration
class.
The template files are going to be placed into the views
directory,
which must be located on the classpath.
get("/hello/:name", SparkFreeMarker::message, new FreeMarkerEngine(conf));
The FreeMarkerEngine
is passed to the get()
method.
public static ModelAndView message(Request req, Response res) { Map<String, Object> params = new HashMap<>(); params.put("name", req.params(":name")); return new ModelAndView(params, "hello.ftl"); }
The ModelAndView
is used to set the name of the view and
the model object to be rendered.
<!DOCTYPE html> <html> <head> <title>Home page</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <p>Hello ${name}</p> </body> </html>
This is the hello.ftl
template file; it refers to the name variable
which was passed with the ModelAndView
object.
$ mvn package
We build the project with mvn package
command.
$ java -jar target/SparkFreeMarkejar-with-dependencies.jar
We run the program. The maven-assembly-plugin
allows to create an
executable JAR with all dependencies.
$ curl localhost:4567/hello/Thomas <!DOCTYPE html> <html> <head> <title>Home page</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <p>Hello Thomas</p> </body> </html>
This is the output.
FreeMarker with Spring
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.
Classic Spring application
In the following example, we integrate FreeMarker into a classic Spring application.
├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── service │ │ │ ├── IVersionService.java │ │ │ └── VersionService.java │ │ └── web │ │ └── MyController.java │ ├── resources │ │ └── my.properties │ └── webapp │ ├── META-INF │ │ └── context.xml │ └── WEB-INF │ ├── spring-servlet.xml │ ├── views │ │ ├── index.ftl │ │ └── version.ftl │ └── web.xml └── test └── java
This is the project structure of our classic Spring application.
<?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>ClassicSpringFreeMarker</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>ClassicSpringFreeMarker</name> <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> <dependencies> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.6.RELEASE</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project>
The pom.xml
file contains dependencies for Spring modules and FreeMarker.
<?xml version="1.0" encoding="UTF-8"?> <web-app 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" version="3.1"> <servlet> <servlet-name>spring</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> </web-app>
In the web.xml
file, we define Spring DispatcherServlet
, which is
the central dispatcher for HTTP request handlers.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.zetcode"/> <context:property-placeholder location="classpath*:my.properties"/> <!--freemarker config--> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/views/"/> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".ftl"/> </bean> </beans>
In the spring servlet context XML file we define two beans: freemarkerConfig
and viewResolver
. These are configuration beans for FreeMarker.
The spring-servlet.xml is located in WEB-INF
.
<context:component-scan base-package="com.zetcode" />
Spring will scan for components in the com.zetcode
package.
<context:property-placeholder location="classpath*:my.properties"/>
The <context:property-placeholder>
element registers a
PropertySourcesPlaceholderConfigurer
, which allows to set properties
with the @Value
annotation. The location
attribute
tells where to look for properties.
app.version: "1.0"
In the my.properties
file we have one key/value pair. The value
is the version of the application. The file is located in the
usr/main/resources
directory.
package com.zetcode.service; public interface IVersionService { public String getVersion(); }
The IVersionService
interface contains one method
contract: getVersion()
.
package com.zetcode.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class VersionService implements IVersionService { @Value("${app.version}") private String appVersion; @Override public String getVersion() { return appVersion; } }
The VersionService
returns the version of the application.
@Value("${app.version}") private String appVersion;
The value from the app.version
key, located in the my.properties
file, is injected into the appVersion
attribute.
package com.zetcode.web; import com.zetcode.service.VersionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; @Controller public class MyController { @Autowired private VersionService versionService; @RequestMapping("/index") public String index(Model model) { return "index"; } @RequestMapping(value = "/version", method = RequestMethod.GET) public ModelAndView version() { String version = versionService.getVersion(); ModelAndView model = new ModelAndView("version"); model.addObject("version", version); return model; } }
This is the controller class.
@RequestMapping(value = "/version", method = RequestMethod.GET) public ModelAndView version() { String version = versionService.getVersion(); ModelAndView model = new ModelAndView("version"); model.addObject("version", version); return model; }
In the version
method, which is called when a request with
/version
URL arrives, we call the VersionService's
getVersion()
method and pass the value into the
ModelAndView
. The processing is dispatched to the
version.ftl
template file, where the version value is inserted.
<!DOCTYPE html> <html> <head> <title>Home page</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <p>Show application version <a href="version.html">version</a></p> </body> </html>
This is the index.ftl
file. It has an link which sends a request
to the server to get the version of the application.
<!DOCTYPE html> <html> <head> <title>Home page</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <p>Application version: ${version}</p> </body> </html>
The version.ftl
template file is used to build the server
response to the client.
Spring Boot web application using FreeMarker
In the next application, we integrate FreeMarker into a Spring Boot web application.

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.
<?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).
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 @SpringBootApplication
annotation does three things:
1) defines the class as a configuration class, 2) enables auto-configuration,
3) enables component scanning.
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.
<!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.
<!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.

The Spring Boot starts an embedded Tomcat server, listening on port 8080.
This tutorial was dedicated to the FreeMarker template engine.
List all Java tutorials.