カテゴリ: Thymeleaf 更新日: 2026/01/23

Thymeleafのeachの基本!繰り返し処理の書き方

【Thymeleaf】eachの基本!繰り返し処理の書き方
【Thymeleaf】eachの基本!繰り返し処理の書き方

新人と先輩の会話形式で理解しよう

新人

「HTMLにJavaのデータを表示したいんですが、ループ処理ってどうやって書けばいいんですか?」

先輩

「それなら、Thymeleafのeach属性を使えば、リストなどを繰り返し表示できますよ。」

新人

「Thymeleafってそもそも何なんですか?Javaとどう関係があるんですか?」

先輩

「いい質問ですね。まずはThymeleafがどんなテンプレートエンジンなのかを理解しておきましょう。」

1. Thymeleafとは?

1. Thymeleafとは?
1. Thymeleafとは?

Thymeleaf(タイムリーフ)は、Javaアプリケーションと連携してHTMLテンプレートを動的に生成できるテンプレートエンジンです。Spring Frameworkと非常に相性が良く、Spring Bootでもよく使われています。Thymeleafを使うことで、サーバーサイドのJavaオブジェクトをHTMLに自然な形で埋め込むことができ、動的なWebページを効率よく作成できます。

HTMLファイルに直接Thymeleafの属性(th:textth:eachなど)を追加することで、画面にJavaの値を表示したり、繰り返し表示、条件分岐などが可能になります。

2. HTMLに組み込めるThymeleafの特徴

2. HTMLに組み込めるThymeleafの特徴
2. HTMLに組み込めるThymeleafの特徴

ThymeleafはHTMLテンプレートとしてそのままブラウザで表示できる「ナチュラルテンプレート」機能が特徴です。つまり、Thymeleafの構文を埋め込んだHTMLファイルを、開発中でも通常のHTMLとしてブラウザで確認できるため、デザイナーとエンジニアが同じファイルを扱いやすいというメリットがあります。

また、Spring MVCの@ModelAttributeやModelに追加したJavaオブジェクトを簡単にHTMLテンプレートに渡して表示できます。これにより、コントローラでデータを用意して画面に表示するまでの流れが非常にスムーズになります。

3. each属性とは何か?基本的な使い方と意味

3. each属性とは何か?基本的な使い方と意味
3. each属性とは何か?基本的な使い方と意味

Thymeleafで繰り返し処理を行いたいときに使うのがth:each属性です。Javaで用意したリストや配列の要素を、HTML上で繰り返し表示できます。たとえば、名前の一覧をループで表示したいときには、以下のように書きます。


<ul>
    <li th:each="name : ${nameList}" th:text="${name}"></li>
</ul>

このコードでは、コントローラから渡されたnameList(たとえばList<String>型の名前リスト)を、th:eachで1件ずつ取り出して li 要素として表示しています。

このname : ${nameList}という記述は、拡張for文のような構文です。nameには1つずつの要素が入り、${name}で表示されます。

コントローラ側のJavaコードは以下のように記述します。


@Controller
public class SampleController {

    @GetMapping("/names")
    public String showNames(Model model) {
        List<String> nameList = List.of("佐藤", "鈴木", "高橋", "田中");
        model.addAttribute("nameList", nameList);
        return "names";
    }
}

このようにして、Springの@ControllerでModelにリストを追加し、Thymeleafでそのリストをth:eachで表示します。

繰り返し処理を使うことで、例えば商品一覧、ユーザー一覧、コメント一覧など、さまざまな画面で役立つ実装が簡単にできるようになります。

4. eachの基本構文(th:each)の使い方と記述例

4. eachの基本構文(th:each)の使い方と記述例
4. eachの基本構文(th:each)の使い方と記述例

Thymeleafのth:eachは、HTMLの要素に対して繰り返し処理を実装するための属性です。基本構文は次のようになります。


<tr th:each="item : ${itemList}">
    <td th:text="${item}"></td>
</tr>

この構文では、Javaで作成したitemListの中身を1つずつ取り出してitemに代入し、それを表示しています。ループ処理を行うHTML要素に対してth:eachを指定するだけで、複数のデータを動的にレンダリングできます。

例えば、次のように商品名の一覧を表示するテーブルを作ることが可能です。


<table>
    <thead>
        <tr>
            <th>商品名</th>
        </tr>
    </thead>
    <tbody>
        <tr th:each="product : ${productList}">
            <td th:text="${product}"></td>
        </tr>
    </tbody>
</table>

このようにth:eachを活用することで、データベースなどから取得した複数データを自動的にHTMLへ展開できます。Thymeleafテンプレートで繰り返し処理を取り入れる際には、まずこの構文を覚えておくと良いでしょう。

5. 繰り返し中の変数(status変数など)の使い方

