PS: If you can't discipline yourself for now, then keep yourself busy.
The previous articles attempted interface development, Thymeleaf templates, and their common syntax. You can read the previous articles before reading this one:
- Spring Boot Series: Developing an Interface
- Spring Boot Series: Introduction to Thymeleaf Templates
- Spring Boot Series: Common Syntax of Thymeleaf
The main purpose of Thymeleaf template layout is to better divide the front-end pages, mainly through Thymeleaf-related syntax to layout the front-end pages. The main content is as follows:
- Referencing template fragments
- Fragment expression syntax
- Parameterized template fragments
- Removing template fragments
- Template layout inheritance
Referencing Template Fragments#
Using th:fragment
allows you to define layout fragments for other pages to reference. The template fragment is defined in footer.html as follows:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<!--Define layout fragment-->
<div th:fragment="copy">
© 2020 Gōngxíngzhī
</div>
</body>
</html>
The above defines a fragment named copy, which can be included using th:insert
, th:replace
, and th:include
. Note that th:include
is no longer recommended after Thymeleaf 3.0. The template fragment is referenced in home.html as follows:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--Include template fragment-->
<div th:insert="~{footer::copy}"></div>
</body>
</html>
Run the project and check http://localhost:8080/home
, the result is as follows:
© 2020 Gōngxíngzhī
© 2020 Gōngxíngzhī
Next, let's look at the differences between th:insert
, th:replace
, and th:include
. The three methods are used to include the fragment named copy
as follows:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--Differences between th:insert, th:replace, and th:include-->
<p>---Differences between th:insert, th:replace, and th:include---</p>
<!--Directly insert template fragment-->
<div id="insert" th:insert="~{footer::copy}">insert</div>
<!--Directly replace current fragment-->
<div id="replace" th:replace="~{footer::copy}">replace</div>
<!--Directly insert the content of the specified fragment into the current fragment-->
<div id="include" th:include="~{footer::copy}">include</div>
</body>
</html>
In the above code, the three div
elements are set with corresponding id
s of insert
, replace
, and include
. After running the project, the source code viewed in the browser is as follows:
<!--...-->
<!--Differences between th:insert, th:replace, and th:include-->
<p>---Differences between th:insert, th:replace, and th:include---</p>
<div id="insert">
<div>
© 2020 Gōngxíngzhī
</div>
</div>
<div>
© 2020 Gōngxíngzhī
</div>
<div id="include">
© 2020 Gōngxíngzhī
</div>
<!--...-->
The differences among the three are as follows:
th:insert
: Directly inserts the template fragment;th:replace
: Directly replaces the current fragment;th:include
: Directly inserts the content of the specified fragment into the current fragment.
Fragment Expression Syntax#
The template mainly uses fragment expressions, and the syntax is as follows:
~{templatename::selector}
: Introduces the specified template fragment by name;~{templatename}
: Introduces all fragments of the specified template;~{:: selector}
: Same as~{this:: selector}
, introduces the specified name fragment of the current template.
Here, templatename
refers to the template name, such as footer
in the above text, and selector
refers to the fragment name, such as copy
in the above text.
Additionally, selector
can also be an ID selector, class selector, or tag, allowing the use of related template fragments without defining th:fragment
, as shown below:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<div id="head">
<p>Using fragment expressions without defining th:fragment--id</p>
</div>
<div class="head">
<p>Using fragment expressions without defining th:fragment--class</p>
</div>
<div>
<span>Using fragment expressions without defining th:fragment--span</span>
</div>
</body>
</html>
The corresponding code fragments can be used in another template as follows:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--Using fragment expressions without defining th:fragment-->
<div th:insert="~{footer::#head}"></div>
<div th:insert="~{footer::.head}"></div>
<div th:insert="~{footer::span}"></div>
</body>
</html>
Run the project, and the result is as follows:
Using fragment expressions without defining th:fragment--id
Using fragment expressions without defining th:fragment--class
Using fragment expressions without defining th:fragment--span
Parameterized Template Fragments#
When defining template fragments with th:fragment
, parameters can be added as follows:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<!--Add parameters to the template fragment-->
<div th:fragment="frag(name)" th:assert="${!#strings.isEmpty(name)}">
<p th:text="'Public account name:' + ${name}">Default</p>
</div>
</body>
</html>
Then, when referencing the above fragment in the corresponding page, you can pass the corresponding parameters as follows:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--Parameterized template fragment-->
<div th:insert="~{footer::frag(${gzh})}"></div>
<!--This way, if there are multiple parameters, the order can vary-->
<div th:insert="~{footer::frag(name=${gzh})}"></div>
</body>
</html>
In the above code, the parameter value gzh=Gōngxíngzhī
, and the result after running the project is as follows:
Public account name: Gōngxíngzhī
Public account name: Gōngxíngzhī
In the template fragment, the th:assert
attribute can be used for parameter validation, meaning that only if the values of the expressions in th:assert
are all true
will the execution continue; otherwise, an exception will be thrown.
Removing Template Fragments#
To remove template fragments, the th:remove
attribute is used, and the values that can be set are as follows:
- all: Remove the current tag and all its child tags;
- body: Do not remove the current tag, only remove the corresponding child tags;
- tag: Only remove the current tag, do not delete its child tags;
- all-but-first: Remove all child tags of the current tag except the first one;
- none: No removal operation.
The specific usage is as follows:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>COMMENT</th>
</tr>
<!--Remove the current tag and all its child tags-->
<tr th:remove="all">
<td>A</td>
<td>1</td>
<td>AA</td>
</tr>
<!--Do not remove the current tag, only remove the corresponding child tags-->
<tr th:remove="body">
<td>B</td>
<td>2</td>
<td>BB</td>
</tr>
<!--Only remove the current tag, do not delete its child tags-->
<tr th:remove="tag">
<td>C</td>
<td>3</td>
<td>CC</td>
</tr>
<!--Remove all child tags of the current tag except the first one-->
<tr th:remove="all-but-first">
<td>D</td>
<td>4</td>
<td>DD</td>
</tr>
<!--No removal operation-->
<tr th:remove="none">
<td>E</td>
<td>5</td>
<td>EE</td>
</tr>
</table>
</body>
</html>
Focus on the effects of running with different values set for the th:remove
attribute, which results in the following page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>COMMENT</th>
</tr>
<!--Remove the current tag and all its child tags-->
<!--Do not remove the current tag, only remove the corresponding child tags-->
<tr></tr>
<!--Only remove the current tag, do not delete its child tags-->
<td>C</td>
<td>3</td>
<td>CC</td>
<!--Remove all child tags of the current tag except the first one-->
<tr>
<td>D</td>
</tr>
<!--No removal operation-->
<tr>
<td>E</td>
<td>5</td>
<td>EE</td>
</tr>
</table>
</body>
</html>
Template Layout Inheritance#
Template layout inheritance still uses th:fragment
and th:replace
. Below is an example demonstrating the writing of template layout inheritance. The page to be inherited is defined as follows:
<!DOCTYPE html>
<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:replace="${title}">Layout Title</title>
</head>
<body>
<h1>Layout H1</h1>
<div th:replace="${content}">
<p>Layout content</p>
</div>
<footer>
Layout footer
</footer>
</body>
</html>
The file inheriting the above page will replace the values of title
and content
. The writing of the inheriting page is as follows:
<!DOCTYPE html>
<html th:replace="~{base :: layout(~{::title}, ~{::section})}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Page Title</title>
</head>
<body>
<section>
<p>Page content</p>
<div>Included on page</div>
</section>
</body>
</html>
The result after running is as follows:
Layout H1
Page content
Included on page
Layout footer