Thymeleafのth:fragmentを使ったテンプレートの再利用方法を完全ガイド!初心者でもわかる使い方
生徒
「Thymeleafのth:fragmentって何ですか?どうやって使うんでしょうか?」
先生
「th:fragmentは、Thymeleafでよく使うテンプレートの一部分を再利用するための機能です。例えば、ヘッダーやフッターを別のHTMLファイルとして分けておき、必要なページに呼び出すことができます。」
生徒
「それなら、共通部分のメンテナンスが楽になりますね!具体的な使い方を教えてください。」
先生
「それでは、基本的なth:fragmentの使い方を見ていきましょう!」
1. th:fragmentとは?
Thymeleafのth:fragmentは、HTMLテンプレートの一部を再利用可能な「断片(フラグメント)」として定義するための属性です。これを使うと、共通部分を一箇所にまとめて管理できるため、HTMLコードの重複を減らし、保守性が向上します。例えば、ナビゲーションバーやフッターなどのコンポーネントを一度作成しておけば、複数のページで簡単に再利用することができます。
2. th:fragmentの基本的な使い方
まず、th:fragmentを使ってヘッダーとフッターを分割し、再利用する方法を紹介します。以下の例では、ヘッダーとフッターを別ファイルとして定義し、それをメインのHTMLから呼び出します。
<!-- fragments/header.html -->
<div th:fragment="headerFragment">
<header>
<h1>サイトのヘッダー</h1>
<nav>
<ul>
<li><a href="/">ホーム</a></li>
<li><a href="/about">会社概要</a></li>
<li><a href="/contact">お問い合わせ</a></li>
</ul>
</nav>
</header>
</div>
<!-- fragments/footer.html -->
<div th:fragment="footerFragment">
<footer>
<p>© 2024 My Website</p>
</footer>
</div>
<!-- main.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleafのth:fragment例</title>
</head>
<body>
<!-- ヘッダーを読み込み -->
<div th:insert="fragments/header :: headerFragment"></div>
<h2>メインコンテンツ</h2>
<!-- フッターを読み込み -->
<div th:insert="fragments/footer :: footerFragment"></div>
</body>
</html>
このように、th:insertまたはth:replaceでフラグメントを呼び出すことができます。例えば、ナビゲーションメニューの変更があった場合、header.htmlを修正するだけで、すべてのページに変更が反映されます。
3. パラメータを渡して動的にフラグメントを利用する方法
Thymeleafのth:fragmentでは、パラメータを渡すこともできます。これにより、より動的で柔軟なテンプレートが作成可能です。次の例では、メッセージを渡してフラグメント内で表示します。
<!-- fragments/message.html -->
<div th:fragment="messageFragment (msg)">
<p>メッセージ: [[${msg}]]</p>
</div>
<!-- main.html -->
<div th:insert="fragments/message :: messageFragment (msg='こんにちは、Thymeleaf!')"></div>
上記のコードを実行すると、「メッセージ: こんにちは、Thymeleaf!」と表示されます。このようにパラメータを利用すれば、共通パーツをさらに汎用的に使い回すことができます。
4. th:fragmentを使うときの注意点
th:fragmentを活用する際の注意点をいくつか紹介します。
- ファイルパスが正しくないと、エラーが発生します。特にパスのスペルミスやディレクトリ構成に注意してください。
- テンプレートファイルはUTF-8で保存することを推奨します。文字化けを防ぐためにも重要です。
- 複数のページで利用されるフラグメントは、メンテナンス性を考慮して適切に管理しましょう。
5. th:fragmentを使った実践的なサンプル
最後に、th:fragmentを使った実際のWebページ構成例を紹介します。ログインフォームを再利用するケースを考えてみましょう。
<!-- fragments/login.html -->
<div th:fragment="loginForm">
<form th:action="@{/login}" method="post">
<label for="username">ユーザー名:</label>
<input type="text" id="username" name="username" />
<br/>
<label for="password">パスワード:</label>
<input type="password" id="password" name="password" />
<br/>
<button type="submit">ログイン</button>
</form>
</div>
<!-- main.html -->
<div th:insert="fragments/login :: loginForm"></div>
これにより、ログインフォームを複数のページで再利用でき、メンテナンスも簡単になります。
6. th:insert・th:replace・th:includeの違いと選び方
Thymeleafでフラグメントを再利用する際は、状況に合わせてth:insert・th:replace・th:includeを使い分けます。ホスト要素を残したいならth:insert、完全に置き換えたいならth:replace、フラグメントの「子要素」だけを取り込みたいならth:includeが便利です。
<!-- fragments/header.html -->
<header th:fragment="siteHeader">
<h1>サイトのヘッダー</h1>
</header>
<!-- fragments/menu.html -->
<ul th:fragment="menuItems">
<li><a th:href="@{/}">ホーム</a></li>
<li><a th:href="@{/about}">会社概要</a></li>
</ul>
<!-- host.html -->
<!-- insert: ホスト要素(<header>)は残る -->
<header th:insert="~{fragments/header :: siteHeader}"></header>
<!-- replace: ホスト要素ごと置き換える -->
<header th:replace="~{fragments/header :: siteHeader}"></header>
<!-- include: フラグメントの「子要素」だけを取り込む -->
<nav>
<ul th:include="~{fragments/menu :: menuItems}"></ul>
</nav>
7. レイアウト全体をth:fragmentで共通化する手順(ヘッダー・フッター込み)
ページ全体のレイアウトをフラグメント化すると、ヘッダー・フッターを一括管理でき、テンプレートの再利用性がさらに高まります。以下は「中身」を引数で受け取り、共通レイアウトに差し込む定番パターンです。
<!-- layouts/base.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>共通レイアウト</title>
</head>
<body>
<div th:fragment="layout(content)">
<div th:insert="~{fragments/header :: headerFragment}"></div>
<main th:replace="${content}"></main>
<div th:insert="~{fragments/footer :: footerFragment}"></div>
</div>
</body>
</html>
<!-- pages/home.html -->
<div th:replace="~{layouts/base :: layout(~{::content})}">
<div th:fragment="content">
<h2>ホーム</h2>
<p>ここにページごとのメインコンテンツを記述します。</p>
</div>
</div>
8. 複数パラメータ・名前付き引数で柔軟に再利用する
th:fragmentは複数パラメータや名前付き引数に対応しています。メッセージや種類を渡して表示内容を切り替えるなど、同一フラグメントを汎用化できます。
<!-- fragments/alert.html -->
<div th:fragment="alert(type, message)"
th:class="'alert ' + (${type} == 'success' ? 'alert-success' : (${type} == 'error' ? 'alert-danger' : 'alert-info'))">
<i class="bi bi-info-circle"></i> [[${message}]]
</div>
<!-- 呼び出し側 -->
<div th:replace="~{fragments/alert :: alert(type='success', message='登録に成功しました')}"></div>
<div th:replace="~{fragments/alert :: alert(type='error', message='エラーが発生しました')}"></div>
9. th:fragmentとループ・条件分岐で動的ナビゲーションを作る
フラグメント内でth:eachやth:ifを使えば、配列やログイン状態に応じたメニューを動的生成できます。現在ページに「active」クラスを付ける例です。
<!-- fragments/nav.html -->
<nav th:fragment="nav(items)">
<ul class="nav">
<li class="nav-item" th:each="item : ${items}"
th:classappend="${#httpServletRequest.requestURI.startsWith(item.href)} ? ' active' : ''">
<a class="nav-link" th:href="${item.href}" th:text="${item.label}">Link</a>
</li>
</ul>
</nav>
<!-- 呼び出し側(ControllerでmenuItemsをModelに投入しておく) -->
<div th:replace="~{fragments/nav :: nav(items=${menuItems})}"></div>
まとめ
ここまで、Thymeleafのth:fragmentを使ったテンプレートの再利用方法について詳しく解説してきました。th:fragmentを使用することで、HTMLの共通部分を効率的に管理し、コードの重複を減らすことができます。特に、ヘッダー、フッター、ナビゲーションバーなどの共通コンポーネントを独立したテンプレートファイルに分けて再利用することで、メンテナンスが非常に容易になります。
さらに、th:insertやth:replaceを利用することで、柔軟にフラグメントを読み込み、パラメータを渡して動的に表示内容を変更することが可能です。この機能は、大規模なWebアプリケーションにおいて特に有用であり、テンプレートの一元管理により開発効率が向上します。また、パラメータ付きフラグメントを利用すれば、ページごとに異なるデータを表示しつつ、共通のレイアウトを保持できます。
例えば、eコマースサイトでは商品カードのフラグメントを作成し、異なる商品情報をパラメータで渡すことで、同じレイアウトを維持しながら動的に商品情報を表示することができます。以下にそのような例を示します。
<!-- fragments/productCard.html -->
<div th:fragment="productCard (productName, price, imageUrl)">
<div class="product-card">
<img th:src="@{${imageUrl}}" alt="商品画像" class="img-fluid" />
<h3>[[${productName}]]</h3>
<p>価格: ¥[[${price}]]</p>
</div>
</div>
<!-- main.html -->
<div th:insert="fragments/productCard :: productCard
(productName='商品A', price=5000, imageUrl='/images/productA.jpg')"></div>
<div th:insert="fragments/productCard :: productCard
(productName='商品B', price=3000, imageUrl='/images/productB.jpg')"></div>
上記の例では、th:fragmentを使用して商品カードのテンプレートを定義し、異なる商品データを渡すことで、効率的に商品リストを表示することができます。これにより、HTMLコードがより簡潔になり、保守性が向上します。
さらに、Thymeleafのth:replaceは、既存の要素をフラグメントの内容で置き換えるため、特定の部分を動的に変更する際に便利です。例えば、ログイン状態によって異なるメニューを表示する場合に役立ちます。
これらのThymeleafの機能を活用することで、効率的なWebページ開発が可能になります。テンプレートの再利用は、今後のメンテナンスコストを削減し、新しい機能追加時の作業効率を向上させるための重要な手法です。
生徒
「今日はth:fragmentの使い方をしっかり学べました!テンプレートを再利用することで、コードがすごくスッキリしました。」
先生
「そうですね。th:fragmentを使うと、共通部分を管理しやすくなり、変更があった場合でも一箇所修正するだけで済みます。これが大規模なプロジェクトでの効率化につながります。」
生徒
「さらに、パラメータを渡せることで、同じフラグメントをいろいろなページで使い回すことができるんですね。」
先生
「その通りです。例えば、商品リストやユーザーのプロフィールなど、パラメータを使って動的に内容を変えられるコンテンツに最適です。理解が深まったようで良かったです。」
生徒
「これから実際のプロジェクトでもth:fragmentを積極的に使ってみます!テンプレートの管理がとても楽になりそうです。」
先生
「ぜひ挑戦してください。Thymeleafの他の機能も活用すれば、さらに効率的に開発が進められますよ。」