banner
jzman

jzman

Coding、思考、自觉。
github

Spring BootシリーズのThymeleafテンプレートレイアウト

PS:もし自分を一時的に律することができないのなら、自分を忙しくさせることを考えてみてください。

前の数記事ではインターフェース開発、Thymeleaf テンプレートおよびその一般的な構文を試しました。この記事を読む前に、前の数記事を読むことができます:

Thymeleaf テンプレートのレイアウトは、主にフロントエンドページをより良く分割するために使用され、主に Thymeleaf 関連の構文を使用してフロントエンドページのレイアウトを行います。主な内容は以下の通りです:

  1. テンプレートフラグメントの参照
  2. フラグメント式構文
  3. パラメータ化されたテンプレートフラグメント
  4. テンプレートフラグメントの削除
  5. テンプレートレイアウトの継承

テンプレートフラグメントの参照#

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">
    &copy; 2020 躬行之
</div>
</body>
</html>

上記では、copy という名前のフラグメントを定義しました。th:insertth: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:insertth: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がそれぞれidinsertreplaceincludeに設定しています。プロジェクトを実行した後、ブラウザでソースコードを確認すると、以下のようになります:

<!--...-->

<!--th:insert、th:replace、th:includeの違い-->
<p>---th:insert、th:replace、th:includeの違い---</p>
<div id="insert">
	<div>
		&copy; 2020 躬行之
	</div>
</div>
<div>
	&copy; 2020 躬行之
</div>
<div id="include">
	&copy; 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:fragmentth: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>

上記のページを継承するファイルは、上記のtitlecontentの値を置き換えます。継承するページの書き方は以下の通りです:

<!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
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。