Spring Boot Thymeleaf tutorial

In Spring Boot Thymeleaf tutorial, we are going to create a simple Spring Boot web application. The application uses Thymeleaf template engine and H2 database.

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

H2 is an open source relational database management system created entirely in Java. It can be embedded in Java applications or run in the client-server mode. It is easy to deploy and install and has small footprint.

Thymeleaf is a modern server-side Java template engine for both web and standalone environments. It builds on the he concept of natural templates: template files that can be directly opened in browsers and that still display correctly as web pages. Spring Boot automatically configures Thymeleaf when it finds the dependency in the Maven POM file.

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── Application.java
    │   │           ├── bean
    │   │           │   └── Car.java
    │   │           ├── controller
    │   │           │   └── MyController.java
    │   │           └── service
    │   │               ├── CarService.java
    │   │               └── ICarService.java
    │   └── resources
    │       ├── application.yml
    │       ├── data-h2.sql
    │       ├── schema-h2.sql
    │       ├── static
    │       │   └── css
    │       │       └── style.css
    │       └── templates
    │           ├── index.html
    │           └── showCars.html
    └── test
        └── java

This is the project structure. Thymeleaf template files are located in the src/main/resources/template directory by default.

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>SpringBootThymeleaf</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</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.5.3.RELEASE</version>
    </parent>    
    
    <dependencies>
        
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>                        
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>    
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</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. The spring-boot-devtools enables hot swapping, disables template cache and enables live reloading. The spring-boot-starter-thymeleaf is a starter for building Spring MVC applications with Thymeleaf. The spring-boot-starter-jdbc is a starter for using JDBC in Spring Boot.

Car.java
package com.zetcode.bean;

public class Car {
    
    private Long id;
    private String name;
    private int price;
    
    public Car() {}

    public Car(Long id, String name, int price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    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;
    }

    @Override
    public String toString() {
        return "Car{" + "id=" + id + ", name=" + name + ", price=" + price + '}';
    }
}

This is Car bean class. It contains item ID, name, and price.

application.yml
server:
    context-path: /myapp

spring: 
    main:
        banner-mode: "off"       
    datasource:
        platform: h2

logging: 
    level: 
        org: 
            springframework: ERROR

The application.yml is the main Spring Boot configuration file. The context-path defines the name of the web application. With the banner-mode property we turn off the Spring banner. The platform value is used in SQL initialization scripts: schema-${platform}.sql and data-${platform}.sql. Also, we set the logging level for spring framework to ERROR.

Notice that we do not configure the datasource; Spring automatically configures H2 in the in-memory mode if there is no configuration data. We wanted to have an in-memory database, so we leave Spring to do the automatic configuration.

schema-h2.sql
CREATE TABLE CARS(ID BIGINT PRIMARY KEY AUTO_INCREMENT, 
                  NAME VARCHAR(30), PRICE INT);

This SQL script creates the Cars table.

data-h2.sql
INSERT INTO CARS(NAME, PRICE) VALUES('Audi', 52642);
INSERT INTO CARS(NAME, PRICE) VALUES('Mercedes', 57127);
INSERT INTO CARS(NAME, PRICE) VALUES('Skoda', 9000);
INSERT INTO CARS(NAME, PRICE) VALUES('Volvo', 29000);
INSERT INTO CARS(NAME, PRICE) VALUES('Bentley', 350000);
INSERT INTO CARS(NAME, PRICE) VALUES('Citroen', 21000);
INSERT INTO CARS(NAME, PRICE) VALUES('Hummer', 41400);
INSERT INTO CARS(NAME, PRICE) VALUES('Volkswagen', 21600);

This script fills the table with data. Both scripts are located in the root of the classpath.

ICarService.java
package com.zetcode.service;

import com.zetcode.bean.Car;
import java.util.List;

public interface ICarService {

    public List<Car> findAll();
}

ICarService provides a contract method to get all cars from the data source.

CarService.java
package com.zetcode.service;

