【Thymeleaf】eachでmapをループ処理する方法を初心者向けに解説!
新人
「Thymeleafでeachを使ってMapをループ処理したいんですけど、どうすればいいですか?」
先輩
「いいね!Thymeleafではth:each属性を使ってMapもループ処理できるんだよ。」
新人
「リストは見たことあるんですけど、Mapはkeyとvalueがあるので少し混乱してます…」
先輩
「大丈夫、順番にMapループ処理の考え方と構文を解説していこうか!」
1. Thymeleafとは?(簡単なおさらい)
Thymeleaf(タイムリーフ)は、Spring FrameworkのWebアプリケーションでよく使われるテンプレートエンジンです。HTMLファイル内にサーバーサイドのデータを埋め込むことができ、HTMLの構造を崩さずに動的なページを作成できます。JSPに代わる新しい選択肢として人気があり、Spring BootやSpring MVCと一緒に使われることが多いです。
たとえば、Thymeleafを使うことで以下のようなことが簡単にできます:
- データをHTMLに表示
- 繰り返し処理(ループ)
- 条件分岐で表示内容を切り替える
- フォーム送信時のバリデーション表示
この記事では、特に「Mapをループ処理」する方法にフォーカスして解説していきます。
2. each属性とは何か?ループ処理の基本
Thymeleafでは、リストや配列、MapなどをHTMLテンプレートで繰り返し表示するためにth:eachという属性を使います。このth:eachは、for文のような役割を果たします。
リストをループ処理する場合は、以下のような書き方をします:
<tr th:each="item : ${itemList}">
<td th:text="${item}"></td>
</tr>
itemListはControllerから渡されたリストで、itemはその1要素を表します。
このように、非常にシンプルな記述でHTMLにデータを繰り返し表示することができます。
3. Mapをループする場面と必要性
次に、Map(マップ)をループ処理する場面について見ていきましょう。
たとえば以下のようなケースでMapをループする必要があります:
- 都道府県コードと名前を一覧表示したい
- 社員IDと名前を対応させて表にしたい
- 設定名と値を一覧で確認したい
Mapにはkeyとvalueという2つの要素があるため、リストとは違って少し書き方が異なります。
以下のように、コントローラ側でMapを生成し、Thymeleafテンプレートに渡すのが基本の流れです。
@Controller
public class SampleController {
@GetMapping("/map-view")
public String showMap(Model model) {
Map<String, String> deptMap = new LinkedHashMap<>();
deptMap.put("HR", "人事部");
deptMap.put("DEV", "開発部");
deptMap.put("SALES", "営業部");
model.addAttribute("departments", deptMap);
return "map-view";
}
}
このように、ControllerでMapを生成してModelに追加し、HTML側で表示するという流れです。@Controllerを使って記述する点もポイントです。
この後の中盤では、いよいよHTMLでMapをループ処理する方法を具体的に見ていきます。
4. Mapのループ構文(th:each)を使った基本例
それでは、ThymeleafでMapをループ処理する基本的な書き方を見ていきましょう。リストのようにシンプルにループできるわけではありませんが、構文を覚えてしまえば難しくありません。
まずはth:eachを使ってMapの中身を1行ずつ取り出すHTMLコードの例です。
<table>
<thead>
<tr>
<th>部門コード</th>
<th>部門名</th>
</tr>
</thead>
<tbody>
<tr th:each="entry : ${departments}">
<td th:text="${entry.key}"></td>
<td th:text="${entry.value}"></td>
</tr>
</tbody>
</table>
このように、Mapのループではentry : ${departments}という形で、各エントリを1件ずつ取り出します。ここでのentryは1つのMap.Entryオブジェクトを表しています。
そして、entry.keyでキーの値、entry.valueでバリューの値を取り出すことができます。
5. Mapのkeyとvalueを取り出す方法
ThymeleafでMapの中のkeyとvalueを個別に使いたい場合は、Map.Entryとして扱う方法が有効です。これはJavaの標準仕様に沿った記述で、初心者でも理解しやすい方法です。
以下に、Mapの中からkeyとvalueをそれぞれ表示するHTMLのサンプルコードを示します。
<ul>
<li th:each="entry : ${departments}">
<span>コード:<span th:text="${entry.key}"></span></span> /
<span>名前:<span th:text="${entry.value}"></span></span>
</li>
</ul>
このコードでは、Mapの各要素をliタグで表示しています。たとえば「HR:人事部」「DEV:開発部」というように、コードと名称を対で表示するレイアウトを簡単に実現できます。
このようにth:eachとentry.key・entry.valueの組み合わせを覚えておくと、今後Mapを扱う場面でとても役立ちます。
6. 画面表示における注意点とデバッグ方法
ThymeleafでMapをループ処理する際、いくつかの注意点があります。まず、Mapがnullの場合や中身が空の場合には、ループ処理が実行されず、画面に何も表示されないことがあります。
そのような時は、th:if属性を使ってMapが存在しているかどうかを確認する方法があります。
<div th:if="${departments}">
<p>部門一覧:</p>
<ul>
<li th:each="entry : ${departments}">
<span th:text="${entry.key}"></span> - <span th:text="${entry.value}"></span>
</li>
</ul>
</div>
<div th:unless="${departments}">
<p>部門情報がありません。</p>
</div>
th:ifとth:unlessを使うことで、Mapが存在する場合としない場合の表示を分けることができます。
また、Mapが空であるかどうかをチェックするには、以下のような条件分岐を使うことも可能です。
<div th:if="${#lists.isEmpty(departments)}">
<p>部門情報が登録されていません。</p>
</div>
Thymeleafのユーティリティオブジェクト(#listsや#maps)を活用することで、ループの前にMapの状態を確認することができ、エラーや空表示を防ぐことができます。
そしてデバッグ方法としては、開発中に値をそのまま出力して確認することがよくあります。以下のようにpreタグ内で変数の中身を一時的に表示することで、Thymeleaf側でデータが渡っているかを確認できます。
<pre th:text="${departments}"></pre>
上記のように、Mapの内容をそのまま表示させることで、データが正しく受け渡されているかをチェックするのに便利です。
もちろん、最終的なリリース時にはこのようなデバッグ表示は削除するようにしましょう。
ここまでで、ThymeleafにおけるMapのループ処理と、keyとvalueの扱い方、表示時の注意点について学ぶことができました。
7. よくあるエラーと対処法(例:変数がnull、ループできないなど)
ThymeleafでMapをループ処理するとき、初心者がよくつまずくポイントは「変数がnullでループができない」「keyやvalueが表示されない」「テンプレートエラーでページが表示されない」などです。ここでは、よくあるエラーとその対処法を丁寧に解説します。
① Mapがnullのままループしようとしている
Controllerから渡すMapがnullの状態だと、th:eachのループ処理は実行されません。その結果、何も表示されなかったり、テンプレートエンジンの内部エラーが発生することもあります。
そのような時は、Controller側で必ずMapを初期化しておくようにしましょう。
Map<String, String> deptMap = new LinkedHashMap<>(); // nullではなく空で初期化
② keyやvalueが表示されない
ThymeleafでMapをループ処理する際に、entry.keyやentry.valueが正しく表示されない場合があります。その原因として、ループ変数名の間違いやModelに正しくデータが渡っていないケースが多いです。
ループの記述が次のようになっているかを再確認しましょう。
<tr th:each="entry : ${departments}">
<td th:text="${entry.key}"></td>
<td th:text="${entry.value}"></td>
</tr>
また、Controller側では必ずmodel.addAttribute("departments", deptMap);のようにして属性名が一致していることも確認してください。
③ エラーメッセージ例
以下のようなエラーメッセージが出た場合、それぞれ対処が必要です。
Cannot invoke "Object.getKey()" because "entry" is null→ ControllerでMapがnullのまま渡っていないか確認。Exception evaluating SpringEL expression: "entry.key"→th:eachでentryがMap.Entryとして扱われていない可能性。Model attribute 'departments' not found→ Controllerからmodelにdepartmentsが渡されていない。
8. 実践例:部門ごとの社員リストをMapで表示する(コントローラとHTML連携)
ここでは、Mapのループ処理を活かした実践的なサンプルとして、「部門ごとの社員リスト」を表示する画面を作成してみましょう。Mapの中にリストを持つような構造(Map<String, List<String>>)を想定し、実装していきます。
① コントローラーの実装
@Controller
public class EmployeeController {
@GetMapping("/employee-list")
public String showEmployees(Model model) {
Map<String, List<String>> employeeMap = new LinkedHashMap<>();
employeeMap.put("開発部", List.of("田中太郎", "佐藤花子"));
employeeMap.put("営業部", List.of("鈴木一郎", "高橋由美"));
employeeMap.put("人事部", List.of("伊藤健", "中村恵"));
model.addAttribute("employeeMap", employeeMap);
return "employee-list";
}
}
② HTML側でのループ処理
<table>
<thead>
<tr>
<th>部門名</th>
<th>社員一覧</th>
</tr>
</thead>
<tbody>
<tr th:each="entry : ${employeeMap}">
<td th:text="${entry.key}"></td>
<td>
<ul>
<li th:each="name : ${entry.value}" th:text="${name}"></li>
</ul>
</td>
</tr>
</tbody>
</table>
このように、Mapのvalueにリストが含まれる構造でも、th:eachをネストして使うことでデータを綺麗に表示することができます。
実務でもよく使われるパターンですので、しっかり理解しておくと非常に役立ちます。
9. 学習のポイントと理解を深めるためのアドバイス
ThymeleafでMapを扱う際は、次のようなポイントを意識すると理解が深まり、実務でも応用しやすくなります。
① Mapの構造を意識する
Mapはkeyとvalueの組み合わせで構成されているため、表示時にはそれぞれをどう使うかを意識することが大切です。
例えば、「都道府県コードと名称」「社員IDと氏名」など、キーとバリューの役割を明確に考えることで、テンプレートの記述もスムーズになります。
② th:eachの基本構文を定着させる
th:each="entry : ${map}"の構文を何度も使って、自然に書けるようにしておきましょう。
Mapの中にリストを持つパターンや、valueがオブジェクトの場合など、応用例にも触れておくとより理解が深まります。
③ 表示されない時は「データがあるか」をまず疑う
表示がうまくいかないときは、Modelにデータが正しく入っているか、またkeyやvalueの指定が正しいかを確認するようにしましょう。
開発中は一時的にth:text="${変数}"などで内容をダンプしておくのも効果的な方法です。
④ ドキュメントと公式リファレンスを活用しよう
Thymeleafは公式サイトに豊富なドキュメントがあり、構文やユーティリティオブジェクトの使い方も紹介されています。疑問点があればまず公式ドキュメントを参照する習慣をつけると安心です。
初心者のうちは迷うことも多いですが、実際に書いて動かしてみることで理解が深まっていきます。