Spring Boot: Thymeleaf

Spring Boot View Thymeleaf

Spring-Boot
View
thymeleaf
Spring Boot View
Author

albertprofe

Published

Tuesday, June 1, 2021

Modified

Tuesday, September 26, 2023

In Spring Boot, the Model-View-Controller (MVC) pattern is used to separate the application logic into three components: Model - View -Controller

📘 Thymeleaf

Thymeleaf is a modern server-side Java template engine for both web and standalone environments.


Spring Boot Request-Response Cycle

Spring Boot Request-Response Cycle

Thymeleaf

Thymeleaf

1 Overview

Thymeleaf uses HTML attributes to add functionality and dynamic behavior to web pages, allowing for server-side rendering and template processing.

<p th:text="'Thymeleaf will display this'">text</p>

Here Thymeleaf will process the text inside the th:text attribute, and replace the contents of the <p> tag with it.

Thymeleaf works by replacing the contents of the tags that its attributes are defined on. so the final in the browser output will be:

<p>Thymeleaf will display this</p>

Notice that the special attributes are now gone, as well as the text “text” which is now replace with the contents of the Thymeleaf attribute.

A more complicated example:

<tr th:each="prod : ${prods}">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
<tr>

Here Thymeleaf will repeat the <tr> with the list of products, this is defined by the attribute th:each, it will also remove the dummy content in both the <td> tags, and replace them with the content that is evaluated from th:text="${prod.name}" and th:text="${prod.price}".

2 Configuration

In order to use thymeleaf in a project, we need to add the following starter to the dependency:

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

The starter spring-boot-starter-thymeleaf added to the project, thanks to the auto-configuration mechanism. Default values include:

  • HTML templates should be in the resources/templates directory (this is the so-called root)
  • files should have the html extension (so we won’t have to duplicate this information in the code)
  • viewResolver has an appropriate implementation (thymeleafViewResolver)

3 Passing data to views: @Controller and View

The @Controller will retrun a String object: it will display an HTML view with the appropriate message at the address:

http://localhost:8080/

Thymeleaf allows you to define templates of HTML views. In order to be able to use additional Thymeleaf functionalities we need to add the appropriate **namespace** to the HTML document (and the html tag):

xmlns:th=“http://www.thymeleaf.org”

Define the places to replace in the HTML template as follows:

in the tag we indicate the attribute that should be replaced with the name. We precede this attribute with the name namespace and the character :, e.g.:

<p th:text=...></p>

indicate the value to be replaced inside the braces and precede it with a dollar sign, e.g. ${myCustomAttributeName}

4 Messages

Thymeleaf by default allows you to define such messages in the messages.properties file, which by default should be located directly in the resources directory.

In this file we store the keys and the corresponding values. In the HTML template, we refer to the key using the # sign:

hi.msg=Hi there!

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
    <p th:text="#{hi.msg}"></p

    <a href="?lang=fr">Français</a>

</body>
</html>

In application.properties, we should define locale:

spring.mvc.locale=en

We could add another lenguage by creating a new file named messages_fr.properties (messages_cat.properties, messages_es.properties, messages_ja.properties) in the same directory.

This approach also allows the implementation of internationalization by means of the so-called interceptors:

@Bean
public LocaleResolver localeResolver() {
    SessionLocaleResolver resolver = new SessionLocaleResolver();
    resolver.setDefaultLocale(Locale.ENGLISH);
    return resolver;
}

@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
    LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
    interceptor.setParamName("lang");
    return interceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(localeChangeInterceptor());
}

5 ThymeLeaf Templates Engine

Most Thymeleaf attributes allow their values to be set as or containing expressions, which we will call Standard Expressions because of the dialects they are used in. These can be of five types:

Thymeleaf expresssions
  • ${…} : Variable expressions.
  • *{…} : Selection expressions.
  • #{…} : Message (i18n) expressions.
  • @... : Link (URL) expressions.
  • ~{…} : Fragment expressions.
  • __{…} : use an element inside another

Attributes th:

Thyemleaf attributes
  • message: <p th:text="#{msg.welcome}">Welcome everyone!</p>
  • list: <li th:each="book : ${books}" th:text="${book.title}">En las Orillas del Sar</li>
  • link: <form th:action="@{/createOrder}">
  • action: <input type="button" th:value**="#{form.submit}" />
  • path: <a th:href="@{/admin/users}">

How to write th:

ThymeLeaf how TH: works (1/3)

ThymeLeaf how TH: works (1/3)

6 Fragments

