カテゴリ: Thymeleaf 更新日: 2025/12/30

Thymeleafのth:objectの使い方を完全ガイド!初心者でもわかるフォームデータの連携

Thymeleafのth:objectの使い方
Thymeleafのth:objectの使い方

先生と生徒の会話形式で理解しよう

生徒

「Thymeleafでフォームとサーバー側のデータを連携させる方法ってありますか?」

先生

「はい、Thymeleafではth:objectという属性を使って、フォーム全体をサーバーサイドのデータオブジェクトと簡単に連携させることができます。」

生徒

「具体的にはどのように使うんですか?」

先生

「それでは、th:objectの使い方を順を追って見ていきましょう!」

1. th:objectとは?

1. th:objectとは?
1. th:objectとは?

th:objectは、Thymeleafのテンプレートエンジンでフォーム全体をサーバーサイドのモデルオブジェクトと連携するための属性です。 主にSpring MVCのコントローラーと連携して、ユーザーが入力したデータを受け取ったり、初期値を設定するために使用します。

例えば、フォームを使ってユーザーの名前やメールアドレスを入力させ、それをバックエンドのJavaオブジェクトにマッピングする際に活用します。 th:objectを正しく設定することで、フォーム内の各入力要素が自動的にオブジェクトのプロパティと紐づけられます。

2. th:objectの基本的な使い方

2. th:objectの基本的な使い方
2. th:objectの基本的な使い方

th:objectを使用するには、フォームタグにth:object属性を追加します。 ここでは、ユーザーの名前とメールアドレスを入力する簡単な例を見てみましょう。


<form th:action="@{/submit}" th:object="${user}" method="post">
    <label for="name">名前:</label>
    <input type="text" id="name" th:field="*{name}" />
    <label for="email">メールアドレス:</label>
    <input type="email" id="email" th:field="*{email}" />
    <button type="submit">送信</button>
</form>

上記の例では、th:objectで指定した${user}オブジェクトに、入力された名前とメールアドレスがバインドされます。 th:fieldを使うことで、各入力フィールドとuserオブジェクトのプロパティが紐づけられます。

3. th:objectを使うメリット

3. th:objectを使うメリット
3. th:objectを使うメリット

th:objectを使う最大のメリットは、テンプレートとサーバーサイドのデータオブジェクトが簡単に連携できることです。 以下にその主なメリットをまとめます。

  • テンプレートの保守性が向上し、コードが簡潔になる。
  • Spring MVCと連携することで、データバインディングやフォームバリデーションが容易に行える。
  • 初期値の設定やエラーメッセージの表示が簡単になる。

例えば、ユーザー登録フォームで初期値を設定したい場合、コントローラー側でuserオブジェクトを作成し、初期値をセットしてビューに渡すことで、フォームに反映させることができます。

4. th:objectを使ったフォームバリデーション

4. th:objectを使ったフォームバリデーション
4. th:objectを使ったフォームバリデーション

Spring MVCとThymeleafを組み合わせることで、フォームバリデーションを簡単に実現できます。 例えば、入力必須の項目にエラーメッセージを表示する例を以下に示します。


<form th:action="@{/submit}" th:object="${user}" method="post">
    <label for="name">名前:</label>
    <input type="text" id="name" th:field="*{name}" />
    <div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
    <label for="email">メールアドレス:</label>
    <input type="email" id="email" th:field="*{email}" />
    <div th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
    <button type="submit">送信</button>
</form>

この例では、th:errorsを使って、エラーが発生したフィールドに対応するエラーメッセージを表示しています。 これにより、ユーザーがどの項目でエラーが発生したかを簡単に確認できます。

5. th:objectを使用する際の注意点

5. th:objectを使用する際の注意点
5. th:objectを使用する際の注意点

th:objectを使う際には、以下の点に注意してください。

  • サーバーサイドで正しいオブジェクトがコントローラーから渡されていることを確認する。
  • オブジェクトのプロパティ名とth:fieldの指定が一致していること。
  • フォーム送信時に適切なエラーハンドリングを実装すること。

これらを考慮することで、th:objectを使ったフォームの動作を正確に管理できます。

6. ネストしたオブジェクトとコレクションのバインド(住所・電話番号など)

6. ネストしたオブジェクトとコレクションのバインド(住所・電話番号など)
6. ネストしたオブジェクトとコレクションのバインド(住所・電話番号など)