5. 繰り返し中の変数(status変数など)の使い方
5. 繰り返し中の変数(status変数など)の使い方

Thymeleafのth:eachでは、ループの現在の状態を表すステータス変数を使うこともできます。構文は次のように書きます。


<tr th:each="item, stat : ${itemList}">
    <td th:text="${stat.index} + 1"></td>
    <td th:text="${item}"></td>
</tr>

この例ではstatがステータス変数です。stat.indexは0から始まるインデックス、stat.countは1から始まるカウント番号を表します。

この機能を使うことで、ループの中で何番目かを表示したり、偶数行と奇数行でスタイルを切り替えるといった応用が可能です。たとえば以下のように記述します。


<tr th:each="user, stat : ${userList}"
    th:class="${stat.even}? 'even-row' : 'odd-row'">
    <td th:text="${stat.count}"></td>
    <td th:text="${user.name}"></td>
</tr>

このコードでは、stat.evenを使って偶数行にはeven-rowというクラスを、奇数行にはodd-rowというクラスを動的に付与しています。

このように、th:eachのステータス変数を使うことで、より柔軟なテンプレート処理が実現できます。

6. Java側(@Controller)でListデータを用意し、Thymeleafで表示する流れ

6. Java側(@Controller)でListデータを用意し、Thymeleafで表示する流れ
6. Java側(@Controller)でListデータを用意し、Thymeleafで表示する流れ

Thymeleafのth:eachを使って繰り返し処理を行うには、まずJava側で表示したいデータをList形式などで用意し、それをSpringの@Controllerクラスから画面に渡す必要があります。

以下は、Gradleプロジェクトでpleiades上に作成したSpring Bootアプリケーションのサンプルです。


@Controller
public class ProductController {

    @GetMapping("/products")
    public String showProducts(Model model) {
        List<String> productList = List.of("りんご", "バナナ", "みかん", "ぶどう");
        model.addAttribute("productList", productList);
        return "product-list";
    }
}

このコントローラでは、/productsというURLにアクセスしたときに、文字列のリストproductListをモデルに追加しています。

続いて、Thymeleafテンプレート(resources/templates/product-list.html)で以下のように繰り返し表示を行います。


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>商品一覧</title>
</head>
<body>
    <h1>商品一覧</h1>
    <ul>
        <li th:each="item, stat : ${productList}">
            <span th:text="'No.' + ${stat.count} + ' - ' + ${item}"></span>
        </li>
    </ul>
</body>
</html>

このHTMLテンプレートでは、th:eachproductListの要素を1件ずつ取り出し、それぞれのアイテムに番号を付けて表示しています。

このように、Javaで用意したデータをModelに追加し、Thymeleafテンプレートでth:eachを使って繰り返し処理することで、リスト形式のデータを簡単に画面に表示できます。

Spring MVCとThymeleafの連携は非常にスムーズであり、初心者でも迷わず使える構成になっています。Gradleベースのプロジェクトでも、pleiades環境で簡単に動作確認ができるため、開発環境としても扱いやすいのが特徴です。

7. eachのネスト(入れ子)で繰り返す方法

7. eachのネスト(入れ子)で繰り返す方法
7. eachのネスト(入れ子)で繰り返す方法

Thymeleafではth:eachを入れ子にして、リストの中のリストを表示するようなネスト構造の繰り返し処理が可能です。たとえば、カテゴリごとに商品を分類して表示したい場合、カテゴリのリストの中に商品リストを含むような構造を使います。

まずはJava側のデータ構造を定義します。


public class Category {
    private String name;
    private List<String> items;

    public Category(String name, List<String> items) {
        this.name = name;
        this.items = items;
    }

    public String getName() { return name; }
    public List<String> getItems() { return items; }
}

そして、コントローラでは以下のようにカテゴリリストを用意してModelに追加します。


@Controller
public class CategoryController {

    @GetMapping("/categories")
    public String showCategories(Model model) {
        List<Category> categoryList = List.of(
            new Category("フルーツ", List.of("りんご", "バナナ", "みかん")),
            new Category("野菜", List.of("にんじん", "キャベツ", "だいこん"))
        );
        model.addAttribute("categoryList", categoryList);
        return "category-list";
    }
}

続いてThymeleafテンプレートでネストされたth:eachを使って以下のように表示します。


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>カテゴリ別商品一覧</title>
</head>
<body>
    <h1>カテゴリ別商品一覧</h1>
    <div th:each="category : ${categoryList}">
        <h2 th:text="${category.name}"></h2>
        <ul>
            <li th:each="item : ${category.items}" th:text="${item}"></li>
        </ul>
    </div>
</body>
</html>

このように、categoryListの中にあるitemsリストを繰り返し処理することで、ネストされたデータ構造を画面に表示できます。Thymeleaf each ネストの処理は非常に直感的で、HTMLの構造を崩さずに記述できるのが特徴です。

