ユーザ登録フォームを作成する
この章のゴール
- HTMLフォームで入力した値を、Controllerで受け取れるようにする
@RequestParamを使ってinputのname属性から値を取得する仕組みを理解する- フィールド数が増えた場合に備え、
UserFormクラスでオブジェクトとして受け取るリファクタを行う System.out.printlnでサーバ側に値が届いていることを確認する
ここまでで商品一覧や詳細ページを表示できるようになった。
次は、ユーザが会員登録を行うためのフォームを作成する。
この章では、まず「inputのname属性を使って値を受け取る」方法を学び、
その後に「複数の値をまとめて扱う」方法へと発展させる。
1. フォーム送信の流れ
フォーム送信は以下の流れで進む。
- HTMLフォームに入力し、「送信」ボタンを押す
- ブラウザがPOSTリクエストを送信(リクエストパラメータ付き)
- Controllerが
@RequestParamで値を受け取り処理を実行 - 結果画面で入力内容を表示
ここで重要なのは、inputのname属性がリクエストパラメータ名となり、
Controllerで同名の変数に値をマッピングできる点である。
2. フォーム画面を作成する
templates/user/register.html を作成する。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>ユーザ登録</title>
</head>
<body>
<header th:replace="layout/_header :: header"></header>
<main>
<h1>ユーザ登録フォーム</h1>
<form th:action="@{/register}" method="post">
<p>名前:<input type="text" name="name" /></p>
<p>メールアドレス:<input type="email" name="email" /></p>
<p>パスワード:<input type="password" name="password" /></p>
<p><button type="submit">登録</button></p>
</form>
<a href="/">▶ トップページへ戻る</a>
</main>
<footer th:replace="layout/_footer :: footer"></footer>
</body>
</html>
3. Controllerを作成して、name属性から値を受け取る
UserControllerを新規作成する。
package com.example.ecsample.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserController {
@GetMapping("/register")
public String showForm() {
return "user/register";
}
@PostMapping("/register")
public String submitForm(
@RequestParam("name") String name,
@RequestParam("email") String email,
@RequestParam("password") String password,
Model model) {
// name属性に対応した値が受け取れることを確認
System.out.println("name = " + name);
System.out.println("email = " + email);
System.out.println("password = " + password);
model.addAttribute("name", name);
model.addAttribute("email", email);
model.addAttribute("password", password);
return "user/result";
}
}
ポイント
@GetMapping("/register")は、フォーム画面を開いたとき(HTTP GET)に呼ばれる。
つまり「ページを開くリクエスト」に対応する。@PostMapping("/register")は、フォーム送信時(HTTP POST)に呼ばれる。
フォームのmethod="post"によって送信されたデータを受け取る。- 同じパス文字列
/registerでも、HTTPメソッドの違い(GETかPOSTか) によって呼び分けられる。@RequestParam("email")は、HTMLフォームの<input name="email">の値を受け取る。
HTMLフォームの name属性 と一致する名前を指定することで、リクエストの中の値を取得できる。
4. 結果画面を作成する
templates/user/result.html を作成する。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>登録結果</title>
</head>
<body>
<header th:replace="layout/_header :: header"></header>
<main>
<h1>登録結果</h1>
<ul>
<li>名前:[[${name}]]</li>
<li>メール:[[${email}]]</li>
<li>パスワード:[[${password}]]</li>
</ul>
<a href="/register">▶ 戻る</a>
</main>
<footer th:replace="layout/_footer :: footer"></footer>
</body>
</html>
5. 動作確認①(個別値)
http://localhost:8080/registerにアクセス- 名前・メール・パスワードを入力して送信
- コンソールに以下のような出力が表示されることを確認
name = 山田太郎
email = taro@example.com
password = abc123
- 結果画面に同じ内容が表示されれば成功である
6. フォーム入力値をまとめて扱えるように UserForm クラスを定義する
フォーム項目が増えるたびに、@RequestParamを1つずつ追加すると次のような問題がある。
- Controllerの引数が多くなり可読性が下がる
- 同じ入力項目を他の画面でも使いたい場合、重複コードになる
- 1つのフォームを「入力」「確認」「登録完了」で共通して扱いにくい
これを解決するために、入力データをまとめる**フォームクラス(DTO)**を用意し、
Controllerではそのオブジェクトを1つ受け取る形に変更する。
src/main/java/com/example/ecsample/form に UserForm クラスを作成する。
package com.example.ecsample.form;
public class UserForm {
private String name;
private String email;
private String password;
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
7. Controllerをリファクタする
8. フォーム画面をUserForm対応にリファクタする
これまでのフォームでは、name属性を直接使って値を受け渡していた。
UserFormクラスと@ModelAttributeを利用して、
フォーム全体をオブジェクトとして扱えるように変更する。
th:object でフォーム全体を UserForm にバインドし、
各項目には th:field="*{プロパティ名}" を指定する。
ポイント
th:object="\${form}"は、Controllerで受け渡したUserFormオブジェクトをフォーム全体に紐づける。th:field="*{name}"のように指定すると、UserFormのnameプロパティに自動でマッピングされる。- これにより、HTMLフォームとJavaオブジェクトの対応関係が明確になり、項目が増えてもコードが整理される。
@ModelAttribute UserForm formとセットで利用することで、双方向にデータを受け渡せる。
9. 結果画面の修正
10. 動作確認②(フォームオブジェクト)
- 再度
/registerへアクセスしフォーム送信 - コンソールに以下のように出力されれば成功
name = 山田太郎
email = taro@example.com
password = abc123
- 結果画面でも同じ値が
[[${form.xxx}]]で表示される
📘 この章での学び
inputタグのname属性が、サーバ側の@RequestParamと対応して値を受け渡すことを理解した- フィールドをまとめる
UserFormクラスを導入し、@ModelAttributeで受け取るリファクタを行った System.out.printlnで、フォーム入力値がサーバに届いていることを確認した
練習問題
UserFormに「住所」フィールドを追加し、フォーム・結果画面の両方で扱えるようにせよ。- 結果画面に「編集する」リンクを追加し、再入力できるようにせよ。
Gitでコミットを作成する
git add .
git commit -m "ユーザ登録フォームを作成し、UserFormでリファクタ"