th:objectは、ネストしたプロパティ(例:address.city)やリスト型(例:phones)にも対応できます。 住所や電話番号のように階層構造や複数行の入力を扱うときは、プロパティパスとインデックスを正しく指定します。


<form th:action="@{/users/save}" th:object="${user}" method="post">
  <!-- ネストしたオブジェクト -->
  <div class="mb-3">
    <label>郵便番号</label>
    <input type="text" th:field="*{address.postalCode}" />
  </div>
  <div class="mb-3">
    <label>都道府県</label>
    <input type="text" th:field="*{address.prefecture}" />
  </div>
  <div class="mb-3">
    <label>市区町村</label>
    <input type="text" th:field="*{address.city}" />
  </div>

  <!-- コレクション(phones) -->
  <div th:each="ph, stat : *{phones}" class="mb-3">
    <label>電話番号 [[${stat.index}+1]] 件目</label>
    <!-- インデックスを使ってコレクション要素にバインド -->
    <input type="text" th:field="*{phones[__${stat.index}__].number}" placeholder="090-xxxx-xxxx" />
    <select th:field="*{phones[__${stat.index}__].type}">
      <option value="HOME">自宅</option>
      <option value="MOBILE">携帯</option>
      <option value="WORK">勤務先</option>
    </select>
  </div>

  <button type="submit" class="btn btn-primary">保存</button>
</form>
  
  • ネストはドット記法(*{address.city})で指定。
  • リストはインデックス(*{phones[__${stat.index}__].number})で要素を特定。
  • 動的に行を追加する場合も、同じインデックス規則を守ると確実にバインドされます。

7. @ModelAttributeとth:objectの連携(コントローラー側の基本)

7. @ModelAttributeとth:objectの連携(コントローラー側の基本)
7. @ModelAttributeとth:objectの連携(コントローラー側の基本)

フォーム表示(GET)と送信(POST)で同じ属性名を使うのがポイントです。@ModelAttribute("user")の名前と、 テンプレート側のth:object="${user}"を揃えると、双方向のデータ連携が自然に機能します。


@Controller
@RequestMapping("/users")
public class UserController {

  @GetMapping("/new")
  public String showForm(@ModelAttribute("user") UserForm form) {
    // 初期値(例:電話番号1件だけ用意)
    form.getPhones().add(new PhoneForm());
    return "users/form"; // Thymeleafテンプレート
  }

  @PostMapping("/save")
  public String save(
      @Valid @ModelAttribute("user") UserForm form,
      BindingResult bindingResult) {

    if (bindingResult.hasErrors()) {
      return "users/form"; // エラー時は同じテンプレートへ戻す
    }
    // TODO: 保存処理
    return "redirect:/users/complete";
  }
}
  
  • @ModelAttribute("user")th:object="${user}"の名称一致が重要。
  • バリデーションは@ValidBindingResultで受け取り、テンプレートの#fieldsと連携。
  • 初期表示時にコレクション要素を用意しておくと、空のフォームが描画しやすくなります。

8. 既存データの編集フォーム(初期値表示・IDの保持)

8. 既存データの編集フォーム(初期値表示・IDの保持)
8. 既存データの編集フォーム(初期値表示・IDの保持)

編集フォームでは、th:fieldが自動で初期値を反映します。識別子(ID)はhiddenで保持し、 CSRF対策やメソッド、アクションはアプリの規約に合わせて設定します。


<form th:action="@{/users/update}" th:object="${user}" method="post">
  <input type="hidden" th:field="*{id}" />
  <div class="mb-3">
    <label>氏名</label>
    <input type="text" th:field="*{name}" />
  </div>
  <div class="mb-3">
    <label>メール</label>
    <input type="email" th:field="*{email}" />
  </div>
  <!-- 既存の住所・電話もそのまま表示される -->
  <div class="mb-3">
    <label>市区町村</label>
    <input type="text" th:field="*{address.city}" />
  </div>

  <button type="submit" class="btn btn-success">更新</button>
</form>
  
  • th:fieldは既存値を自動反映(th:valueの併用は不要)。
  • IDは<input type="hidden" th:field="*{id}">で送信時に失われないよう保持。
  • 表示専用の値はth:text、編集可能な値はth:fieldを使い分け。

9. セレクト・ラジオ・チェックボックス・ファイルとの連携