import com.zetcode.bean.Car;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class CarService implements ICarService {

    @Autowired
    private JdbcTemplate jtm;

    @Override
    public List<Car> findAll() {

        String sql = "SELECT * FROM CARS";

        List<Car> cars = jtm.query(sql, new BeanPropertyRowMapper(Car.class));

        return cars;
    }
}

CarService contains the implementation of the findAll() method. We retrieve all cars from the Cars table with the help of the JdbcTemplate.

@Autowired
private JdbcTemplate jtm;

JdbcTemplate is injected.

String sql = "SELECT * FROM CARS";

This is SQL to be executed. We select all cars from the Cars table.

List<Car> cars = jtm.query(sql, new BeanPropertyRowMapper(Car.class));

BeanPropertyRowMapper converts a row into a new instance of the specified mapped target class.

MyController.java
package com.zetcode.controller;

import com.zetcode.bean.Car;
import com.zetcode.service.ICarService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.servlet.ModelAndView;

@Controller
public class MyController {

    @Autowired
    private ICarService carService;
    
    @RequestMapping("/")
    public String index(Model model) {
        
        return "index";
    }    

    @RequestMapping("/showCars")
    public ModelAndView showCars() {

        List<Car> cars = carService.findAll();

        Map<String, Object> params = new HashMap<>();
        params.put("cars", cars);

        return new ModelAndView("showCars", params);
    }
}

This is the controller class for the Spring Boot web application. A controller is decorated with the @Controller annotation. The controller has two mappings: one mapping for the home page and one for listing all cars. Spring Boot automatically configures Thymeleaf views when it detects Thymeleaf starter in the Maven POM file.

@Autowired
private ICarService carService;

We inject the ICarService into the field with the @Autowired annotation.

@RequestMapping("/")
public String index(Model model) {
    
    return "index";
}   

The "index" is the name of the view located in the predefined template directory.

@RequestMapping("/showCars")
public ModelAndView showCars() {

    List<Car> cars = carService.findAll();

    Map<String, Object> params = new HashMap<>();
    params.put("cars", cars);

    return new ModelAndView("showCars", params);
}

This controller method serves a list of cars. We find all car objects from the car service and place the resulting list into the parameters. Spring will locate the Thymeleaf view named showCars and let the engine join the template with the model data.

style.css
h2 {color: blue}

The style.css is a static file located in the src/main/resources/static/css directory. It sets the h2 tag to blue colour.

index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Home page</title>
        <meta charset="UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    </head>
    <body>
        <a href="showCars">Show cars</a>
    </body>
</html>

The index.html is the home page of the application. It contains a link to retrieve all cars.

showCars.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Cars</title>
        <link rel="stylesheet" th:href="@{/css/style.css}" />
        <meta charset="UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    </head>
    <body>
        <h2>List of cars</h2>

        <table>
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>Price</th>
            </tr>
            <tr th:each="car : ${cars}">
                <td th:text="${car.id}">id</td>
                <td th:text="${car.name}">name</td>
                <td th:text="${car.price}">price</td>
            </tr>
        </table>

    </body>
</html>

The showCars.html is a Thymeleaf template file that contains placeholders to be filled with data from the model. To access the data, we use the ${} variable expressions.

<link rel="stylesheet" th:href="@{/css/style.css}" />

We include the static CSS file with the Thymeleaf link expression @{}. The link expression automatically adds the server context path (myapp).

<tr th:each="car : ${cars}">
    <td th:text="${car.id}">id</td>
    <td th:text="${car.name}">name</td>
    <td th:text="${car.price}">price</td>
</tr>

We iterate over the list of cars and put each car details into one table row.

Application.java
package com.zetcode;

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);
    }
}

We set up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning.

Listing cars
Figure: Listing cars

The application is deployed on the built-in Tomcat server, which listens on port 8080.

In this tutorial, we have created a Spring Boot web application with Thymeleaf and H2. You might also be interested in the related tutorials: Spring Boot Thymeleaf configuration, Spring Boot FreeMarker tutorial, Spring Boot Mustache tutorial, Spring Boot Swing integration tutorial, Introduction to Spring web applications, Standalone Spring applications, FreeMarker tutorial, Java tutorial, Introduction to Play, or Introduction to Stripes.