8. th:ifと組み合わせて条件付きで繰り返す方法

8. th:ifと組み合わせて条件付きで繰り返す方法
8. th:ifと組み合わせて条件付きで繰り返す方法

Thymeleafではth:eachth:ifを組み合わせて、条件を満たすデータだけを繰り返し表示することも可能です。たとえば、空文字や特定のキーワードを除外したい場合に便利です。

以下は「在庫あり」の商品のみを表示する例です。まず、Java側のデータクラスを用意します。


public class Product {
    private String name;
    private boolean inStock;

    public Product(String name, boolean inStock) {
        this.name = name;
        this.inStock = inStock;
    }

    public String getName() { return name; }
    public boolean isInStock() { return inStock; }
}

コントローラで商品リストを作成し、Modelに追加します。


@Controller
public class StockController {

    @GetMapping("/stock")
    public String showStock(Model model) {
        List<Product> productList = List.of(
            new Product("テレビ", true),
            new Product("冷蔵庫", false),
            new Product("洗濯機", true)
        );
        model.addAttribute("productList", productList);
        return "stock-list";
    }
}

HTMLテンプレートではth:ifを使って、inStocktrueの商品のみを表示します。


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>在庫一覧</title>
</head>
<body>
    <h1>在庫ありの商品一覧</h1>
    <ul>
        <li th:each="product : ${productList}" th:if="${product.inStock}">
            <span th:text="${product.name}"></span>
        </li>
    </ul>
</body>
</html>

th:ifによって、繰り返し処理の中でも表示条件を柔軟に制御できます。th:unlessを使えば逆の条件(在庫なしなど)も簡単に扱えます。Thymeleafテンプレートの中でth:eachと条件分岐を組み合わせることで、より現実的な表示ロジックが実現できます。

9. よくあるエラーと対処法(eachでリストがnullの場合など)

9. よくあるエラーと対処法(eachでリストがnullの場合など)
9. よくあるエラーと対処法(eachでリストがnullの場合など)

Thymeleafのth:eachを使う際に初心者がよくつまずくポイントのひとつが、リストがnullのときのエラーです。モデルにデータが存在しない、もしくはコントローラでaddAttributeを忘れていた場合、テンプレートが正常にレンダリングされず例外が発生します。

たとえば以下のようなケースでエラーになります。


<ul>
    <li th:each="item : ${undefinedList}" th:text="${item}"></li>
</ul>

この例では、undefinedListがModelに存在しないため、Thymeleafがnullとして扱い、繰り返し処理で例外が出る可能性があります。

このような問題を避けるためには、以下のようにth:ifを使ってnullチェックを入れると安全です。


<ul th:if="${itemList != null}">
    <li th:each="item : ${itemList}" th:text="${item}"></li>
</ul>

または、コントローラ側で空のリストを初期化して渡すようにすれば、テンプレートでのエラーを防げます。


@GetMapping("/safe")
public String showSafe(Model model) {
    List<String> itemList = new ArrayList<>(); // 空のリスト
    model.addAttribute("itemList", itemList);
    return "safe-list";
}

このようにThymeleaf each エラーの回避策として、nullチェックや空のリスト初期化を意識することが大切です。初学者のうちは、nullによるエラーでテンプレートが真っ白になることもあるため、早い段階でエラーの原因を把握し、適切な対処方法を身につけておくと安心です。

まとめ

まとめ
まとめ

Thymeleafのeachでできることの振り返り

ここまで、Thymeleafのeachを中心に、Springと連携した繰り返し処理の考え方や書き方を順番に見てきました。ThymeleafはJavaのデータをHTMLに自然に組み込めるテンプレートエンジンであり、その中でもth:eachは一覧表示やデータの列挙に欠かせない存在です。リストや配列、オブジェクトの集合を扱う場面はWebアプリケーションでは非常に多く、eachの理解度がそのまま画面実装の安定感につながります。

基本となる構文は「変数 : コレクション」という形で、Javaの拡張for文に近い感覚で使えるのが特徴です。Modelに追加したListデータをテンプレート側で受け取り、HTML要素に対してth:eachを指定するだけで、複数行の表示が自動的に生成されます。商品一覧、ユーザー一覧、カテゴリ一覧など、実務でも頻繁に使われるため、まずは基本構文を迷わず書けるようになることが大切です。

ステータス変数と実務での活用ポイント

eachのもう一つの重要な要素がステータス変数です。indexやcountを使えば、何番目のデータかを表示したり、偶数行と奇数行でCSSクラスを切り替えたりできます。これにより、単なる一覧表示だけでなく、見た目やユーザビリティを意識した画面作りが可能になります。特にテーブル表示では、行番号や背景色の切り替えは定番の実装なので、ステータス変数の存在を知っているかどうかで実装スピードに差が出ます。

