前回では、Spring Bootを使ったWebアプリケーションで入力されたデータを画面間で受け渡す方法を解説しました。 今回は、入力されたデータのバリデーション(入力チェック)を解説する予定でしたが、その前に入力データをフォームオブジェクトで扱う方法を解説します。
フォームとは
画面で入力されたデータ、画面に表示するデータを一つのオブジェクトとしてまとめたものになります。 前回の実装では、コントローラーメソッドの引数で入力されたデータを受け取っていました。
public String hello(@RequestParam("name") String name, @RequestParam("age") String age, Model model) {
この方法だと、画面の入力項目の数分、引数を定義する必要があります。例えば、個人情報を入力するような画面では、苗字、名前、住所、電話番号、性別、生年月日など、入力項目が十数個になることも珍しくありません。 画面の入出力項目をフォームにまとめることで、項目の増減に対応できるようになりますし、プログラムの見通しもよくなります。
今回は、前回までに作成したWebアプリケーションを改修して、画面で入力したデータをフォームに格納し、フォームから入力したデータを表示します。
フォームクラスの作成
まずは、画面の入出力項目を格納するフォームクラスを作成します。 難しいことはなく、入出力項目をフィールドと、そのフィールドのgetter/setterメソッドを定義したクラスを作成します。 今回は入力項目として「名前」と「年齢」があるので、名前に対応するフィールド「name」をString型で、年齢に対応するフィールド「age」をInteger型で定義します。
public class ProfileForm { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
コントローラークラスの修正
次にコンロトーラークラスの修正です。前回の開設で、画面間のデータの受け渡し方法には「必要なデータをリクエストに含めて引き継ぐ」方法と、「必要なデータをサーバに保存する」方法の2通りがありました。今回は後者の「必要なデータをサーバに保存する」方法を使用して、フォームをHTTPセッションに保存します。
@Controller @RequestMapping("profile") @SessionAttributes("profileForm") public class ProfileController { @ModelAttribute("profileForm") public ProfileForm setProfileForm() { return new ProfileForm(); } @GetMapping("name") public String name() { return "name"; } @PostMapping("age") public String age(ProfileForm profileForm) { return "age"; } @PostMapping("hello") public String hello(ProfileForm profileForm, SessionStatus sessionStatus) { sessionStatus.setComplete(); return "hello"; } }
フォームをHTTPセッションに保存するためのコードは以下の箇所になります。
@ModelAttribute("profileForm") public ProfileForm setProfileForm() { return new ProfileForm(); }
このメソッドにより、setProfileFormメソッドの復帰値であるProfileFormオブジェクトが"profileForm"という名前でモデルに保存されます。
@SessionAttributes("profileForm")
そして、@SessionAttributesアノテーションにより、名前が"profileForm"のオブジェクトがHTTPセッションに保存されます。
そして、送信されたデータをフォームで受け取るためのコードは以下の箇所になります。
@PostMapping("age") public String age(ProfileForm profileForm) { return "age"; } @PostMapping("hello") public String hello(ProfileForm profileForm, SessionStatus sessionStatus) { sessionStatus.setComplete(); return "hello"; }
前回までは、引数で直接データを受信していましたが、今回は引数にフォームクラスを指定しています。 送信データの名称と、フォームのフィールド名が同じものが紐づけられ、送信データがフォームに格納されます。 メソッドの引数にフォームクラス名を指定していますが、メソッドの中で引数を参照していません。しかし、引数に指定することで送信データがHTTPセッションに保存されているフォームオブジェクトに設定されるので、必要な引数となります。
また、今回の趣旨とは違いますが、メソッドに指定しているアノテーションを変更しています。 前回は@RequestMappingアノテーションを使用して、パスとHTTPメソッドを指定しました。
@RequestMapping(path = "age", method = RequestMethod.POST)
今回は@PostMappingアノテーションに変更しています。この@PostMappingアノテーションは@RequestMappingアノテーションの合成アノテーションであり、@RequestMapping(method = RequestMethod.POST)を指定したことと同じになります。
@PostMapping("age")
画面の修正
コントローラクラスを修正することで、画面の入力データがフォームに格納されるようになりました。 次にテンプレートファイルを修正して、フォームから画面へ出力されるようにします。
年齢入力画面では、一つ前の名前入力画面で入力された名前を出力しているので、その名前をフォームから取得できるように修正します。
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Age</title> </head> <body> <form th:action="@{/profile/hello}" th:object="${profileForm}" method="post"> <p> <label for="age"><span th:text="*{name}">あなた</span>さんの年齢を入力してください</label> <input type="text" name="age" id="age"> </p> <p> <input type="submit" value="次へ"> </p> </form> </body> </html>
修正箇所は2か所です。
<form th:action="@{/profile/hello}" th:object="${profileForm}" method="post">
formタグにth:object属性でフォームオブジェクトを指定します。th:object属性でオブジェクトを指定すると、以降でオブジェクトのフィールドにアクセスしやすくなります。
<span th:text="*{name}">あなた</span>
そして、名前を出力する部分も変更があります。ぱっと見、変更箇所がわかりにくいですが、th:text属性の値を変更しています。変更前は「"${name}"」でしたが、「"{name}"」に変更しています。「${~)」では、モデルを直接参照になりますが、「{~)」ではth:object属性で指定されたオブジェクトのフィールドの参照になります。
同様に、ようこそ画面も修正します。
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Hello</title> </head> <body th:object="${profileForm}"> <p>ようこそ<span th:text="*{name}">あなた</span>さん</p> <p><span th:text="*{age}">20</span>歳なんですね。</p> </body> </html>
次回予告
今回は画面の入出力項目をフォームにまとめました。 次回こそは、入力チェック処理を実装します。
では、次回の「Spring Bootで作るWebアプリケーション⑥ - 入力バリデーション」でお会いしましょう!!