Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

Thymeleaf is a template engine popular in the Java ecosystem. It helps bind data from the controller layer to the view layer. Thymeleaf attributes are set using expressions. In this tutorial, we’ll discuss expression types with examples.

2. Example Setup

We’ll use the simple web application Dino as an example. It’s a simple web app to create a dinosaur profile.

First, let’s create a model class for our dinosaur:

public class Dino {
    private int id;
    private String name;
    // constructors   
    // getter and setter
}

Next, let’s create a controller class:

@Controller
public class DinoController {

    @RequestMapping("/")
    public String dinoList(Model model) {
        Dino dinos = new Dino(1, "alpha", "red", 50);
        model.addAttribute("dinos", dinos);
        return "index";
    }
}

With our example setup, we can inject an instance of Dino into our template files.

3. Variable Expression

Variable expression helps to inject data from the controller into the template file. It exposes model attributes to the web view.

The variable expression syntax combines a dollar sign and curly braces. Our variable name resides inside the curly braces:

${...}

Let’s inject our Dino data into the template file:

<span th:text="${dinos.id}"></span> 
<span th:text="${dinos.name}"></span>

Conditionals and iteration can also use a variable expression:

<!-- for iterating -->
<div th:each="dinos : ${dinos}">

<!-- in conditionals -->
<div th:if="${dinos.id == 2}">

4. Selection Expression

Selection expression operates on a previously chosen object. It helps us select the child of the chosen object.

The selection expression syntax is a combination of asterisk and curly braces. Our child object resides inside the curly braces:

*{...}

Let’s select the id and name of our Dino instance and inject it into our template file:

<div th:object="${dinos}">
    <p th:text="*{id}">
    <p th:text="*{name}">
</div>

Furthermore, selection expression is primarily used within a form in HTML. It helps bind form inputs with model attributes.

Unlike variable expression, treating each input element individually is unnecessary. Using our Dino web app as an example, let’s create a new instance of Dino and bind it to our model attribute:

<form action="#" th:action="@{/dino}" th:object="${dinos}" method="post">
    <p>Id: <input type="text" th:field="*{id}" /></p>
    <p>Name: <input type="text" th:field="*{name}" /></p>
</form>

5. Message Expression

This expression helps bring externalized text into our template file. It’s also called text externalization.

The external source where our text resides could be a .properties file. This expression is dynamic when it has placeholder(s).

The message expression syntax is a combination of hash and curly braces. Our key resides inside the curly braces:

#{...}

For example, let’s assume we wanted to display a specific message throughout the pages of our Dino web app. We can put the message in a messages.properties file:

welcome.message=welcome to Dino world. 

To bind the welcome message to our view templates, we can reference it by its key:

<h2 th:text="#{welcome.message}"></h2>

We can have message expression accept parameters by adding a placeholder in our external file:

dino.color=red is my favourite, mine is {0}

In our template file, we’ll reference the message and add a value to the placeholder:

<h2 th:text="#{dino.color('blue')}"></h2>

Additionally, we can make our placeholder dynamic by injecting a variable expression as the value of the placeholder:

<h2 th:text="#{dino.color(${dino.color})}"></h2>
This expression is also called internationalization. It can help us adapt our web application to accommodate different languages.
Link expressions are integral in URL building. This expression binds to the specified URL.
 
The link expression syntax combines the “at” sign and curly braces. Our link resides inside the curly braces:
@{...}

URLs can be absolute or relative. When using a link expression with absolute URLs, it binds to the full URL starting with “http(s)“:

<a th:href="@{http://www.baeldung.com}"> Baeldung Home</a>

A relative link, on the other hand, binds to the context of our web server. We can easily navigate through our template files as defined in the controller:

@RequestMapping("/create")
public String dinoCreate(Model model) {
    model.addAttribute("dinos", new Dino());
    return "form";
}

We can request the page as specified in @RequestMapping:

<a th:href="@{/create}">Submit Another Dino</a>

It can take parameters through path variables. Let’s assume we wanted to provide a link to edit an existing entity. We can invoke the object we want to edit through its id. Link expressions can accept the id as a parameter:

<a th:href="/@{'/edit/' + ${dino.id}}">Edit</a>

Link expressions can set protocol-relative URLs. Protocol-relative is like an absolute URL. The URL will use the HTTP or HTTPS protocol scheme, depending on the server’s protocol:

<a th:href="@{//baeldung.com}">Baeldung</a>

7. Fragment Expression

Fragment expression can help us move markup(s) between our template files. The expression enables us to generate a moveable markup fragment.

The fragment expression syntax is a combination of tilde and curly braces. Our fragment resides inside the curly braces:

~{...}

For our Dino web app, let’s create a footer in our index.html file with a fragment attribute:

<div th:fragment="footer">
    <p>Copyright 2022</p>
</div>

We can now inject the footer into other template files:

<div th:replace="~{index :: footer}"></div>

8. Conclusion

In this article, we looked at various Thymeleaf simple expressions and examples.

As always, the complete source code for the examples is available on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
1 Comment
Oldest
Newest
Inline Feedbacks
View all comments
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.