Thymeleaf th属性とは?基本の使い方をやさしく解説
新人
「先輩、Thymeleafを使って画面を作っているときにth属性ってよく見かけるんですが、これは何なんですか?」
先輩
「良いところに気が付いたね。Thymeleaf th属性はテンプレートエンジン特有の書き方で、通常のHTML属性の代わりに使うことでサーバーサイドのデータを動的に表示できる仕組みなんだ。」
新人
「なるほど、じゃあ単なるHTMLとどう違うのか気になります。具体的にどういう風に書いて、どういう使い方をするんですか?」
先輩
「それじゃあ、Thymeleaf th属性の基本から順番に見ていこうか。」
1. Thymeleafのth属性とは?
Thymeleaf th属性とは、テンプレートエンジンであるThymeleafが提供する独自の属性で、サーバーから渡された値を画面に反映させるために使います。通常のHTMLタグに似ていますが、th:textやth:hrefといった形で指定することで、HTMLの中に直接Javaのデータを埋め込めます。
例えば次のように書くと、コントローラから渡されたmessageという値をブラウザに表示できます。
<p th:text="${message}">ここにメッセージが入ります</p>
このようにThymeleaf th属性を使えば、動的なWebページを簡単に作れるのです。
2. なぜth属性を使うのか(通常のHTML属性との違い)
ではなぜ通常のHTML属性ではなくThymeleaf th属性を使うのでしょうか。その理由は大きく二つあります。ひとつは「動的に値を置き換える」ことができる点です。例えば、通常のHTMLでは静的な文字列しか書けませんが、th属性を使えばサーバーから送られてきたデータに応じて内容が切り替わります。
もうひとつは「テンプレートとしての利便性」です。Thymeleafは、静的なHTMLとして開いてもエラーにならず、動的に実行すればth属性が適用されます。これによりデザイナーとエンジニアが同じテンプレートを扱いやすくなるという利点があります。
HTML属性とth属性の違い例
<!-- 通常のHTML属性 -->
<p id="message">固定のテキスト</p>
<!-- Thymeleaf th属性 -->
<p th:text="${message}">ここにサーバーからのテキストが入る</p>
この違いを理解することで、Thymeleaf 使い方を学ぶ上での基礎がしっかり身につきます。
3. pleiades+Gradle環境でのth属性の利用前提
ここからは実際に開発環境での前提を整理しておきます。今回の記事ではpleiadesを利用したEclipse環境を想定しています。そしてビルドツールはMavenではなくGradleを使用します。プロジェクト作成時には、pleiadesのチェックでSpring WebやThymeleafの依存関係を追加することができます。
コントローラは必ず@Controllerを利用し、@RestControllerは使いません。以下はその基本的な例です。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HelloController {
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("message", "こんにちは、Thymeleafの世界!");
return "hello";
}
}
上記のコントローラからmessageというデータをビューに渡すことで、テンプレート側ではth:textを使って値を表示できます。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf th属性の例</title>
</head>
<body>
<h1>サンプルページ</h1>
<p th:text="${message}">ここにサーバーからのメッセージが入る</p>
</body>
</html>
このように、pleiades+Gradle環境であっても、特別な設定をしなくてもThymeleaf th属性はすぐに利用可能です。初心者が最初に学ぶ上でも安心して導入できます。
さらに、開発を進める中でThymeleaf th属性を意識しておくと、後のth:ifやth:eachといった発展的な機能を理解する助けにもなります。
4. th:textで画面に文字を表示する基本例
Thymeleaf th属性の中でも最もよく使われるのがth:textです。これはサーバーサイドから渡された値を文字として表示するための属性です。通常のHTMLではタグの中に固定の文字を書きますが、th:textを使うことで動的に内容を差し替えることができます。
例えばコントローラで「こんにちは」という文字列を渡したとき、テンプレートでは次のように表示できます。
<p th:text="${message}">ここにメッセージが入ります</p>
この場合、ブラウザには「こんにちは」というテキストが表示され、プレースホルダーの文字列は置き換えられます。これがThymeleaf th:textの基本的な使い方です。
重要なポイントは、th:textを使うとサーバーからの値が安全にエスケープされて表示されることです。これによりセキュリティリスクを防ぎながら動的なWebページを作成できます。
5. th:hrefやth:srcでリンクや画像を動的に設定する方法
Thymeleaf th属性は文字の表示だけでなく、リンク先や画像パスの指定にも利用できます。例えばth:hrefを使えば、サーバーから渡された値をリンクのURLとして反映できます。
th:hrefの例
<a th:href="@{/user/list}">ユーザー一覧へ</a>
この例では、アプリケーションのコンテキストパスを自動で考慮したリンクが生成されます。静的なHTMLで書くよりも柔軟で、URLが変更になった場合でもメンテナンスがしやすくなります。
th:srcの例
<img th:src="@{/images/sample.png}" alt="サンプル画像">
th:srcを使えば画像のパスも動的に指定できます。例えばユーザーごとに異なるプロフィール画像を表示する場合、サーバーから渡されたファイル名を使ってパスを組み立てられます。
<img th:src="@{'/images/' + ${user.image}}" alt="ユーザー画像">
このようにth:hrefやth:srcを利用することで、リンクや画像を柔軟に制御できるのがThymeleaf 使い方の大きな魅力です。
6. コントローラ(@Controller)から渡したデータをth属性で表示する例
次に、@Controllerから渡したデータをThymeleaf th属性で表示する具体的な流れを確認してみましょう。ここでは、ユーザーの名前とメールアドレスを画面に表示するサンプルを取り上げます。
@Controllerの例
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class UserController {
@GetMapping("/user")
public String user(Model model) {
model.addAttribute("name", "山田太郎");
model.addAttribute("email", "taro@example.com");
return "user";
}
}
上記のコードでは、コントローラがnameとemailというデータをビューに渡しています。これをテンプレート側で受け取り、Thymeleaf th属性を使って表示します。
Thymeleafテンプレートの例
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ユーザー情報</title>
</head>
<body>
<h1>ユーザー情報の表示</h1>
<p th:text="'名前: ' + ${name}">名前が表示されます</p>
<p th:text="'メール: ' + ${email}">メールが表示されます</p>
</body>
</html>
このように、@Controllerから受け取ったデータをth:textで出力すると、ブラウザには「名前: 山田太郎」「メール: taro@example.com」と表示されます。これがThymeleaf th属性を使った典型的なデータ表示の流れです。
さらに、複数の情報を組み合わせたり、条件分岐や繰り返し処理を追加したりすることで、より複雑な画面を作ることもできます。まずはこの基本を押さえておくことが大切です。
7. th:ifやth:eachを使った条件分岐や繰り返し処理
ここではテンプレートでよく使う条件分岐と繰り返しの基本を整理します。まず条件分岐はThymeleaf 条件分岐として知られる書き方で、値の有無や状態に応じて要素の表示を切り替えます。特に単純な可否であれば属性一つで読みやすく保守しやすい構造にできます。繰り返しはThymeleaf 繰り返しの代表的な機能で、一覧や表の表示に向いています。どちらもThymeleaf th属性の考え方に沿って、サーバーから渡された値を画面側で直感的に扱えるのが特徴です。
条件分岐では肯定の分岐に加えて否定形の表現も覚えておくと便利です。値が空のときだけ表示したい注意文や、権限の状態に応じて一部の項目を隠すといった用途で安全に使えます。繰り返しでは反復中の添え字や最初最後の判定を併用すると見た目の区切りや行の強調が自然に書けます。まずは基本となる最小限の例を確認してから応用へ広げていくと理解が安定します。
条件分岐の基本
<p th:if="${message != null}">メッセージがあります</p>
<p th:unless="${message != null}">まだメッセージがありません</p>
上記のように簡潔な条件で表示可否を制御できます。否定形の書き方は読み手にとって意味が分かりにくくなる場合があるため、文言と条件をそろえて迷わない表現に整えると読みやすくなります。
繰り返しの基本
<ul>
<li th:each="user, stat : ${users}" th:text="${stat.index + 1} + '番 ' + ${user.name}"></li>
</ul>
この例では反復用の情報を併用して番号付きの一覧を表示しています。先頭行や末尾行を判定して区切り線や余白を調整する処理も簡単に追加できます。反復中に別の条件を組み合わせると一覧の中で一部の要素だけ強調する表現も容易になります。
8. th属性を使うときのよくある間違いと注意点
ここでは日常の作業でつまずきやすい点を整理します。まず多いのが値の参照名の取り違えです。コントローラ側で設定した名前とテンプレート側の参照名が一致していないと表示できません。次に同じ要素へ通常の属性と動的な属性を同時に書いたときの上書きの挙動です。画面側で固定値を残したつもりでも動的な属性が優先されるため、意図しない表示になることがあります。さらに不要な空白や不正な式の区切りが混ざると表示全体が崩れることがあるため、式の境界は常に丁寧に確認します。
条件分岐では否定形を重ねた複雑な条件が読みづらさの原因になります。短い式に分けてから合成するか、役割の異なる要素に分割する方が保守性は高くなります。繰り返しでは空の一覧に対する表示を忘れがちです。一覧が空のときに反復が一度も実行されないため、何も表示されず操作の手がかりが失われます。こうした場面には空の状態用の要素を別で用意して明確に案内を出すと親切です。
名前の不一致による未表示
/* コントローラ側 */
model.addAttribute("userName", "山田太郎");
<!-- テンプレート側(誤り) -->
<p th:text="${name}">名前</p>
<!-- テンプレート側(正しい) -->
<p th:text="${userName}">名前</p>
固定値と動的値の混在
<!-- 動的な書き方だけに統一して混乱を避ける -->
<a th:href="@{/help}">ヘルプ</a>
上記のように一つの要素には一つの意図で属性を書くと混乱が起きにくくなります。どうしても両方の可能性を扱いたい場合は条件分岐で要素ごとに分けると読み手が迷いません。
空の一覧への配慮
<ul th:if="${#lists.isEmpty(users)}">
<li>まだ項目がありません</li>
</ul>
<ul th:unless="${#lists.isEmpty(users)}">
<li th:each="u : ${users}" th:text="${u.name}"></li>
</ul>
このように表示の分岐を先に置くと処理の流れが明確になり、読み手が安心してコードを追える構造になります。小さな工夫ですが毎日の作業で大きな差になります。
9. 実際の開発での活用シーン(デバッグやチーム開発での利用方法)
最後に日常の運用で役立つ使い方を紹介します。まず一覧画面の検証では繰り返しの中へ識別しやすい印を一時的に出して並び順や欠損の有無を確かめます。条件分岐の検証では境界値を意識して値が切り替わる直前直後の動きを重点的に見ます。こうした確認は短い作業時間でも効果が高く、表示の不具合を早期に見つけられます。さらに大規模な画面では要素を小さな塊に分けて条件をそれぞれ独立させ、影響範囲を明確にすると保守しやすくなります。
チーム開発では役割の異なる担当者が同じテンプレートを触ることがあります。そのため条件と繰り返しの責務を簡潔な文で近くに残し、どの値で切り替わるのか、空のときに何を出すのかを明示しておくとレビューが円滑になります。命名も重要です。短く分かりやすい名前を選び、画面の文言と近い言い回しで統一すると認識のずれが起きにくくなります。最初は地味に見えても運用期間が長いほど効果が出ます。
検証に役立つ最小例
/* コントローラ側の準備 */
model.addAttribute("flag", true);
model.addAttribute("items", java.util.List.of("りんご", "ばなな", "みかん"));
<!-- テンプレート側の検証用表示 -->
<section>
<p th:if="${flag}">条件が有効です</p>
<p th:unless="${flag}">条件が無効です</p>
<ul>
<li th:each="it, s : ${items}" th:text="${s.index + 1} + 'つめ ' + ${it}"></li>
</ul>
</section>
この最小例を基準にして値だけ差し替えると、さまざまな画面の検証を素早く回せます。反復用の情報は位置や奇数偶数の判定にも使えるため、列の背景色や区切りの表現にも応用できます。条件の組み合わせが増えてきたら小さな要素に分割し、責務ごとに読みやすさを保つのが長期運用のこつです。
案内文と空の状態の設計
<section>
<div th:if="${#lists.isEmpty(items)}">
<p>まだ項目がありません。追加の操作を実行してください。</p>
</div>
<table th:unless="${#lists.isEmpty(items)}">
<tr th:each="it : ${items}">
<td th:text="${it}"></td>
</tr>
</table>
</section>
空の状態を明確に設計しておくと利用者は迷いません。案内文は短く具体的な表現にまとめ、次の操作が分かる導線を置くと体験が向上します。日々の開発ではこの基本を丁寧に守るだけで品質と生産性が安定します。以上の流れを通してThymeleaf th属性の条件分岐と繰り返しを活用すれば、読みやすく安全で柔軟な画面を着実に組み立てられます。