フォーム送信とバインド(th:object, th:field)の使い方!Thymeleafのデータ送信の基本
新人
「Spring MVCでフォームの送信をやってみたいんですが、どうすればいいですか?」
先輩
「フォーム送信では、th:objectとth:fieldを使うと、データのバインドが簡単にできるんだ。これを使えば、ユーザーが入力したデータを自動的にモデルにマッピングできるんだよ。」
新人
「なるほど!でも、th:objectとth:fieldって具体的に何をしているんですか?」
先輩
「よし、それじゃあ基本から順に説明していこう!」
1. フォーム送信とは?
Webアプリケーションでは、ユーザーからデータを入力してもらい、そのデータをサーバーに送信して処理することがよくあります。これが「フォーム送信」です。例えば、会員登録フォームやお問い合わせフォームなどがこれにあたります。
Spring MVCでは、フォーム送信時にデータを受け取り、コントローラで処理を行います。その際に役立つのがThymeleafのth:objectとth:fieldです。これらを使うことで、入力されたデータが自動的にモデルオブジェクトにバインドされ、コードがシンプルでわかりやすくなります。
※バインド(bind)とは、「ひもづける」ことを意味します。
Webアプリの文脈では、フォームで入力された値(たとえば名前やメールアドレスなど)を、Javaのオブジェクト(モデルクラス)に自動的にセットすることを「バインド」と呼びます。
2. th:objectとは?
th:objectは、フォーム全体にバインドするモデルオブジェクトを指定するために使います。この属性を使用することで、フォーム内のすべてのth:fieldが指定したオブジェクトと関連付けられます。
例えば、ユーザー情報を入力するフォームの場合、th:object="${user}"と記述すれば、フォーム内の各フィールドがuserオブジェクトのプロパティと自動的に紐づきます。
<form th:action="@{/submit}" th:object="${user}" method="post">
<label>名前:</label>
<input type="text" th:field="*{name}" />
<br/>
<label>メールアドレス:</label>
<input type="email" th:field="*{email}" />
<br/>
<button type="submit">送信</button>
</form>
このように書くことで、ユーザーが入力したnameやemailの値が、モデルに渡されたuserオブジェクトのプロパティに自動的にバインドされます。
3. th:fieldとは?
th:fieldは、フォームの各入力フィールドにモデルオブジェクトのプロパティをバインドするために使います。この属性を使うと、フォーム送信時に自動でデータがモデルにマッピングされます。
例えば、th:field="*{name}"と書くと、th:objectで指定したオブジェクトのnameプロパティと関連付けられます。これにより、以下のメリットがあります。
- 入力値が自動的にモデルに反映される
- 初期値の表示やエラー時の再表示が簡単になる
- 保守性が向上し、コードが短くて済む
<input type="text" th:field="*{name}" placeholder="名前を入力" />
<input type="email" th:field="*{email}" placeholder="メールアドレスを入力" />
このコードでは、ユーザーが入力した値が自動的にuserオブジェクトのnameとemailにバインドされます。これにより、フォーム処理が簡単になり、開発効率が大幅に向上します。
4. モデルクラスの作成方法とデータバインドの流れ
フォーム送信でユーザーが入力したデータを受け取るためには、まずモデルクラスを作成する必要があります。このモデルクラスは、フォームの入力フィールドとデータをバインドする役割を担います。以下は、ユーザー情報を管理するUserクラスの例です。
package com.example.demo.model;
public class User {
private String name;
private String email;
public User() { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
このクラスでは、nameとemailという2つのフィールドを持ち、それぞれに対応するゲッターとセッターを用意しています。フォームの入力値は自動的にこれらのフィールドにバインドされます。
5. コントローラの作成方法(@Controllerを使用)
次に、フォームを表示し、送信されたデータを受け取るためのコントローラを作成します。Spring MVCでは@Controllerを使用して、リクエストの処理を行います。
package com.example.demo.controller;
import com.example.demo.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class UserController {
@GetMapping("/form")
public String showForm(Model model) {
model.addAttribute("user", new User());
return "user-form";
}
@PostMapping("/submit")
public String submitForm(@ModelAttribute User user, Model model) {
model.addAttribute("submittedUser", user);
return "result";
}
}
showFormメソッドでは、新しいUserオブジェクトを作成し、モデルに追加しています。これにより、フォームが表示されたときにth:object="${user}"が有効になります。
submitFormメソッドでは、@ModelAttributeを使用してフォームから送信されたデータをUserオブジェクトにバインドしています。受け取ったデータはsubmittedUserとして結果ページに表示されます。
6. フォーム画面の作成とth:object, th:fieldの活用
次に、Thymeleafテンプレートを作成して、実際にユーザーが入力するフォーム画面を作成しましょう。以下はuser-form.htmlのコードです。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ユーザーフォーム</title>
</head>
<body>
<h2>ユーザー情報入力フォーム</h2>
<form th:action="@{/submit}" th:object="${user}" method="post">
<label for="name">名前:</label>
<input type="text" id="name" th:field="*{name}" placeholder="名前を入力" />
<br/>
<label for="email">メールアドレス:</label>
<input type="email" id="email" th:field="*{email}" placeholder="メールアドレスを入力" />
<br/>
<button type="submit">送信</button>
</form>
</body>
</html>
このテンプレートでは、th:object="${user}"を使ってフォーム全体をUserオブジェクトにバインドしています。各入力フィールドにはth:fieldを使用し、nameとemailプロパティにデータがバインドされます。
フォームを送信すると、/submitエンドポイントにデータが送られ、コントローラで処理されます。以下は送信後の結果を表示するresult.htmlです。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>送信結果</title>
</head>
<body>
<h2>送信結果</h2>
<p>名前: <span th:text="${submittedUser.name}"></span></p>
<p>メールアドレス: <span th:text="${submittedUser.email}"></span></p>
<a th:href="@{/form}">戻る</a>
</body>
</html>
この結果ページでは、コントローラから渡されたsubmittedUserオブジェクトのプロパティを表示しています。これにより、ユーザーが送信したデータが正しくバインドされ、表示されていることを確認できます。
7. 実際にデータを送信してみよう(実行結果の確認)
ここまで作成したモデルクラス、コントローラ、フォーム画面を組み合わせて、実際にデータを送信してみましょう。PleiadesでSpring Bootアプリケーションを実行し、ブラウザでhttp://localhost:8080/formにアクセスしてください。
以下は、ブラウザで表示されるユーザー情報入力フォームの実行結果です。
<h2>ユーザー情報入力フォーム</h2>
<form action="/submit" method="post">
名前:<input type="text" name="name" placeholder="名前を入力" />
<br/>
メールアドレス:<input type="email" name="email" placeholder="メールアドレスを入力" />
<br/>
<button type="submit">送信</button>
</form>
このフォームにデータを入力して「送信」ボタンをクリックすると、次のような結果ページが表示されます。
<h2>送信結果</h2>
<p>名前: 山田太郎</p>
<p>メールアドレス: yamada@example.com</p>
<a href="/form">戻る</a>
フォームで入力した名前とメールアドレスが正しく送信され、結果画面に表示されていることが確認できます。これにより、th:objectとth:fieldを使用したデータバインドが正常に機能していることがわかります。
8. よくあるエラーとその解決方法
フォーム送信とデータバインドを行う際に、初心者がよくつまずくエラーについて解説します。エラーが発生した場合は、以下の解決策を試してみてください。
8.1 th:objectが機能しない
原因: コントローラでモデルにオブジェクトが正しく追加されていない場合、th:objectが機能しません。
解決方法: showFormメソッドでモデルにuserオブジェクトが追加されていることを確認してください。
model.addAttribute("user", new User());
8.2 th:fieldでデータがバインドされない
原因: th:fieldの属性名がモデルのプロパティ名と一致していない場合、データバインドが失敗します。
解決方法: モデルクラスのフィールド名とth:fieldの指定が一致しているか確認してください。
<input type="text" th:field="*{name}" /> <!-- Userクラスにnameフィールドが存在するか確認 -->
8.3 HTTP 405エラー(Method Not Allowed)
原因: フォームのmethod="post"に対応する@PostMappingがない場合に発生します。
解決方法: コントローラに@PostMapping("/submit")が正しく設定されていることを確認してください。
@PostMapping("/submit")
public String submitForm(@ModelAttribute User user) {
// 処理内容
}
8.4 テンプレートが見つからないエラー
原因: テンプレートファイルが正しい場所に配置されていない場合に発生します。
解決方法: resources/templates/フォルダ内にHTMLファイルがあることを確認してください。
resources/
└── templates/
├── user-form.html
└── result.html
9. 記事全体の振り返りとポイント解説
本記事では、Spring MVCとThymeleafを使った「フォーム送信」と「データバインド」の基本を解説しました。th:objectとth:fieldを使うことで、簡単にデータの受け渡しができるようになります。以下が今回のポイントです。
- フォーム送信の基礎: モデルクラスを用意して、データを受け取る準備をする。
- th:objectの使い方: フォーム全体にオブジェクトをバインドすることで、データのやり取りが簡単になる。
- th:fieldの役割: 入力フィールドにモデルのプロパティを関連付けて、データを自動的にバインド。
- エラー解決方法: よくあるミスを避けるために、属性名やテンプレート配置に注意する。
初心者にとってフォーム送信の仕組みは少し難しいかもしれませんが、実際にコードを書いて動かしてみることが理解への近道です。
小さなプロジェクトで練習を重ね、th:objectとth:fieldの使い方をマスターしていきましょう!