Thymeleaf is a Java XML / XHTML / HTML5 template engine that can be used in both web and non-web environments. It is more suitable for providing XHTML / HTML5 in the view layer of MVC-based web applications, but it can also handle any XML file even in offline environments. It provides full integration with the Spring Framework.
Development Environment#
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
Introduce Dependencies#
Mainly add the spring-boot-starter-thymeleaf
dependency:
spring-boot-starter-thymeleaf
: Automatically configures the Thymeleaf template engine
<dependencies>
...
<!-- Thymeleaf Start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Thymeleaf End -->
...
</dependencies>
Configure Thymeleaf#
application.yml
spring:
thymeleaf:
cache: false # Whether to enable template caching, default is: true, turn off caching during development, otherwise you won't see real-time pages!
mode: HTML # Specify the mode of the template, default is: HTML
encoding: UTF-8 # Specify the encoding of the template, default is: UTF-8
prefix: classpath:/templates/ # Specify the prefix of the template, default is: classpath:/templates/
suffix: .html # Specify the suffix of the template, default is: .html
servlet:
content-type: text/html # Specify Content-Type value, default is: text/html
From org.thymeleaf.templatemode.TemplateMode
, it can be seen that Thymeleaf
started using HTML
instead of HTML5, LEGACYHTML5, XHTML, VALIDXHTML
from version 3.0.0
. If you are still using a version prior to 3.0.0
and want to use non-strict HTML, you need to do the following configuration:
- Introduce the
nekohtml
dependency inpom.xml
- Configure
spring.thymeleaf.mode=LEGACYHTML5
inapplication.yml
For more property configurations, please refer to the property introduction of the # THYMELEAF (ThymeleafAutoConfiguration)
module in "Appendix A. Common application properties." (TIPS: Use CTRL + F
for quick navigation)
Create Test Controller#
Create a Controller to assign a value to the message
attribute and set the redirection, the code is as follows:
IndexController.java
@Controller
public class IndexController {
@GetMapping(path = {"/", "index"})
public String indexPage(Model model) {
model.addAttribute("message", "Hello Thymeleaf!");
return "index";
}
}
Create Test HTML Page#
Create an index.html
file in the templates
directory and declare the Thymeleaf namespace xmlns:th="http://www.thymeleaf.org"
in the html
tag, the code is as follows:
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Thymeleaf</title>
</head>
<body>
<h1 th:text="${message}">Hello World!</h1>
</body>
</html>
The key code is:
xmlns="http://www.thymeleaf.org"
This mainly allows the IDE to recognize the Thymeleaf namespace, so when you enter th:
in the tag, the IDE will prompt the corresponding syntax, facilitating development! Not adding this line of code will not affect the rendering of the Thymeleaf template engine or the normal display of the page.
Test Access#
After a successful startup, visit http://127.0.0.1:8080 to see the effect:
Access result: Hello Thymeleaf!
Common Thymeleaf Syntax#
- JAVA source code path: TagsController.java
- HTML source code path:
templates
directory
Get Variable Value#
<p th:text="'Hello! ' + ${name} + '!'" >name</p>
It can be seen that to get the variable value, the $
symbol is used, and for JavaBeans, the variable name and property name are used to access it, which is the same as the EL
expression.
Additionally, the $
expression can only be written inside th
tags; otherwise, it will not take effect. The above example uses the value of the th:text
tag to replace the value inside the <p>...</p>
tag, while the original value inside p
is just for display during front-end development. This achieves a good separation of front and back ends.
Content Information Output: th:text
and th:utext
#
th:text
: Outputs in plain textth:utext
: Outputs in HTML tag format, which the browser can render normally
HTML code:
<body>
<h2 th:text="' th:text   » ' + ${content}">Output in plain text</h2>
<h2 th:utext="'th:utext » ' + ${content}">Output in HTML tag format, which the browser can render normally</h2>
</body>
JAVA code:
@GetMapping("/text-utext")
public String textAndutext(Model model) {
model.addAttribute("content", "<span style='color:red'>thymeleaf text output</span>");
return "text-utext";
}
Referencing URLs#
URL handling is done using the syntax @{…}
:
HTML code:
<body>
<ul>
<li>
<a th:href="@{https://github.com/{username}(username=${username})}">Absolute Path 1</a>,
<a th:href="@{https://www.baidu.com}">Absolute Path 2</a>
</li>
<li>
<a th:href="@{/}">Relative Path</a>
</li>
<li>
<a th:href="@{/css/app.css}">Content Path, default accesses CSS files under static</a>
</li>
</ul>
</body>
JAVA code:
@GetMapping("/refer-url")
public String referUrl(Model model) {
model.addAttribute("username", "y0ngb1n");
return "refer-url";
}
Similar tags include: th:href
and th:src
String Replacement#
Often, we may only need to replace a certain part of a large piece of text, which can be done through string concatenation:
<p th:text="'Welcome to our application, ' + ${user.name} + '!'">
This can be done in a more concise way:
<p th:text="|Welcome to our application, ${user.name}!|">
String replacement can also be combined with other expressions:
<p th:text="${onevar} + ', ' + |${twovar}, ${threevar}|">
Of course, this form has more limitations; |…|
can only contain variable expressions ${…}
, and cannot include other constants, conditional expressions, etc.
HTML code:
<body>
<p th:text="'Welcome to our application, ' + ${user.name} + '!'">
<p th:text="|Welcome to our application, ${user.name}!|">
<p th:text="${onevar} + ', ' + |${twovar}, ${threevar}|">
</body>
JAVA code:
@GetMapping("replace-text")
public String replaceText(Model model) {
model.addAttribute("user", user);
model.addAttribute("onevar", "one");
model.addAttribute("twovar", "two");
model.addAttribute("threevar", "three");
return "replace-text";
}
Operators#
Various arithmetic operators can be used in expressions, such as +, -, *, /, %
:
th:with="isEven=(${user.age} % 2 == 0)"
Logical operators >, <, <=, >=, ==, !=
can also be used. The only thing to note is that when using <, >
, you need to use their HTML escape characters:
th:if="${user.age} > 1"
th:text="'Environment is ' + ((${env} == 'dev') ? 'Development' : 'Production')"
HTML code:
<body>
<h2 th:text="|name: ${user.name}, age: ${user.age}, env: ${env}|"></h2>
<p th:with="isEven=(${user.age} % 2 == 0)">Age is even</p>
<p th:with="isEven=(${user.age == 18})">Wow, only 18!</p>
<p th:if="${user.age} > 18">Current age is greater than 18</p>
<div th:class="${env} == 'dev' ? 'dev' : 'prod'"></div>
<p th:text="'Current environment: ' + ((${env} == 'dev') ? 'Development' : 'Production')"></p>
</body>
JAVA code:
@GetMapping("/operator")
public String operator(Model model) {
model.addAttribute("user", user);
model.addAttribute("env", "dev");
return "operator";
}
Conditional Judgments#
th:if, th:unless
#
Use th:if
and th:unless
attributes for conditional judgments. In the example below, the tag will only be displayed if the condition in th:if
is met:
<a th:href="@{/login}" th:if=${user == null}>Login</a>
<a th:href="@{/login}" th:unless=${user != null}>Login</a>
th:unless
is exactly the opposite of th:if
; it will only display its content if the condition in the expression is not met.
th:switch, th:case
#
Supports multi-way switch structures:
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
</div>
The default attribute can be represented by *
:
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>
Message expression:
#{...}
, also known as text externalization, internationalization, or i18n
HTML code:
<body>
<a th:href="@{/login}" th:unless="${user == null}">Login</a>
<p th:if="${user != null}">Welcome, <span th:text="|${user.name}(role: ${user.role})|">tony</span></p>
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>
</body>
JAVA code:
@GetMapping("/condition")
public String condition(Model model) {
model.addAttribute("user", user);
return "condition";
}
Looping#
Rendering list data is a very common scenario. For example, if there are n records that need to be rendered into a table, the data collection must be iterable, using the th:each
tag:
HTML code:
<body>
<table>
<tr>
<th>NAME</th>
<th>AGE</th>
<th>ADMIN</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.name}">Onions</td>
<td th:text="${user.age}">22</td>
<td th:text="${user.role} == 'admin' ? #{true} : #{false}">yes</td>
</tr>
</table>
</body>
As you can see, the th:each
tag needs to be added to the element being looped over (here it is the <tr>
), where th:each="prod : ${prods}"
means iterating over the collection variable prods
, and the loop variable is prod
, which can be accessed in the loop body through expressions.
JAVA code:
@GetMapping("/loop")
public String loop(Model model) {
List<User> users = new ArrayList<>(3);
users.add(user);
users.add(User.builder().name("tony").age(23).role("user").build());
users.add(User.builder().name("tom").age(21).role("user").build());
model.addAttribute("users", users);
return "loop";
}
For more tag usage, please refer to "Common Thymeleaf Syntax" and "Thymeleaf Reference Manual" to unlock more tips 😜
References#
- Spring Boot (IV) Template Engine Thymeleaf Integration
- Introduction to Using Thymeleaf in Spring
- The First Thymeleaf Template Page
- Spring Boot Project Setup (III) Integrating Thymeleaf Template
- Spring Boot (IV) Detailed Explanation of Thymeleaf Usage
- Next-Generation Java Template Engine Thymeleaf
- Common Thymeleaf Syntax
- Thymeleaf Reference Manual