Thymeleafのth:replaceの使い方を徹底解説!テンプレート置き換えの基本やth:includeとの違いを解説
生徒
「先生、Thymeleafのth:replaceってどういう時に使うんですか?」
先生
「Thymeleafのth:replaceは、テンプレートを再利用するために使うものです。同じHTMLパーツを複数のページで共通化したい時に役立ちますよ。」
生徒
「具体的にはどのように使うんですか?」
先生
「じゃあ、簡単な例を見ながら説明していきますね!」
1. th:replaceとは?
Thymeleafのth:replaceは、HTMLテンプレートの一部を別のテンプレートファイルから読み込んで置き換えるための属性です。これを使うと、同じヘッダーやフッター、共通コンポーネントなどを一箇所にまとめて管理できるため、複数のページで再利用が可能になります。たとえば、ナビゲーションバーやページのフッターをすべてのページで共通化する際に非常に便利です。
例えば、全てのページで同じヘッダーを使いたい場合、th:replaceを活用することでコードの重複を防ぎ、保守性を高めることができます。
2. 基本的なth:replaceの使い方
それでは、th:replaceの基本的な使い方を見ていきましょう。まず、再利用したい部分を別のテンプレートファイルとして作成します。以下の例では、ヘッダー部分を別ファイルとして切り出し、他のテンプレートからth:replaceを使って読み込む方法を紹介します。
<!-- header.html -->
<header>
<h1>My Awesome Site</h1>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
次に、このheader.htmlを他のテンプレートから呼び出すには、th:replaceを使います。
<!-- main.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleaf Example</title>
</head>
<body>
<div th:replace="fragments/header :: header"></div>
<h2>Welcome to the homepage!</h2>
</body>
</html>
このようにth:replaceを使うことで、main.htmlの中にheader.htmlの内容を挿入することができます。これにより、ヘッダー部分の修正が必要な際は、header.htmlだけを編集すれば、全ページに反映されるため、メンテナンスが容易になります。
3. th:replaceの使い方の応用
th:replaceには、引数を渡すこともできます。例えば、動的にページタイトルを変更したい場合、引数として設定することが可能です。
<!-- fragment.html -->
<div>
<p>This is a reusable component.</p>
<p>Title: [[${title}]]</p>
</div>
<!-- page.html -->
<div th:replace="fragments/fragment :: this (title='Dynamic Page')"></div>
これにより、titleパラメータがfragment.htmlに渡され、「Title: Dynamic Page」という出力になります。このように動的なパラメータを使用することで、より柔軟なテンプレートの再利用が可能です。
4. th:replaceとth:includeの違い
th:replaceとよく似た属性にth:includeがありますが、これらには違いがあります。th:replaceは、指定したテンプレートの内容全てを置き換えますが、th:includeは、テンプレートの内容をそのまま挿入します。以下の例を見てみましょう。
<!-- fragment.html -->
<div>共通のコンテンツ</div>
<!-- page.html -->
<div th:include="fragments/fragment :: this"></div>
th:replaceの場合はpage.html内の<div>が完全に置き換わりますが、th:includeの場合は内部に内容が挿入されます。この違いを理解することで、適切に使い分けることができます。
5. よくあるth:replaceのエラーと対処法
th:replaceを使用する際、テンプレートファイルのパスが間違っているとエラーになります。Template not foundというエラーメッセージが表示された場合、指定したファイルパスや名前を再度確認しましょう。また、Thymeleafのパス指定にはclasspath:を使うこともできます。
<div th:replace="classpath:/templates/fragments/header :: header"></div>
これで、テンプレートの読み込み先をクラスパスから指定することができ、パスの問題を回避することができます。
6. フラグメント表現(~{...})と参照ルールの基本
th:replaceでは、フラグメント表現のチルダ記法(~{...})を使うと、テンプレート解決のルールが明確になり可読性が高まります。ファイルパスとフラグメント名(::)を組み合わせて指定します。
<!-- fragments/header.html -->
<header th:fragment="siteHeader">
<h1>My Awesome Site</h1>
<nav>...</nav>
</header>
<!-- main.html -->
<div th:replace="~{fragments/header :: siteHeader}"></div>
同一ディレクトリ配下であれば相対指定、別ディレクトリであればパスを含めて指定します。フラグメント名はテンプレート内のth:fragment="...名..."に一致させます。
7. フラグメントにパラメータを渡す(複数・オブジェクト・デフォルト値)
再利用性を高めるために、フラグメントに引数を定義して値を渡せます。複数パラメータ、オブジェクト、デフォルト値の表現も可能です。
<!-- fragments/panel.html -->
<section class="card p-3" th:fragment="panel(title, user, note)">
<h3 class="fs-4">[[${title}?:'無題']]</h3>
<p>ユーザー:[[${user.name}]]</p>
<p th:if="${note}">メモ:[[${note}]]</p>
</section>
<!-- page.html -->
<div
th:replace="~{fragments/panel :: panel(
'ダッシュボード', ${loginUser}, note=${message?:'初回アクセス'}
)}"></div>
フラグメント側は引数名で参照し、呼び出し側はリテラル・式・名前付き引数(name=value)を混在できます。?:でデフォルト値を表現できます。
8. 条件分岐・繰り返しとth:replaceの組み合わせ
表示条件やリスト描画と組み合わせると、共通フラグメントを状況に応じて差し替えられます。
<!-- fragments/auth.html -->
<div th:fragment="loginButton"><a href="/login" class="btn btn-primary">ログイン</a></div>
<div th:fragment="profile(user)"><span>ようこそ、[[${user.name}]] さん</span></div>
<!-- header.html(呼び出し側) -->
<div th:if="${#authorization.expression('isAuthenticated()')}"
th:replace="~{fragments/auth :: profile(${loginUser})}"></div>
<div th:if="${!#authorization.expression('isAuthenticated()')}"
th:replace="~{fragments/auth :: loginButton}"></div>
<!-- 繰り返しで行フラグメントを挿入 -->
<ul>
<li th:each="prod : ${products}"
th:replace="~{fragments/product :: row(product=${prod})}"></li>
</ul>
th:ifやth:eachで制御しつつ、行・カードなどのUI単位をフラグメント化すると、保守性と一貫性が向上します。
9. レイアウト設計のベストプラクティス(ヘッダー・フッター・<head>の置き換え)
ページの骨組みをレイアウト化し、ヘッダー・フッター・メタ情報をフラグメントとして分割すると、全ページの統一と変更容易性が高まります。
<!-- fragments/layout.html -->
<head th:fragment="head(title)">
<meta charset="UTF-8">
<title>[[${title}]] | My Awesome Site</title>
<link rel="stylesheet" href="/css/site.css">
</head>
<header th:fragment="header">...共通ナビ...</header>
<footer th:fragment="footer">...共通フッター...</footer>
<!-- page.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/layout :: head('商品一覧')}"></head>
<body>
<div th:replace="~{fragments/layout :: header}"></div>
<main class="container py-4">
<h1>商品一覧</h1>
<!-- ページ本体 -->
</main>
<div th:replace="~{fragments/layout :: footer}"></div>
</body>
</html>
メタやアセットの差し替えは<head>ごと置き換えると管理が容易です。共通部品は「1ファイル=1責務」を意識してフラグメント化しましょう。
まとめ
ここまで、Thymeleafのth:replaceについて詳しく解説してきました。th:replaceはテンプレートの再利用を促進し、HTMLの重複を減らして保守性を向上させる便利な機能です。特に、共通パーツを複数のページに簡単に挿入できるため、ヘッダーやフッターなどの共通要素を管理する際に役立ちます。また、th:replaceとth:includeの違いを理解することで、場面に応じた適切なテンプレート管理が可能となります。
さらに、動的にパラメータを渡すことで、テンプレートの柔軟性が増し、ページごとに異なる情報を表示することができます。th:replaceを使う際には、パスの指定に注意することが大切です。Template not foundというエラーが発生した場合は、テンプレートのパスを見直し、classpath:を用いた指定方法も検討してみましょう。
このようにThymeleafのth:replaceは、開発効率を上げるために欠かせない機能の一つです。テンプレートエンジンの特性を活かし、メンテナンスが容易なコードを作成することができます。これからThymeleafを活用して、効率的なWebアプリケーションの開発に取り組んでいきましょう。
生徒
「先生、今日学んだth:replaceって、実際にどうやって活用すればいいですか?」
先生
「いい質問ですね。例えば、会社のWebサイトで複数のページに同じヘッダーやフッターを使いたい場合にth:replaceが役立ちますよ。一度作ったテンプレートを再利用するだけで、全てのページに反映されます。」
生徒
「じゃあ、新しいページを追加しても、ヘッダー部分を変更するときは一箇所だけ直せばいいんですね!」
先生
「その通りです。さらに、動的にパラメータを渡すことで、より柔軟にテンプレートを使い回すことができますよ。例えば、ページごとに異なるタイトルを設定することも簡単です。」
生徒
「なるほど!パラメータの設定って実務でも使いそうですね。次は実際にコードを書いてみたいです。」
先生
「ぜひ挑戦してみてください。まずはシンプルな例から始めて、慣れてきたら動的な引数を活用してみると良いですよ。」
今回の学習を通じて、Thymeleafのth:replaceの基本から応用までを理解することができました。これを機に、より効率的なWeb開発に役立ててくださいね。
さらに深く学びたい場合は、th:fragmentやth:includeなどの他のThymeleaf属性も試してみると良いでしょう。これらを組み合わせることで、テンプレートの再利用性が飛躍的に向上し、保守性の高いコードを書くことができます。