PS: If you can't discipline yourself for now, then keep yourself busy.
The previous articles attempted interface development, Thymeleaf templates, and their commonly used syntax. You can read the earlier articles before 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 organize the front-end pages, primarily through Thymeleaf-related syntax for layout. 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
, using all three methods 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
s are set with corresponding id
s as 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 primarily uses fragment expressions, with the syntax as follows:
~{templatename::selector}
: Introduces the specified template's specified fragment name;~{templatename}
: Introduces all fragments of the specified template;~{:: selector}
: Same as~{this:: selector}
, introduces the specified name of the current template's fragment.
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 using 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, in the corresponding page, the above fragment can be referenced to 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 syntax allows multiple parameters, and 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 all expressions in th:assert
are true
will execution continue; otherwise, an exception will be thrown.
Removing Template Fragments#
To remove template fragments, the th:remove
attribute is used, with the following possible values:
- 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, not delete its child tags;
- all-but-first: Remove all child tags 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, not delete its child tags-->
<tr th:remove="tag">
<td>C</td>
<td>3</td>
<td>CC</td>
</tr>
<!--Remove all child tags 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 mainly on the effects after running with different values set for the th:remove
attribute, which results in a page like the following:
<!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, not delete its child tags-->
<td>C</td>
<td>3</td>
<td>CC</td>
<!--Remove all child tags 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, defining the page to be inherited 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