<th:each>を使ってリストをループ表示しよう!初心者でもわかるThymeleaf繰り返し構文
新人
「Spring MVCで画面にリストを繰り返して表示したいんですけど、どうやればいいですか?」
先輩
「それなら、Thymeleafのth:eachを使えば簡単にできるよ。」
新人
「th:eachってどういうものなんですか?初めて聞きました。」
先輩
「それじゃ、th:eachの基本から順番に説明していこう!」
1. th:eachとは何か
th:eachは、Spring MVCでThymeleafテンプレートを使ってHTMLにデータを表示する際に、リストや配列などのコレクションをループさせて繰り返し表示するための属性です。
たとえば、ユーザー一覧や商品リスト、カテゴリのメニューなど、複数の項目を同じ形式で並べたいときに便利です。
th:eachは、Javaの拡張for文のような感覚で使うことができ、書き方もシンプルです。
<ul>
<li th:each="item : ${items}">[[${item}]]</li>
</ul>
この例では、itemsというリストを繰り返して、それぞれの要素をitemとして表示しています。
このように、Thymeleafのth:eachを使えば、複数の要素を簡単にHTML上でループ表示することができます。SEO対策としても、リスト構造で情報を出力することで検索エンジンに認識されやすくなります。
2. どのような場面で使うのか
th:eachが活躍するのは、たとえば次のような場面です。
- 商品一覧を表示するECサイトの画面
- ユーザー一覧を管理画面で表示する機能
- カテゴリリストやナビゲーションメニューを動的に表示する場面
- コメント一覧や通知履歴のような繰り返し要素を表示するとき
これらはすべて、「同じパターンで複数の情報を表示する」ため、th:eachが適しています。
以下は、Spring MVCの@ControllerからModelにデータを渡し、テンプレート側でth:eachを使って表示する基本のイメージです。
@Controller
public class ItemController {
@GetMapping("/items")
public String showItems(Model model) {
List<String> itemList = List.of("商品A", "商品B", "商品C");
model.addAttribute("items", itemList);
return "item-list";
}
}
このitemsというリストを、Thymeleafのテンプレートで以下のように繰り返し表示します。
<ul>
<li th:each="item : ${items}">[[${item}]]</li>
</ul>
このように、Spring MVCとThymeleafを連携させれば、Pleiades環境での開発でもスムーズにループ処理が行えます。Gradleで依存関係を追加していれば、複雑な設定も不要で使い始めることができます。
なお、th:eachは配列・List・Setなど、複数の形式に対応しており、Javaオブジェクトであればほとんど問題なくループに使えます。
特に、初心者にとってループ処理は必ず通る道なので、th:eachの使い方を理解することは、Spring MVCによるWebアプリケーション開発の基礎としてとても重要です。
3. th:eachの基本的な書き方と構文
th:eachの基本構文はとてもシンプルです。「ループ変数 : オブジェクトのリスト」の形式で記述します。たとえば、Javaでリストをループする拡張for文に似たイメージです。
書き方の構文は以下のようになります。
<div th:each="item : ${itemList}">
[[${item}]]
</div>
ここでは、itemListがリスト(Listや配列など)で、itemが繰り返し処理中に使う1件分の変数です。
上記の例では、itemListに入っている全ての要素を順番にitemに代入して、<div>内に表示する処理になります。
ループ中のitemは、JavaBeanであればプロパティアクセスも可能です。たとえば、次のようにitem.nameやitem.priceなど、オブジェクトの中の情報を表示することも可能です。
<tr th:each="item : ${itemList}">
<td>[[${item.name}]]</td>
<td>[[${item.price}]]</td>
</tr>
このようにth:eachは、オブジェクトの中身を展開するのにも適しており、テンプレート側で繰り返し処理を直感的に記述できます。
4. Spring MVCのコントローラからリストを渡す方法
次に、th:eachを使うには、Java側からテンプレートにリスト(配列やListなど)を渡す必要があります。Spring MVCでは、コントローラでModelにオブジェクトを追加するだけで簡単にテンプレートに値を渡すことができます。
以下は、@Controllerを使ったコントローラの例です。Pleiadesでプロジェクトを作成し、Gradleで依存関係を追加していれば、このような構成が一般的です。
@Controller
public class ProductController {
@GetMapping("/products")
public String showProducts(Model model) {
List<Product> productList = new ArrayList<>();
productList.add(new Product("りんご", 150));
productList.add(new Product("バナナ", 100));
productList.add(new Product("ぶどう", 300));
model.addAttribute("productList", productList);
return "product-list";
}
}
この例では、「productList」という名前でModelにデータを渡しており、テンプレート側で${productList}として参照できます。
このようにSpring MVCの構造に慣れてくると、テンプレートに複雑なリストやテーブルを動的に表示することが容易にできるようになります。
5. テンプレートでリストをループして表示する具体例
では、実際にテンプレート側でth:eachを使って、先ほどのproductListをループ表示するHTMLを見てみましょう。
以下は商品名と価格を表形式で表示するテンプレートの例です。
<table>
<thead>
<tr>
<th>商品名</th>
<th>価格(円)</th>
</tr>
</thead>
<tbody>
<tr th:each="product : ${productList}">
<td>[[${product.name}]]</td>
<td>[[${product.price}]]</td>
</tr>
</tbody>
</table>
このようにth:eachを使えば、Spring MVCで@Controllerから渡したリストをテンプレート側で簡単にループして表示できます。
もし、Java側でProductクラスを用意していない場合は、以下のように作成します。
public class Product {
private String name;
private int price;
public Product(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
}
このクラスを使って、コントローラからテンプレートに渡すと、テンプレート側でプロパティを${product.name}や${product.price}で簡単に参照できます。
このようにThymeleafとSpring MVCの連携により、複雑な処理をしなくても、リストのループ表示がとても自然な形で実装可能です。
特に初心者の方は、th:each リスト表示やSpring MVC ループ表示というキーワードで検索されることが多いため、この使い方をしっかり覚えておくと、他のシステム開発にも応用できます。
テンプレート側の記述をシンプルに保ちながら、動的なリスト出力が可能な点は、Thymeleafの大きな魅力のひとつです。
6. ループ内でのインデックスや条件の使い方
Thymeleafのth:eachでは、ループ処理の中で現在のインデックス番号を取得したり、先頭か最後かを判定したりといった便利な機能を使うことができます。こうした情報を取得するには「ステータス変数」を使います。
ステータス変数は、ループの中で使える補助的な情報で、構文は次のようになります。
<tr th:each="product, stat : ${productList}">
<td>[[${stat.index}]]</td>
<td>[[${product.name}]]</td>
</tr>
この例では、statがステータス変数として定義されています。stat.indexは現在のインデックス(0始まり)、stat.countは1から始まる連番を表します。
また、stat.firstで最初の要素かどうか、stat.lastで最後の要素かどうかを判定できます。
<tr th:each="product, stat : ${productList}" th:classappend="${stat.first} ? 'first-row'">
<td>[[${product.name}]]</td>
</tr>
このように、ステータス変数を使えば、ループの中で柔軟に条件分岐をすることができ、th:each ステータス変数の使い方は覚えておきたい基本ポイントです。
7. よくある間違いや注意点
初心者がth:eachを使っていてよく遭遇するミスをいくつか紹介します。
まずは、nullのリストをテンプレートに渡してしまうことです。Spring MVCの@ControllerからModelに渡すリストがnullだと、テンプレート側でth:eachを使ってもループ処理が実行されず、表示もされません。
このようなときは、Java側で空のリスト(例えばCollections.emptyList()など)を渡すようにしましょう。
@GetMapping("/users")
public String showUsers(Model model) {
List<User> userList = null;
// データ取得が失敗した場合などを考慮
if (userList == null) {
userList = new ArrayList<>();
}
model.addAttribute("users", userList);
return "user-list";
}
次によくあるのが、ネストされたth:eachの使い方です。たとえば、カテゴリごとに商品を表示するような場合、入れ子構造になります。
<div th:each="category : ${categoryList}">
<h3>[[${category.name}]]</h3>
<ul>
<li th:each="item : ${category.items}">[[${item.name}]]</li>
</ul>
</div>
このようにネストする場合、リスト名やループ変数名が重複していると予期しない挙動になることがあります。必ず異なる名前をつけるようにしましょう。
また、テンプレート側で表示されないときは、HTML構造に問題がないか、th:属性のスペルミスがないかも確認するとよいです。
Thymeleaf nullチェックやth:if、th:unlessなども併用することで、安全でわかりやすい表示が可能になります。
8. 学習を深めるためのヒント
ここまでth:eachの基本的な使い方やコントローラとの連携、リストのループ処理について解説してきましたが、さらに理解を深めるためには日々の練習が大切です。
まずおすすめしたいのは、Thymeleafの公式ドキュメントを読むことです。日本語訳もあるため、ステータス変数や条件付きレンダリングなども体系的に学ぶことができます。
また、実際に@Controllerでダミーデータを用意してテンプレートに渡し、th:eachでさまざまなレイアウトを試すことで、理解がどんどん深まります。
さらに、次のようなキーワードでネット検索をして、実践的な情報を集めるのも効果的です。
- Spring MVC テンプレートループ
- Thymeleaf ステータス変数
- th:each 条件付き表示
- Thymeleaf nullチェック best practice
たとえば、「特定の項目だけ背景色を変える」「偶数行と奇数行で色を切り替える」などのテクニックも、stat.evenやstat.oddを使うことで実現できます。
<tr th:each="product, stat : ${productList}" th:classappend="${stat.even} ? 'bg-light'">
<td>[[${product.name}]]</td>
<td>[[${product.price}]]</td>
</tr>
このような応用方法を身につけておくと、実務でも見やすく整理されたテンプレートが作れるようになります。
そして最後に、他の人のコードを読むことも良い学びになります。GitHubなどのオープンソースプロジェクトで、Spring MVCとThymeleafを使った実装例を参考にすると、自分にはない発想や設計の工夫を学べます。
ぜひ、「作って試す」「調べて読む」を繰り返して、th:eachの使い方をしっかりマスターしていきましょう。