banner
jzman

jzman

Coding、思考、自觉。
github

Spring Boot Series: Thymeleaf Template Layout

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:

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:

  1. Referencing template fragments
  2. Fragment expression syntax
  3. Parameterized template fragments
  4. Removing template fragments
  5. 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">
    &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 ids 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>
		&copy; 2020 Gōngxíngzhī
	</div>
</div>
<div>
	&copy; 2020 Gōngxíngzhī
</div>
<div id="include">
	&copy; 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
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.