Formのバインドについて
本日のお題
本日のお題は、フォームのバインドについてです。
目次
- フォームのバインドとは
- クラスの作成
- コントローラの編集〜getSignup編
- ビューの編集
- コントローラの編集〜postSignup編
フォームのバインドとは
フォームのバインドとは、フォームのname属性をキーとして入力内容をコントローラで取り出すための処理のことです。
例えば、RailsやLaravelであれば以下のような処理でフォームの内容を簡単に取り出すことができていました。
Rails: params[:age]
Laravel: $request->input("age");
これは、この記述だけで意図したものを取り出せるようにあらかじめフレームワークの側でプログラムが組まれているためなのですが、Spring Bootではこの記述をある程度自分自身で行う必要があります。
以下、順番にそのための作業をしていきます。
クラスの作成
まず、フォームの内容を管理するためのJavaクラスを作ります。
今回は、サインアップフォームを作成するので、demo(アプリ名)/applicationディレクトリにform/SignupForm.javaを作ります。
ここではまず、フォームで入力してもらいたい要素(ユーザー名や年齢など)を、SignupFormクラスのインスタンスフィールド化します。
ーーSignupForm.javaーー
package com.example.demo.apprication.form.SignupForm;
import lombok.Data;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
@Data
public class SignupForm{
private String userId;
private String userName;
private String password;
@DateTimeFormat(pattern = "yyyy/mm/dd")
private Date birthday;
private Integer age;
private Integer gender;
}
ポイントになってくるのは、赤線部分の2行ですね。
前半の@DateTimeFormat(pattern = "yyyy/mm/dd")は、指定したフォーマットで入力された文字列をDate型に変換してくれる役割を持っています。
例えばフォームで"1990/01/01"と入力しても、そのままだと"1990/01/01"という文字列(Stirng型)として記録されてしまいます。
ですがこのアノテーションをつけることによって、直後に定義しているbirthdayというインスタンスフィールドに対して、"yyyy/mm/dd"形式の文字列がDate型に変換された状態でセットされるようになります。
コントローラの修正〜getSignup編
フォームを定義するモデルが定義できたので、コントローラを修正します。
まずは、フォームのある画面に遷移するためのgetSingupメソッドを修正します。
importの追加
import org.springframework.web.bind.annotation.ModelAttribute;
import com.example.demo.application.form.SignupForm;
import lombok.exterm.slf4j.Slf4j;
getSignupメソッドの編集
public String getSignup(Model model, Locale locale, @ModelAttribute SignupForm form){
// メソッドの中身はそのままでOK
}
ポイント
ポイントは、引数として追加されている@ModelAttribute SignupForm formですね。
これを追加することで、以下の作業を自動で行ってくれています。
model.addAttribute("signupForm", form);
つまり、先程SignupFormクラスで定義した内容からformというインスタンスを作り、それをsignupFormというキーでビューに渡せるようにしてくれているのですね。
次に、このsignupFormの内容をビューで表示できるようにしていきます。
ビューの編集
ビューの編集のポイントは、object属性とfield属性を使うということです。
どちらもthymeleaf専用の属性ですね。
以下、使用例です。
<form th:object="${signupForm}" .....>
<input type="text" th:field="*{userName}" ....>
.....以下略.....
まず、form要素に対してth:object="{$signupForm}"としてこのフォームをどのクラスにバインドするのかを指定します。
次に、<input th:field="*{userName}"として、各フォーム部品をバインド先のクラスのどのインスタンスフィールドに対応させるのかを指定します。
$ではなく*を用いているところに注意してください。
これで、フォームに入力された値をコントローラで受け取れるようになりました。
th:fieldについての補足
th:field="*{userName}"とした場合、name="userName" id="userName"に変換されてビューに表示されます。
コントローラの編集〜postSignupメソッド編
ビューができたので、次にフォームの内容をコントローラで受け取れるようにしていきます。
以下のようにメソッドを編集します。
// 引数を追加
public String postSignup(@ModelAttribute SignupForm form){
一旦は、フォームの内容をログで出力
log.info(form.toString());
return "redirect: /login";
}
本来ならば、受け取ったパラメータをDBに保存する処理を書くのですが、一旦はログ出力してどのような形でパラメータが送信されているのかを見てみます。
ちなみに、このlog.infoメソッドは、@slf4jアノテーションを用いることで使用可能になります。
フォームから受け取った内容
SignupForm(userId=213399, password=0000000a, userName=test, birthday=Mon Jan 01 00:00:00 JST 1990, age=31, gender=1)
フォームから受け取った内容は以上のようになっています。
終わりに
とりあえずこれで、フォームに入力された値を受け取ることが可能になりました。
本来であればこのあとはDBへの登録処理などを記述していくのですが、その前に次回ではバリデーションを設定していきたいと思います。