フォームとHTMLをつなぐオブジェクト(Formクラス)とは?初心者でもわかるSpring MVCの基本
新人
「Spring MVCで、HTMLフォームとJavaの間をつなぐクラスってよく聞きますけど、それってなんですか?」
先輩
「それはFormクラスのことだね。Spring MVCでHTMLとJavaオブジェクトを橋渡しするために使うんだ。」
新人
「Formクラスって、具体的には何をするんですか?どんなふうに使われるんでしょうか?」
先輩
「じゃあ、Formクラスがどんな役割を持っていて、HTMLとどう連携するかを順番に説明していくよ。」
1. Formクラスとは?Spring MVCにおける基本的な役割
Spring MVCの開発において、Formクラスはとても重要な役割を果たします。Formクラスとは、HTMLの入力フォームとJavaのプログラムを結びつけるためのクラスのことです。
例えば、ユーザーが名前やメールアドレスを入力して送信するようなHTMLフォームを作ったとき、そのデータを受け取るためにJava側にFormクラスを定義します。このクラスには、フォームで入力される項目に対応するフィールド(変数)が定義されていて、Springが自動的にマッピング(値をセット)してくれる仕組みになっています。
以下は、簡単なUserFormというFormクラスの例です。
public class UserForm {
private String name;
private String email;
// ゲッターとセッター
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;
}
}
このように、Formクラスには入力項目に対応するフィールドを定義し、それに対するgetterとsetterを用意します。これによって、Spring MVCが自動的にHTMLフォームの値をJavaのオブジェクトに詰めてくれるのです。
2. FormクラスとHTMLフォームの連携方法を理解しよう
HTMLフォームとFormクラスは、@Controllerで記述されたメソッドを通して連携します。具体的には、@ModelAttributeというアノテーションを使って、リクエストされたフォームデータをFormクラスにバインドします。
以下は、Spring MVCでUserFormを使ってフォーム入力を処理する@Controllerの例です。
@Controller
public class UserController {
@GetMapping("/form")
public String showForm(Model model) {
model.addAttribute("userForm", new UserForm());
return "formPage";
}
@PostMapping("/submit")
public String submitForm(@ModelAttribute UserForm userForm, Model model) {
model.addAttribute("name", userForm.getName());
model.addAttribute("email", userForm.getEmail());
return "resultPage";
}
}
showFormメソッドでは、空のUserFormオブジェクトを作成してビュー(formPage)に渡します。次に、ユーザーがフォームを入力して送信すると、そのデータがsubmitFormメソッドに@ModelAttributeでバインドされます。
このように、HTMLフォームからの入力値は、自動的にFormクラスにマッピングされ、開発者はそのままJavaのオブジェクトとして扱えるようになります。
次に、対応するHTMLのコード例を見てみましょう。
<form action="/submit" method="post">
<label for="name">名前:</label>
<input type="text" id="name" name="name" />
<br>
<label for="email">メールアドレス:</label>
<input type="email" id="email" name="email" />
<br>
<input type="submit" value="送信" />
</form>
このHTMLでは、name属性の値がUserFormクラスのフィールド名と一致しています。Spring MVCは、この一致をもとに自動でマッピングを行い、データをFormクラスに詰めてくれます。
つまり、HTML側では特別な記述をすることなく、name属性の値をJavaクラスのフィールド名と合わせるだけで、HTMLフォームとFormクラスの連携が成立するのです。
この連携のおかげで、開発者はバリデーションや保存処理などのロジックに集中することができ、Spring MVCの仕組みによって効率的なフォーム処理が実現できます。
3. Formクラスの作り方を理解しよう
Spring MVCでフォームの値を扱うには、まずFormクラスを自分で作成する必要があります。このクラスは、Javaの通常のクラスとして作成し、HTMLフォームの入力項目に対応するフィールド(変数)と、それらに対するgetterメソッドおよびsetterメソッドを用意するのが基本です。
Spring MVCは、JavaBeansの規約に基づいて、フィールドに対してgetXxxやsetXxxといった形式のメソッドを通して値を取得・設定します。したがって、必ずプロパティ名に対応するgetterとsetterを正しく書くことが重要です。
以下に、名前・メールアドレス・電話番号を扱うContactFormというFormクラスの例を紹介します。
public class ContactForm {
private String name;
private String email;
private String phone;
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;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
このように、フォームから受け取りたい値をフィールドとして定義し、対応するアクセサ(getter・setter)を用意します。この基本を守れば、Spring MVCが自動的にフォームの値をFormクラスにバインディングしてくれます。
4. @ModelAttributeを使ってFormクラスをコントローラで受け取る
Spring MVCでは、HTMLフォームの送信内容を@Controllerで受け取る際に、@ModelAttributeアノテーションを使用します。これにより、フォームの値をFormクラスのインスタンスに自動でマッピング(バインディング)できます。
以下は、ContactFormを使って送信データを処理する@Controllerのサンプルです。
@Controller
public class ContactController {
@GetMapping("/contact")
public String showForm(Model model) {
model.addAttribute("contactForm", new ContactForm());
return "contactForm";
}
@PostMapping("/contact")
public String submitForm(@ModelAttribute ContactForm contactForm, Model model) {
model.addAttribute("name", contactForm.getName());
model.addAttribute("email", contactForm.getEmail());
model.addAttribute("phone", contactForm.getPhone());
return "contactResult";
}
}
@ModelAttributeを使うことで、Springが自動的にHTMLフォームの値をContactFormの各プロパティにセットします。フォームに入力されたデータは、コントローラ内でJavaオブジェクトとして簡単に扱えるようになります。
この方法は、データの受け渡し処理を簡潔かつ明確にするため、Spring MVCのフォーム処理における標準的な手法として広く利用されています。
5. HTMLフォームとFormクラスのバインディングの仕組み
HTMLフォームとFormクラスを正しく連携させるためには、フォーム内のname属性の値とFormクラスのフィールド名を一致させる必要があります。Spring MVCでは、このname属性を手がかりに、フォームの各入力値をFormクラスにバインディングします。
次のHTMLは、ContactFormクラスとバインディングするための入力フォームの例です。
<form action="/contact" method="post">
<label for="name">お名前:</label>
<input type="text" id="name" name="name" /><br>
<label for="email">メールアドレス:</label>
<input type="email" id="email" name="email" /><br>
<label for="phone">電話番号:</label>
<input type="tel" id="phone" name="phone" /><br>
<input type="submit" value="送信" />
</form>
ここで重要なのは、name="name"、name="email"、name="phone"といったname属性が、ContactFormクラスのname、email、phoneの各フィールド名と完全に一致している点です。この対応が正しく設定されていれば、Springが自動でバインディングを実行し、ユーザーの入力値がJavaオブジェクトに格納されます。
なお、HTML側に記述するinputタグやtextareaタグ、selectタグなど、すべての入力要素において、name属性の設定が正確であることが必須です。これを忘れてしまうと、Java側で値を受け取れなくなってしまいます。
このバインディングの仕組みを理解することで、フォーム送信後の処理が非常にスムーズになります。データの取得、バリデーション、保存といった処理を一貫して扱うことが可能になるため、Formクラスの使い方をマスターすることはSpring MVCの開発では非常に重要です。
6. Formクラスを使ったバリデーションの導入方法
フォームから送信される値に対して、必須チェックや形式チェックなどのバリデーションを行いたい場合は、@ValidアノテーションとBindingResultを組み合わせて使用します。Spring MVCでは、これらを使うことでFormクラスのバリデーション処理が簡単に実現できます。
まず、Formクラスのフィールドにバリデーション用のアノテーションを追加します。以下の例では、@NotBlankと@Emailを使用しています。
import jakarta.validation.constraints.*;
public class ContactForm {
@NotBlank(message = "名前を入力してください。")
private String name;
@NotBlank(message = "メールアドレスを入力してください。")
@Email(message = "正しいメールアドレスの形式で入力してください。")
private String email;
@NotBlank(message = "電話番号を入力してください。")
private String phone;
// getterとsetterは省略
}
次に、コントローラ側では@Validを@ModelAttributeの前に付けて、続けてBindingResultを引数に追加します。BindingResultには、バリデーションエラーがある場合の情報が格納されます。
@PostMapping("/contact")
public String submitForm(@Valid @ModelAttribute ContactForm contactForm, BindingResult result, Model model) {
if (result.hasErrors()) {
return "contactForm";
}
model.addAttribute("name", contactForm.getName());
model.addAttribute("email", contactForm.getEmail());
model.addAttribute("phone", contactForm.getPhone());
return "contactResult";
}
このように、Spring MVCでは@ValidとBindingResultをセットで使うことで、フォームの値を自動的に検証し、問題がある場合はフォーム画面に戻すといった制御が可能になります。
7. エラーがある場合の画面遷移とエラーメッセージ表示(Thymeleaf)
フォームに入力ミスがあったとき、ユーザーにエラーメッセージをわかりやすく表示することはとても大切です。Spring MVCでは、Thymeleafと組み合わせることでバリデーションエラーの表示が簡単に行えます。
以下は、Thymeleafでエラーを表示するHTMLの例です。
<form action="/contact" method="post" th:object="${contactForm}">
<div>
<label for="name">名前:</label>
<input type="text" id="name" th:field="*{name}" />
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
</div>
<div>
<label for="email">メールアドレス:</label>
<input type="email" id="email" th:field="*{email}" />
<div th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
</div>
<div>
<label for="phone">電話番号:</label>
<input type="text" id="phone" th:field="*{phone}" />
<div th:if="${#fields.hasErrors('phone')}" th:errors="*{phone}"></div>
</div>
<button type="submit">送信</button>
</form>
th:field="*{name}"のように記述することで、FormクラスのプロパティとHTMLのinputタグが連携します。そして、th:errors="*{name}"を使えば、バリデーションエラーの内容を画面に表示できます。
このようにThymeleafを使えば、エラー内容を各入力欄のすぐ下に表示できるため、ユーザーにとってもわかりやすい画面を実現できます。
8. よくあるエラーとその対処法
Formクラスを使った開発では、初心者がつまずきやすいポイントがいくつかあります。ここでは、よくあるエラーとその対処法を紹介します。
プロパティ名の不一致
HTMLのname属性とFormクラスのフィールド名が一致していないと、バインディングが行われず、値がJava側に渡らないという問題が発生します。
対処法としては、name属性の値をFormクラスのフィールド名と完全に一致させることが重要です。
getterやsetterが無い
JavaBeansの規約に従わず、getterやsetterが定義されていないと、Spring MVCは値の読み書きができません。
Formクラスを作成する際は、必ずすべてのフィールドに対してgetterとsetterを用意しましょう。
nullエラーや型変換エラー
フォームで未入力だった場合にNullPointerExceptionが発生することがあります。また、数値を期待するフィールドに文字列を入力すると型変換エラーになります。
これらのエラーを防ぐには、適切なバリデーションアノテーションを使うことと、入力欄の型を正しく指定することがポイントです。たとえば、数値入力欄にはinput type="number"を使うと、型の一致がしやすくなります。
BindingResultの順番ミス
@ValidとBindingResultはセットで使いますが、BindingResultは@Validを付けた引数の直後に記述しなければエラーになります。
// 正しい例
public String submit(@Valid @ModelAttribute ContactForm form, BindingResult result)
// 間違った例(BindingResultが離れている)
public String submit(BindingResult result, @Valid @ModelAttribute ContactForm form)
このようなミスは一見些細ですが、正しくエラーハンドリングできない原因になります。順番にも注意しましょう。
以上のように、Formクラスのエラー処理やバリデーションには細かいルールがありますが、ポイントを押さえれば誰でも扱えるようになります。