9. セレクト・ラジオ・チェックボックス・ファイルとの連携
9. セレクト・ラジオ・チェックボックス・ファイルとの連携

選択系やファイル入力もth:objectと相性抜群です。選択肢のリストをモデルに用意しておけば、値と表示名を分けて安全にバインドできます。


<form th:action="@{/profile/save}" th:object="${user}" method="post" enctype="multipart/form-data">
  <!-- セレクト(単一) -->
  <div class="mb-3">
    <label>都道府県</label>
    <select th:field="*{prefecture}">
      <option value="" disabled>選択してください</option>
      <option th:each="p : ${prefectureList}"
              th:value="${p.code}"
              th:text="${p.label}"></option>
    </select>
  </div>

  <!-- ラジオ(性別など) -->
  <div class="mb-3" th:each="g : ${genders}">
    <label>
      <input type="radio" th:field="*{gender}" th:value="${g.code}" />
      <span th:text="${g.label}"></span>
    </label>
  </div>

  <!-- チェックボックス(複数ロール) -->
  <div class="mb-3" th:each="r : ${roleOptions}">
    <label>
      <input type="checkbox" th:field="*{roles}" th:value="${r}" />
      <span th:text="${r}"></span>
    </label>
  </div>

  <!-- 複数選択セレクト -->
  <div class="mb-3">
    <label>興味のある分野</label>
    <select multiple th:field="*{interests}">
      <option th:each="it : ${interestOptions}"
              th:value="${it}"
              th:text="${it}"></option>
    </select>
  </div>

  <!-- ファイルアップロード(MultipartFile avatar) -->
  <div class="mb-3">
    <label>プロフィール画像</label>
    <input type="file" th:field="*{avatar}" />
  </div>

  <button type="submit" class="btn btn-primary">登録</button>
</form>
  
  • 選択肢は「値(code)と表示名(label)」を分離してモデルに用意。
  • 複数選択はコレクション型プロパティ(List<String>など)にバインド。
  • ファイルはenctype="multipart/form-data"を忘れず、サーバー側でMultipartFileを受け取ります。

まとめ

まとめ
まとめ

本記事では、Thymeleafのth:object属性について詳しく解説しました。この属性は、フォーム全体をサーバーサイドのモデルオブジェクトと連携させるための重要な機能です。 th:objectを使うことで、フォーム入力データとバックエンドのプロパティを効率的に紐づけることができます。また、th:fieldと組み合わせることで、個々の入力要素のバインディングが簡単に実現します。

特に、フォームバリデーションの実装やエラーメッセージの表示がスムーズになるため、ユーザー体験を向上させるフォーム作成に役立ちます。 以下に、もう一度基本的なフォーム例を掲載しますので、ぜひ実際に試してみてください。


<form th:action="@{/submit}" th:object="${user}" method="post">
    <label for="username">ユーザー名:</label>
    <input type="text" id="username" th:field="*{username}" />
    <label for="email">メールアドレス:</label>
    <input type="email" id="email" th:field="*{email}" />
    <button type="submit">登録</button>
</form>

このフォームでは、usernameemailのデータがサーバーサイドのuserオブジェクトにバインドされます。適切にコントローラーを設定することで、入力値を受け取ることができます。

先生と生徒の振り返り会話

生徒

th:objectを使うと、フォームとバックエンドの連携がすごく簡単になりますね!」

先生

「その通りです。th:objectを活用すれば、データバインディングが効率的になりますし、テンプレートの保守性も向上しますよ。」

生徒

「フォームバリデーションも簡単に実装できるのが良いですね。これからの開発でどんどん使ってみたいです!」

先生

「ぜひ取り入れてみてください。次は、さらに高度なフォーム機能も試してみるといいですね。」

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

Thymeleafのth:objectとは何ですか?

Thymeleafのth:objectは、フォーム全体をサーバーサイドのオブジェクトと連携させるための属性です。これにより、フォームの入力データを簡単にサーバーに渡すことができます。

フォームにth:objectを使う具体的な手順を教えてください。

フォームタグにth:objectを指定し、連携するモデルオブジェクトを指定します。そして、各入力要素にth:fieldを使ってプロパティをバインドします。

th:fieldth:objectの関係は何ですか?

th:fieldth:objectで指定されたオブジェクトのプロパティをフォーム要素と紐付ける役割を持っています。

