Spring 5でできることは?4からの変更点や互換性について解説
この記事は「Javaで学習するSpringによるWebアプリ開発」というトレノキャンプのeラーニング講座を基に解説した記事です。
前回の記事では、POSTデータを取得・出力する方法と、Hiddenタグを使用してデータを渡す方法について解説しました。
この記事では、これらの機能を使って確認ページを実装していきます。
記事内で使用している問い合わせアプリのプロジェクトの完全版は、以下のコース内にてダウンロードいただけます。
1.下準備
それでは、これから確認ページを作っていきますが、その前に下準備をする必要があります。
①Controllerを編集
InquiryController.javaを開いてください。
こちらのform()メソッドの第1引数にInquiryForm型のinquiryFormを追加してください。
@GetMapping("/form")
public String form(Model model) {
model.addAttribute("title", "Inquiry Form");
return "inquiry/form";
}
@GetMapping("/form")
public String form(InquiryForm inquiryForm, Model model) {
model.addAttribute("title", "Inquiry Form");
return "inquiry/form";
}
こちらの引数は呼び出される際に自動的に型で判別されますので、順番は前後しても問題ありません。
このように、Formクラスを引数に指定しておくと、フォームの入力欄と紐づけられて自動的に初期化が行われます。
それでは、保存をしておいてください。
②HTMLを編集
ではHTMLの方を見ていきましょう。
form.htmlを開いてください。
<form>タグの中の<input>タグおよび<textarea>タグを編集していきます。
<form method="post" action="#" th:action="@{/inquiry/confirm}" th:object="${inquiryForm}">
<label for="name">お名前:</label>
<input id="name" name="name" type="text"><br>
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
<label for="email">メール:</label>
<input id="email" name="email" type="text"><br>
<div th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
<label for="contents">詳細 :</label>
<textarea name="contents" id="contents" rows="3" cols="40"></textarea><br>
<div th:if="${#fields.hasErrors('contents')}" th:errors="*{contents}"></div>
<input type="submit" value="確認ページへ">
</form>
<form method="post" action="#" th:action="@{/inquiry/confirm}" th:object="${inquiryForm}">
<label for="name">お名前:</label>
<input th:value="*{name}" id="name" name="name" type="text"><br>
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
<label for="email">メール:</label>
<input th:value="*{email}" id="email" name="email" type="text"><br>
<div th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
<label for="contents">詳細 :</label>
<textarea th:field="*{contents}" name="contents" id="contents" rows="3" cols="40"></textarea><br>
<div th:if="${#fields.hasErrors('contents')}" th:errors="*{contents}"></div>
<input type="submit" value="確認ページへ">
</form>
こちらはまず、<form>タグのth:object属性に「”${inquiryForm}”」が指定されています。
こうしておくことで、この<form>タグの範囲内で「”*{フィールド名}”」と記述するだけで簡単にFormオブジェクトのフィールドにアクセスするできるようになる他、バリデーションによるエラーメッセージを出力したり、「戻る」ボタンを押したりした際に元の入力値を再び反映させるといったことが可能となります。
なお、th:object属性に指定する値は、”クラス名の頭文字を小文字にしたもの”です。
それでは続いて、「戻る」ボタンを押して戻ってきた際の処理を追加します。
「戻る」ボタンを選択し入力画面に戻ってくる際には、もともとの入力値がPOSTで送られてきますので、<input>タグではth:value属性、<textarea>タグではth:field属性へ「”*{フィールド名}”」と指定することで、データが存在する場合はあらかじめその値が入力欄に入力された状態にしています。
このように、フォームの中でFormオブジェクトのフィールドにアクセスする際は「”*{フィールド名}”」と記述するということを覚えておいてください。
ここまで記述できたら一旦ファイルを保存しておいてください。
2.Controllerクラスで確認処理を実装
では、次にフォームから送信ボタンを押した先の確認処理を実装していきます。
InquiryController.javaを開き、「@PostMapping(“/confirm”)」のアノテーションが付いたconfirm()メソッドを見ていきます。
@PostMapping("/confirm")
public String confirm(/*Add parameters. */) {
//hands-on
return "inquiry/confirm";
}
@PostMapping("/confirm")
public String confirm(@Validated InquiryForm inquiryForm,
BindingResult result,
Model model) {
if(result.hasErrors()) {
model.addAttribute("title", "Inquiry Form");
return "inquiry/form";
}
model.addAttribute("title", "確認ページ");
return "inquiry/confirm";
}
こちらまずは引数から記述していきます。コメントを削除し、まずは「@Validated」と記述してから、InquiryForm型のinquiryFormを指定します。ここで一旦Ctrl + Shift + O(オー)でインポートを行ってください。
このように「@Validated」アノテーションを引数に付与することで、Formクラスの各フィールドへ設定した「@NotNull」や「@Size」といったバリデーションを実行できます。
次に、バリデーションの結果を取得するための引数であるBindingResult型のresultを指定します。こちらもインポートを行う必要があります。
BindingResultはバリデーションを行った結果を保持するオブジェクトになります。
最後にModel型のmodelを指定し、引数の記述は以上です。
続いてメソッドのブロックには、バリデーションの結果によって分岐する処理を記述しています。まずは不要なコメント部分を削除して、if文から書いていきます。
BindingResultのhasErrors()メソッドを用いることでバリデーションの結果をboolean型で取得できますので、こちらをifの条件にそのまま渡します。hasErrors()メソッドはエラーが発生した場合にtrueを返すので、続くifのブロックにはエラーが発生した場合に行いたい処理を記述します。
ここではifのブロック内で「”inquiry/form”」をreturnすることで、エラーが発生した場合は確認ページではなく、再び入力ページに戻るようになっています。
その後if文を抜けた先で、バリデーションによってエラーが発見されなかった場合には「”inquiry/confirm”」をreturnすることで確認ページへと進むようになっています。
なお、エラーが発生した際はif文の中でreturnを行った時点で処理が終了するため、その後の記述をelse節にする必要はありません。
以上でコントローラーは完成ですので、保存をかけておいてください。
3.HTMLでエラーメッセージの実装
では、ここでバリデーションの結果再び入力欄に遷移した場合に、エラーメッセージを表示するという機能を確認していきます。
再びform.htmlを開いてください。
<label for="name">お名前:</label>
<input th:value="*{name}" id="name" name="name" type="text"><br>
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
<input>、<textarea>といった要素の後ろにそれぞれエラーメッセージを表示するための<div>要素が存在しています。
これらの<div>要素は、th:if属性に「”${#fields.hasErrors(‘フィールド名’)}”」を指定することで、該当するフィールドにエラーがある場合に表示されるようになっています。
この「#fields」というオブジェクトは自動的に作られるもので、コントローラー上で@Validatedとしたオブジェクトのフィールドに対するエラーの有無をHTML上で取得できます。
そして、さらに<div>要素にth:errorsという属性を設定し、<input>タグ等と同様「”*{フィールド名}”」を指定しています。こちらの値は、th:errors属性に指定した場合はフィールドの内容ではなく該当するフィールドに設定されたエラーメッセージが展開されます。
以上のようにすることで、バリデーションの結果エラーが見つかった場合にのみエラーメッセージが表示されるようになっています。
4.HTMLで確認画面を実装
それでは、ここまで確認できたら確認画面のほうをみていきましょう。
templates > inquiry > confirm.htmlを開いてください。
<body>
<h1 th:text="${title}">仮のタイトル</h1>
<p>入力内容をご確認ください</p>
<p th:text="${inquiryForm.name}"></p>
<div th:object="${inquiryForm}">
<p th:text="*{name}"></p>
<p th:text="*{email}"></p>
<p th:text="*{contents}"></p>
<form method="post" action="#" th:action="@{/inquiry/form}">
<input type="hidden" name="name" th:value="*{name}">
<input type="hidden" name="email" th:value="*{email}">
<input type="hidden" name="contents" th:value="*{contents}">
<input type="submit" value="戻る">
</form>
<form method="post" action="#" th:action="@{/inquiry/complete}">
<input type="hidden" name="name" th:value="*{name}">
<input type="hidden" name="email" th:value="*{email}">
<input type="hidden" name="contents" th:value="*{contents}">
<input type="submit" value="Complete">
</form>
</div>
</body>
まずは<div>要素に注目してください。
こちら重要ポイントです。th:object属性に「”${inquiryForm}”」が指定されています。このようにすることで、<div>タグの範囲内で「”*{フィールド名}”」と記述するだけでinquiryFormのフィールドを取得可能となっています。
続いて、確認のために<p>タグでそれぞれ入力値を表示して、その結果「戻る」あるいは「Complete」という2つの処理へ進むためのボタンが配置されています。
「戻る」および「Complete」の<form>はそれぞれPOST先のURL(th:action属性)とボタンに表示される文字列が違うのみで、入力値をhiddenタグで送信するという処理内容は全く同じとなっています。
今回は「戻る」ボタンの処理について確認していくので、POST先を見てみましょう。
URLは「/inquiry/form」なので、「@PostMapping(“/form”)」のメソッドをコントローラーから探します。
@PostMapping("/form")
public String formGoBack(InquiryForm inquiryForm, Model model) {
model.addAttribute("title", "InquiryForm");
return "inquiry/form";
}
formGoBack()というメソッドになっています。
こちらは再び入力画面を表示するためにちゃんと「”inquiry/form”」をreturnしています。
5.ブラウザからアクセスして確認
それでは、ここから検証ポイントに入ります。
動作の確認を行いますので、Springを一旦再起動させてください。
再起動できたら、ブラウザを開き「http://localhost:8080/inquiry/form」にアクセスします。
フォームが表示されました。
それでは、まずは空のまま「確認ページへ」のボタンを押してみましょう。
「nullは許可されていません」というエラーメッセージが表示されました。
続いて、バリデーションに引っかかるような内容を入力してみます。
名前欄には21文字以上の文字列を、メール欄にはメールアドレスの形式になっていないものを入力し、再び「確認ページへ」のボタンを押します。
すると、Formクラスでアノテーションにより設定されたエラーメッセージが表示されました。
それでは最後に正しい内容で入力していきましょう。
名前欄は20文字以下、メール欄は名前に「@example.com」といったドメインを付けておきます。詳細欄も適当に入力しておきましょう。
「確認ページへ」をクリックします。
確認ページへ進めました。
続いて「戻る」ボタンを押してみます。
再び入力欄に戻り、先程入力した値がきちんと保存されていることが確認できました。
以上でここまでの機能は完成です。
次の記事は完成処理とリダイレクトに関して確認していきましょう。
お疲れ様でした。
第3章 お問い合わせアプリ開発
まずはこれから作成していくフォームの構成を確認してから、
フォームの作成に必要なHTMLファイル、Formクラスの作成方法を見ていきましょう。
HTMLファイル、Formクラスの編集を行いながらフォームを完成させましょう。
フォームで入力したデータを次のページに渡す方法を学び、確認ページを作ります。
hiddenタグを用いた作成方法、バリデーションの行い方を学びましょう。
実際に確認ページの作成を行っていきましょう。
HTMLの編集、バリデーションを含めた確認処理の実装を行います。
リダイレクト、フラッシュスコープなどの完了処理を作っていきます。
それぞれの作成方法、リダイレクトの仕組みについても確認しておきましょう。
実際にControllerに追加記述をして、リダイレクト、フラッシュスコープの実装を行います。
HTMLとの対応も確認しましょう。