また、eachのネストを使えば、カテゴリと商品、親要素と子要素といった階層構造のデータも自然に表現できます。Java側でデータ構造を整理し、Thymeleafでそれをそのまま展開できるのは大きな強みです。HTMLの構造を崩さずに書けるため、後から見返したときも理解しやすく、保守性の高いテンプレートになります。

条件分岐やエラー対策も含めた実践的な考え方

th:ifやth:unlessと組み合わせることで、条件付きの繰り返し表示も簡単に実現できます。在庫ありの商品だけを表示したり、特定の条件を満たすデータだけを抽出したりする場面は現場ではよくあります。テンプレート側で最低限の条件制御ができるようになると、コントローラのコードも整理しやすくなります。

さらに、リストがnullの場合のエラー対策も重要なポイントです。eachは非常に便利ですが、Modelにデータが存在しないと例外が発生しやすいため、空のリストを渡す、もしくはth:ifで存在チェックを行うといった基本的な対策を習慣づけることが大切です。こうした細かな配慮が、画面が真っ白になるトラブルを防ぎ、安定したアプリケーションにつながります。

まとめとしてのサンプルイメージ

ここまで学んだ内容を踏まえると、Thymeleaf eachは単なる繰り返しではなく、JavaとHTMLをつなぐ重要な橋渡し役だと理解できます。データの受け渡し、表示ロジック、画面構造を意識しながら使うことで、読みやすく拡張しやすいテンプレートが完成します。


<ul th:if="${userList != null}">
    <li th:each="user, stat : ${userList}">
        <span th:text="${stat.count}"></span>
        <span th:text="${user.name}"></span>
    </li>
</ul>
先生と生徒の振り返り会話

生徒

「eachって、最初はただのループだと思っていましたけど、実際には画面作りの基本なんですね。リスト表示が一気に楽になりました。」

先生

「そうですね。Thymeleafのeachを理解すると、Springで渡したデータをどう見せるかが一気に整理できます。実務では毎日のように使いますよ。」

生徒

「ステータス変数で行番号を出したり、偶数行の色を変えたりできるのも便利でした。見た目まで制御できるのが意外でした。」

先生

「その気づきは大事です。eachは表示ロジックとデザインの両方に関わります。条件分岐やネストと組み合わせると、かなり表現力が広がります。」

生徒

「null対策も重要だと分かりました。エラーが出た理由が、少しずつ自分で説明できるようになってきました。」

先生

「それが成長の証拠ですね。Thymeleaf eachをしっかり使いこなせれば、一覧画面の実装で困ることはほとんどなくなります。次は実際に自分で画面を作ってみましょう。」

コメント
コメント投稿は、ログインしてください

まだ口コミはありません。

カテゴリの一覧へ
新着記事
New1
Springの基本
Spring Bootの@ConfigurationPropertiesScanとは?設定クラス自動検出の仕組みを解説
New2
SpringのAPI開発(REST & GraphQL)
Spring Boot GraphQLでResolverを理解しよう!初心者でもわかるデータ取得の基本
New3
SpringのAPI開発(REST & GraphQL)
Spring Boot GraphQL入門!Query・Mutation・Subscriptionの基本を初心者向けに解説
New4
SpringのDB操作
JPQLのパラメータバインド(:name / ?1)の使い方を完全解説!初心者でも迷わない基本の考え方
人気記事
No.1
Java&Spring記事人気No1
Thymeleaf
Thymeleaf とは?初心者向けにThymeleafの基本を徹底解説
No.2
Java&Spring記事人気No2
SpringのWeb開発(Spring MVC)
DispatcherServletの仕組みを理解する!初心者向け完全ガイド
No.3
Java&Spring記事人気No3
Springの基本
Spring Bootのデフォルトログ設定を徹底解説(Logback / SLF4J)
No.4
Java&Spring記事人気No4
SpringのDB操作
JPAの標準クエリメソッド(findById, findAll)を完全解説!初心者でもわかるデータ取得の基本
No.5
Java&Spring記事人気No5
SpringのWeb開発(Spring MVC)
Spring Bootでの@GetMappingと@PostMappingの基本を完全解説!初心者でも理解できる使い方
No.6
Java&Spring記事人気No6
Spring認証(Spring Security)
セッション管理の基本(@SessionAttributes)を完全解説!初心者でもわかるセッションの仕組み
No.7
Java&Spring記事人気No7
SpringのWeb開発(Spring MVC)
@Controller と @RestController の違いを完全解説!初心者向けSpring MVC入門
No.8
Java&Spring記事人気No8
SpringのWeb開発(Spring MVC)
ループ処理(th:each)の基本を完全ガイド!Thymeafの繰り返し処理の使い方