Thymeleafでフォームの初期値を設定するにはどうすればいいですか?

フォームの初期値は、コントローラー側でオブジェクトにプロパティを設定し、そのオブジェクトをth:objectでバインドすることで実現できます。

フォームバリデーションのエラーメッセージを表示するにはどうすればいいですか?

th:errors属性を使うと、バリデーションでエラーが発生したフィールドに対応するエラーメッセージを表示できます。

Thymeleafのth:objectを使うメリットは何ですか?

th:objectを使うと、テンプレートとサーバーサイドの連携が簡単になり、データバインディングやフォームバリデーションが効率的に行えるようになります。

フォーム送信時にサーバー側でエラーが発生した場合、どう対応すればいいですか?

エラーが発生した場合は、BindingResultを使ってエラーメッセージをビューに渡し、th:ifth:errorsを使って表示できます。

ThymeleafとSpring MVCを組み合わせると何が便利ですか?

ThymeleafとSpring MVCを組み合わせると、データの入力やバリデーション、エラーメッセージの表示を簡単に行えるため、開発効率が向上します。

テンプレートエンジンとしてThymeleafを選ぶ理由は何ですか?

ThymeleafはHTMLテンプレートをそのまま使用できるため、デザイナーと開発者の間で作業がスムーズに進みます。また、動的なデータバインディングが可能で、Springと相性が良いのも特徴です。

Thymeleafのフォームでサーバーサイドのオブジェクトをどのように受け取りますか?

フォーム送信後、サーバーサイドのコントローラーで@ModelAttributeを使用してオブジェクトを受け取ります。

ネストしたプロパティ(例:address.city)がnullのときにテンプレートでエラーを避ける方法は?

コントローラーで子オブジェクト(address)を必ず初期化してからモデルに渡します。描画側では th:if="*{address} != null" でガードするのも有効です。

リストの行を削除してインデックスが飛んだ場合でもバインドできますか?

Springのバインドは連番(0,1,2…)を前提とします。送信前にJavaScriptで行を詰め直して再採番するか、描画時に stat.index を用いて連続したインデックスでname属性が出力されるようにします。

Map型のプロパティをフォームにバインドするには?

*{attributes['color']} のようにキーを指定します。一覧表示は th:each="e : *{attributes}" として e.key / e.value を使います。

Springの学習を効率化したい方へ

この記事の内容をもっと深く知るには、以下の入門書が最適です。

Spring Framework超入門をAmazonで見る
カテゴリの一覧へ
新着記事
New1
Spring
SpringDataJPAのJPAクエリメソッド「NotLike」の使い方を完全ガイド!初心者向け解説
更新記事
New2
Spring
SpringDataJPAのJPAクエリメソッド「Like」の使い方を完全ガイド!初心者向け解説
更新記事
New3
Java
JavaのLocalDateTimeクラスとplusMinutesメソッドを完全ガイド!初心者でもわかる分単位の時間操作
新規投稿
New4
Spring
SpringDataJPAのJPAクエリメソッド「IsNotNull」と「NotNull」の使い方を完全ガイド!初心者向け解説
更新記事
人気記事
No.1
Java&Spring記事人気No1
Spring
Spring BootとJavaの互換性一覧!3.5/3.4/3.3はJava 21・17に対応してる?
No.2
Java&Spring記事人気No2
Java
JavaのBooleanクラスの使い方を完全ガイド!初心者でもわかる真偽値の操作
No.3
Java&Spring記事人気No3
JSP
JSPの基本タグ一覧と使い方まとめ!実務で使えるタグを紹介
No.4
Java&Spring記事人気No4
Java
JavaのIOExceptionクラス徹底解説!初心者向けファイル入出力エラー対策ガイド
No.5
Java&Spring記事人気No5
JSP
JSPでif文・for文を使う方法!初心者でもわかるJavaとの違いと使い方
No.6
Java&Spring記事人気No6
Spring
SpringのBindingResultを完全ガイド!初心者でもわかる入力チェックとエラー処理
No.7
Java&Spring記事人気No7
Spring
SpringのModelクラスとaddAttributeメソッドの使い方を完全ガイド!初心者でも安心
No.8
Java&Spring記事人気No8
Spring
SpringDataJPAのJPAクエリメソッド「EndingWith」の使い方を完全ガイド!初心者向け解説