Thymeleaf th:replaceの使い方と応用例を初心者向けに徹底解説!
新人
「Thymeleafってテンプレートエンジンですよね?でも、具体的にどうやって使うのかイマイチ分かってなくて……」
先輩
「うん、ThymeleafはHTMLをベースにしたテンプレートエンジンで、Springと相性がいいんだ。特にth:replaceを使えば、共通部分を再利用しやすくなるよ。」
新人
「再利用ってことは、ヘッダーやフッターとかを共通化できるってことですか?」
先輩
「そのとおり!実際の使い方を順を追って見ていこう。」
1. Thymeleafとは?
Thymeleaf(タイムリーフ)は、HTMLテンプレートエンジンの一種で、Spring Frameworkでよく使われるビューの仕組みです。pleiades環境でSpringプロジェクトを作成する際、Gradleで依存関係にthymeleafを追加することで利用可能になります。
Thymeleafの最大の特徴は、「通常のHTMLファイル」としてもブラウザで開けるという点です。これはHTMLの構造を壊さず、th:textやth:ifなどの属性を追加するだけでテンプレート化できるからです。
テンプレートエンジンとは、動的な値を埋め込んでHTMLを生成する仕組みのことで、Thymeleafは特にJavaとの連携がしやすく、Spring MVCとの統合が簡単です。
2. th:replaceの基本構文と役割
th:replaceは、ThymeleafでHTMLの一部を別ファイルのコンテンツで「置き換える」ための属性です。共通のヘッダーやフッターなどを別ファイル化し、各ページに読み込むことで、テンプレートの再利用性を高めることができます。
基本構文は以下の通りです:
<div th:replace="fragments/header :: headerFragment"></div>
この例では、「fragments/header.html」というテンプレートファイル内の「headerFragment」という名前の部分が挿入されます。
テンプレート構成例
例えば、共通のヘッダーを以下のように作成しておきます。
fragments/header.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="headerFragment">
<header>
<h1>共通ヘッダー</h1>
</header>
</div>
</body>
</html>
main.html(呼び出し側):
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>トップページ</title>
</head>
<body>
<div th:replace="fragments/header :: headerFragment"></div>
<main>
<p>ここがメインコンテンツです。</p>
</main>
</body>
</html>
コントローラの設定(@Controller使用)
Springでは、以下のように@Controllerを使ってHTMLテンプレートを返す構成が一般的です。
@Controller
public class HomeController {
@GetMapping("/")
public String index() {
return "main"; // templates/main.html を返す
}
}
テンプレート再利用のメリット
th:replaceを使うことで、共通レイアウトの変更が1箇所で済みます。たとえば、複数のページで同じヘッダーを使用していても、header.htmlを修正すればすべてのページに反映されるため、メンテナンス性が格段に向上します。
ヘッダーだけでなくフッターも
フッターも同じように再利用可能です。例えば以下のように記述します:
<div th:replace="fragments/footer :: footerFragment"></div>
fragments/footer.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="footerFragment">
<footer>
<p>© 2025 Sample Inc.</p>
</footer>
</div>
</body>
</html>
ネストされたテンプレートにも対応
th:replaceは、ネストされたHTML構造の中でも問題なく使用できます。たとえば、共通レイアウトの中にさらに部品を入れ込むことも可能です。
エラーを防ぐポイント
- ファイル名とフラグメント名が一致しているか確認
th:replaceはHTMLタグを置き換えるため、記述場所に注意- HTML全体でxmlns:thの指定を忘れない
3. フラグメントファイルの作り方とth:replaceの使い方
Thymeleafでテンプレートを分割して管理する際には、「フラグメント」という仕組みを使います。フラグメントとは、th:fragmentで定義された再利用可能なパーツのことです。初心者向けに説明すると、フラグメントはHTMLの一部を部品化したもので、th:replaceを使って呼び出す対象になります。
まず、フラグメントファイルを作る際は、テンプレートフォルダ内にfragmentsディレクトリを作成し、その中にheader.htmlやfooter.htmlといった部品ごとのHTMLファイルを置くのが一般的です。これはプロジェクトの構造を整理するうえで非常に重要です。
ファイルの配置場所とパス指定が一致していないと、th:replaceで読み込めずエラーになります。たとえば、下記のようにテンプレートファイルが配置されていると仮定します:
src/main/resources/templates/main.htmlsrc/main/resources/templates/fragments/header.html
このとき、main.html内でheader.htmlのフラグメントを読み込むには、fragments/header :: headerFragmentという書き方になります。
初めてThymeleafを使う方は、フラグメントのファイルがtemplates直下ではなく、fragmentsのようなサブディレクトリにある場合でも、テンプレート名に「拡張子なし」で指定する点に注意しましょう。
4. ヘッダー・フッター・共通メニューの再利用例
テンプレートを分割して、共通化すべき代表的なパーツには以下のようなものがあります:
- ヘッダー(ロゴ・タイトルなど)
- フッター(著作権表記やリンク)
- ナビゲーションメニュー(サイドバーやグローバルメニュー)
ここでは、ナビゲーションメニューをテンプレートとして定義し、それをmain.htmlなどから呼び出す例を紹介します。
fragments/menu.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="menuFragment">
<nav>
<ul>
<li><a th:href="@{/}">ホーム</a></li>
<li><a th:href="@{/about}">会社概要</a></li>
<li><a th:href="@{/contact}">お問い合わせ</a></li>
</ul>
</nav>
</div>
</body>
</html>
main.html(呼び出し側):
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>トップページ</title>
</head>
<body>
<div th:replace="fragments/header :: headerFragment"></div>
<div th:replace="fragments/menu :: menuFragment"></div>
<main>
<p>ここがメインコンテンツです。</p>
</main>
<div th:replace="fragments/footer :: footerFragment"></div>
</body>
</html>
このように、th:replaceを活用することで、共通のヘッダー・フッター・メニューなどを一元管理でき、テンプレート再利用による保守性の向上が図れます。初心者でもこれを覚えておくことで、大規模なHTML管理がぐっと楽になります。
5. th:includeやth:insertとの違いと使い分け
Thymeleafには、th:replaceのほかにth:includeやth:insertという似た属性があります。初心者にとって混乱しやすいポイントなので、違いと使い分け方をしっかり理解しておきましょう。
th:replaceとの違い
th:replaceは、対象のHTML要素自体をフラグメントの中身と「完全に置き換える」動作をします。一方で、th:includeやth:insertは、「要素の中に挿入する」という動作です。
使い分けのポイント
- 完全に置き換えたいとき:
th:replace - 中身だけ差し込みたいとき:
th:includeまたはth:insert
例えば、以下のように記述した場合、それぞれの違いがよく分かります。
置き換え(th:replace):
<div th:replace="fragments/sample :: sampleFragment"></div>
中身を挿入(th:include):
<div th:include="fragments/sample :: sampleFragment"></div>
上記のように、同じsampleFragmentを使っても、divタグを残したいか、置き換えたいかで使い分ける必要があります。
初心者が混乱しないための補足
初心者が最初につまずくのは、「見た目が一緒なのに期待した結果が得られない」というケースです。たとえば、CSSでデザインされた親タグに対してth:replaceを使ってしまうと、タグそのものが消えるため、スタイルが崩れる可能性があります。
このようなときは、th:includeを使えば、元のタグを残したまま中身だけ差し込めるので安心です。テンプレート分割と再利用を行うときは、デザインの構造も意識しながら適切な属性を選びましょう。
まとめの前の注意点
最終的にテンプレート再利用を安定して行うためには、次のことに注意しましょう:
- フラグメントには
th:fragmentで明示的に名前をつける - ファイルのパスはテンプレートルートからの相対パスで記述する
th:replaceはHTML構造に直接影響するため、使いどころに注意する
6. 条件による動的なth:replaceの切り替え方法
Thymeleafでは、th:replaceとth:ifを組み合わせることで、条件に応じて異なるテンプレートフラグメントを読み込むことが可能です。これは、ユーザーのログイン状態や権限レベル、画面の種類に応じてヘッダーやメニューを切り替えたい場合に非常に有効です。
たとえば、ログインユーザーと未ログインユーザーで表示するメニューを切り替えるには、以下のように記述します。
<div th:if="${user != null}" th:replace="fragments/menu-loggedin :: menuFragment"></div>
<div th:if="${user == null}" th:replace="fragments/menu-public :: menuFragment"></div>
この例では、Spring側でuserというオブジェクトがセッションなどに存在しているかを判定し、ログインしている場合はmenu-loggedinを、していない場合はmenu-publicを表示しています。
条件に応じて異なるレイアウトを動的に読み込めるこの設計は、保守性の高いレイアウト設計を行ううえで非常に重要な考え方です。
7. th:replaceを使った保守性の高いレイアウト設計
実務では、複数の画面に共通するレイアウト構造を維持しつつ、各画面ごとのコンテンツを差し替える仕組みが求められます。Thymeleafのth:replaceは、このようなレイアウトテンプレートを実現するのに非常に有効です。
具体的には、親テンプレートにヘッダー・メニュー・フッターといった共通部分をth:replaceで呼び出し、個別のコンテンツエリアだけを画面ごとに定義するという設計です。
以下に、基本的なレイアウト設計の例を示します。
fragments/layout.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}">デフォルトタイトル</title>
</head>
<body>
<div th:replace="fragments/header :: headerFragment"></div>
<div th:replace="fragments/menu :: menuFragment"></div>
<div th:replace="${content}">ここに動的なコンテンツが入ります</div>
<div th:replace="fragments/footer :: footerFragment"></div>
</body>
</html>
上記のレイアウトテンプレートは、contentという変数に動的にフラグメント名をバインドすることで、柔軟に各画面の中身を切り替える仕組みになっています。
コントローラ側での指定(@Controller):
@Controller
public class PageController {
@GetMapping("/dashboard")
public String dashboard(Model model) {
model.addAttribute("title", "ダッシュボード");
model.addAttribute("content", "pages/dashboard :: content");
return "fragments/layout";
}
}
この設計により、全ページ共通のレイアウトを一元管理でき、将来的にヘッダーやフッターを変更する際もlayout.htmlやheader.htmlの編集だけで全画面に反映されるようになります。保守性と拡張性の観点で、非常に優れた設計手法です。
8. 実践例:ダッシュボード画面への適用とテンプレート設計の最適化
最後に、実務でよく使われる「ダッシュボード画面」にth:replaceを活用するテンプレート設計の具体例を紹介します。ログイン後のユーザー向けに表示されるダッシュボードは、多くの場合ヘッダー・メニュー・メインコンテンツ・フッターという構成になります。
pages/dashboard.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="content">
<main>
<h2>ダッシュボード</h2>
<p>ここにログインユーザー専用の情報を表示します。</p>
</main>
</div>
</body>
</html>
そして、前項で紹介したfragments/layout.htmlにth:replaceで埋め込まれることで、ダッシュボード用の画面が動的に生成されます。
このように、レイアウトテンプレート+個別コンテンツの分割設計を徹底することで、保守性が高く、チーム開発でも修正ミスが起こりにくい構造を実現できます。
テンプレート構造のベストプラクティス
fragmentsフォルダに共通部品を集約するpagesフォルダに個別画面の内容を分離するlayout.htmlを中央に置き、各画面でこれを再利用する
初心者でもこのようなテンプレート分割の基本を理解し、th:replaceの使い方をマスターすることで、将来的な画面追加や修正が非常に楽になります。