PS:もし自分を一時的に律することができないのなら、自分を忙しくさせることを考えてみてください。
前の数記事ではインターフェース開発、Thymeleaf テンプレートおよびその一般的な構文を試しました。この記事を読む前に、前の数記事を読むことができます:
- Spring Boot シリーズのインターフェースを開発する
- Spring Boot シリーズの Thymeleaf テンプレート入門
- Spring Boot シリーズの Thymeleaf 一般的な構文
Thymeleaf テンプレートのレイアウトは、主にフロントエンドページをより良く分割するために使用され、主に Thymeleaf 関連の構文を使用してフロントエンドページのレイアウトを行います。主な内容は以下の通りです:
- テンプレートフラグメントの参照
- フラグメント式構文
- パラメータ化されたテンプレートフラグメント
- テンプレートフラグメントの削除
- テンプレートレイアウトの継承
テンプレートフラグメントの参照#
th:fragment
を使用して、他のページが参照できるレイアウトフラグメントを定義できます。foter.html でテンプレートフラグメントを以下のように定義します:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<!--レイアウトフラグメントを定義-->
<div th:fragment="copy">
© 2020 躬行之
</div>
</body>
</html>
上記では、copy という名前のフラグメントを定義しました。th:insert
、th:replace
、およびth:include
を使用してテンプレートフラグメントを挿入できます。th:include
は Thymeleaf 3.0 以降では推奨されなくなりました。home.html でテンプレートフラグメントを以下のように参照します:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--テンプレートフラグメントを参照-->
<div th:insert="~{footer::copy}"></div>
</body>
</html>
プロジェクトを実行し、http://localhost:8080/home
を確認すると、以下のようになります:
© 2020 躬行之
© 2020 躬行之
次に、th:insert
、th:replace
、およびth:include
の 3 つの違いを見てみましょう。以下のように、copy
という名前のテンプレートフラグメントを 3 つの方法でそれぞれ参照します:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--th:insert、th:replace、th:includeの違い-->
<p>---th:insert、th:replace、th:includeの違い---</p>
<!--テンプレートフラグメントを直接挿入-->
<div id="insert" th:insert="~{footer::copy}">insert</div>
<!--現在のフラグメントを直接置き換え-->
<div id="replace" th:replace="~{footer::copy}">replace</div>
<!--指定されたフラグメントの内容を現在のフラグメントに直接挿入-->
<div id="include" th:include="~{footer::copy}">include</div>
</body>
</html>
上記のコードでは、3 つのdiv
がそれぞれid
をinsert
、replace
、include
に設定しています。プロジェクトを実行した後、ブラウザでソースコードを確認すると、以下のようになります:
<!--...-->
<!--th:insert、th:replace、th:includeの違い-->
<p>---th:insert、th:replace、th:includeの違い---</p>
<div id="insert">
<div>
© 2020 躬行之
</div>
</div>
<div>
© 2020 躬行之
</div>
<div id="include">
© 2020 躬行之
</div>
<!--...-->
3 つの違いは以下の通りです:
th:insert
:テンプレートフラグメントを直接挿入;th:replace
:現在のフラグメントを直接置き換え;th:include
:指定されたフラグメントの内容を現在のフラグメントに直接挿入。
フラグメント式構文#
テンプレートは主にフラグメント式を使用しています。フラグメント式の構文は以下の通りです:
〜{templatename::selector}
: 指定されたテンプレートの指定されたフラグメント名のテンプレートフラグメントを参照;〜{templatename}
: 指定されたテンプレートのすべてのフラグメントを参照;〜{:: selector}
: 同じく〜{this:: selector}
、現在のテンプレートの指定された名前のテンプレートフラグメントを参照。
ここで、templatename
はテンプレート名を示し、上記のfooter
のように、selector
はフラグメント名を示します。上記のcopy
のように。
さらに、selector
は ID セレクタ、クラスセレクタ、タグでも使用できるため、th:fragment
を定義していない場合でも関連するテンプレートフラグメントを使用できます。以下のように:
<!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>th:fragmentを定義していない場合のフラグメント式の使用--id</p>
</div>
<div class="head">
<p>th:fragmentを定義していない場合のフラグメント式の使用--class</p>
</div>
<div>
<span>th:fragmentを定義していない場合のフラグメント式の使用--span</span>
</div>
</body>
</html>
別のテンプレートで上記のコードフラグメントを使用できます。以下のように:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--th:fragmentを定義していない場合のフラグメント式の使用-->
<div th:insert="~{footer::#head}"></div>
<div th:insert="~{footer::.head}"></div>
<div th:insert="~{footer::span}"></div>
</body>
</html>
プロジェクトを実行すると、結果は以下の通りです:
th:fragmentを定義していない場合のフラグメント式の使用--id
th:fragmentを定義していない場合のフラグメント式の使用--class
th:fragmentを定義していない場合のフラグメント式の使用--span
パラメータ化されたテンプレートフラグメント#
th:fragment
を使用してテンプレートフラグメントを定義する際に、パラメータを追加できます。以下のように:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<!--テンプレートフラグメントにパラメータを追加-->
<div th:fragment="frag(name)" th:assert="${!#strings.isEmpty(name)}">
<p th:text="公众号名称+':'+${name}">Default</p>
</div>
</body>
</html>
その後、対応するページで上記のフラグメントを参照し、対応するパラメータを渡すことができます。以下のように:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--パラメータ化されたテンプレートフラグメント-->
<div th:insert="~{footer::frag(${gzh})}"></div>
<!--この書き方では、複数のパラメータがある場合、順序を変更できます-->
<div th:insert="~{footer::frag(name=${gzh})}"></div>
</body>
</html>
上記のコードでパラメータ値gzh=躬行之
を使用すると、プロジェクトを実行した結果は以下の通りです:
公众号名称:躬行之
公众号名称:躬行之
テンプレートフラグメント内でth:assert
属性を使用してパラメータの検証を行うこともできます。つまり、th:assert
内の式の値がすべてtrue
である場合にのみ実行が続行され、それ以外の場合は例外がスローされます。
テンプレートフラグメントの削除#
テンプレートフラグメントを削除するには、th:remove
属性を使用します。この属性に設定できる値は以下の通りです:
- all: 所在するタグおよびすべての子タグを削除;
- body: 所在するタグを削除せず、対応する子タグのみを削除;
- tag: 所在するタグのみを削除し、その子タグは削除しない;
- all-but-first: 所在するタグの最初のものを除くすべての子タグを削除;
- none : 何の削除操作も行わない。
具体的な使用方法は以下の通りです:
<!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>
<!--所在するタグおよびすべての子タグを削除-->
<tr th:remove="all">
<td>A</td>
<td>1</td>
<td>AA</td>
</tr>
<!--所在するタグを削除せず、対応する子タグのみを削除-->
<tr th:remove="body">
<td>B</td>
<td>2</td>
<td>BB</td>
</tr>
<!--所在するタグのみを削除し、その子タグは削除しない-->
<tr th:remove="tag">
<td>C</td>
<td>3</td>
<td>CC</td>
</tr>
<!--所在するタグの最初のものを除くすべての子タグを削除-->
<tr th:remove="all-but-first">
<td>D</td>
<td>4</td>
<td>DD</td>
</tr>
<!--何の削除操作も行わない-->
<tr th:remove="none">
<td>E</td>
<td>5</td>
<td>EE</td>
</tr>
</table>
</body>
</html>
th:remove
属性に設定された異なる値の効果を主に確認します。これは以下のようなページに相当します:
<!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>
<!--所在するタグおよびすべての子タグを削除-->
<!--所在するタグを削除せず、対応する子タグのみを削除-->
<tr></tr>
<!--所在するタグのみを削除し、その子タグは削除しない-->
<td>C</td>
<td>3</td>
<td>CC</td>
<!--所在するタグの最初のものを除くすべての子タグを削除-->
<tr>
<td>D</td>
</tr>
<!--何の削除操作も行わない-->
<tr>
<td>E</td>
<td>5</td>
<td>EE</td>
</tr>
</table>
</body>
</html>
テンプレートレイアウトの継承#
テンプレートレイアウトの継承には、th:fragment
とth:replace
を使用します。以下の例でテンプレートレイアウトの継承の書き方を示します。継承するページを以下のように定義します:
<!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>
上記のページを継承するファイルは、上記のtitle
とcontent
の値を置き換えます。継承するページの書き方は以下の通りです:
<!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>
実行後の効果は以下の通りです:
Layout H1
Page content
Included on page
Layout footer