Using fragments in Thymeleaf can make it easier to maintain and update web pages, as changes to a fragment will be reflected in all pages that include it.

In Thymeleaf, a fragment is a reusable piece of a web page that can be included in multiple pages. It can contain HTML markup, Thymeleaf expressions, and other Thymeleaf features.

Fragments are defined in Thymeleaf using the th:fragment attribute, which is added to any HTML element.

The value of the attribute is the name of the fragment. For example:

<div th:fragment="header">
   <h1>Welcome to my website!</h1>
</div>

This defines a fragment called “header” that contains a heading element. This fragment can then be included in other pages using the th:replace or th:include attributes.

For example:

<html>
   <body>
      <div th:replace="fragments/header :: header"></div>
      <p>This is the content of my page.</p>
   </body>
</html>

This code includes the “headerfragment in the page using the th:replace attribute. The :: syntax is used to specify the fragment name, and the fragments/header prefix specifies the location of the fragment file.

7 Layout

Using the Layout Dialect can make it easier to maintain a consistent layout across your web pages, and simplify the process of creating new pages.

Thymeleaf Layout Dialect is a third-party dialect that provides a way to define a common layout for a set of web pages in Thymeleaf.

With the Layout Dialect, you can define a template that contains the common structure and layout of your web pages, and then include the content of each page in the appropriate section of the template.

To use the Layout Dialect, you need to add the dialect dependency (for Maven):

<dependency>
   <groupId>nz.net.ultraq.thymeleaf</groupId>
   <artifactId>thymeleaf-layout-dialect</artifactId>
   <version>2.5.1</version>
</dependency>

Once you have added the dependency, you can use the Layout Dialect in your Thymeleaf templates. Here’s an example of how to define a layout:

<!DOCTYPE html>
<html>
   <head>
      <title>My Website</title>
   </head>
   <body>
      <header th:replace="fragments/header :: header"></header>
      <div layout:fragment="content"></div>
      <footer th:replace="fragments/footer :: footer"></footer>
   </body>
</html>

This template defines a layout that includes a header and a footer. The layout:fragment attribute is used to define a section where the content of each page will be included.

To use this layout in a page, you can create a new template that includes the layout and defines the content:

<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
   <head>
      <title>My Page</title>
   </head>
   <body>
      <div layout:decorator="layout/template">
         <div layout:fragment="content">
            <p>This is the content of my page.</p>
         </div>
      </div>
   </body>
</html>

This page includes the layout by setting the layout:decorator attribute to the path of the layout template. The content of the page is defined inside the layout:fragment attribute.

8 CheatSheet

Thymeleaf CheatSheet
Feature Description Syntax
th:text Sets the text of an element <p th:text="${someValue}">Default Text</p>
th:if Conditionally renders an element <p th:if="${someCondition}">Visible when condition is true</p>
th:each Loops over a collection and renders an element for each item <ul><li th:each="item : ${items}" th:text="${item}">Default Text</li></ul>
th:object Binds a form to an object and sets its properties <form th:object="${user}"><input th:field="*{name}" /></form>
th:action Sets the URL for a form’s submission <form th:action="@{/submit}" method="post">
th:href Sets the URL for an anchor tag <a th:href="@{/page}">Link Text</a>
th:src Sets the source URL for an image tag <img th:src="@{/image.jpg}" alt="Alt Text" />
th:value Sets the value of an input field <input th:value="${someValue}" />
th:selected Conditionally selects an option in a select field <select><option th:selected="${isSelected}">Option Text</option></select>
th:disabled Conditionally disables an input field <input th:disabled="${isDisabled}" />
th:readonly Conditionally sets an input field as read-only <input th:readonly="${isReadOnly}" />
th:classappend Conditionally appends a CSS class to an element <div class="default" th:classappend="${additionalClass}"></div>
th:style Sets the style attribute of an element <div th:style="'background-color:' + ${bgColor} + ';'"></div>
th:attr Sets any attribute of an element <input th:attr="data-id=${itemId}" />
th:replace Replaces an element with another <div th:replace="fragments/header :: header"></div>
th:include Includes a fragment of a template <div th:include="fragments/footer :: footer"></div>
th:unless Conditionally renders an element when a condition is false <p th:unless="${someCondition}">Visible when condition is false</p>
th:inline Sets the inline mode of an element <script th:inline="javascript">alert([[${message}]]);</script>
th:textappend Appends text to an element <span th:textappend="${additionalText}">Default Text</span>
th:with Sets a local variable in the current context <div th:with="varName=${someValue}"></div>