はじめに
こんにちは!ゼロからJavaであそぶシリーズ第4弾です。いま名前つけました。
前回までの記事はこちら↓
今回は、前回作ったエコーアプリケーションに、バリデーションをつけていこうと思います。
現状、文字列も数字も環境依存文字も、何文字でも入れられてしまうガバ状態なので、怪文書を送ると以下のように表示崩れが発生してしまいます。
怖い。
名前にハテナが並んでると不穏な雰囲気になっちゃいますね。文字化けかな?
ゼロが画面幅を突き破ってしまっているのもなんか嫌ですね。
そこで今回は、何かのサービスのユーザーネームっぽく、以下の要件でバリデートするようにしちゃおうと思います。エラーの場合同じ画面内でエラーメッセージを出すイメージです。
- 使用可能文字種:半角英数のみ
- 文字数制限:4文字以上
完成品は以下のような形です。
(背景色を目に優しい色に変えました)
使用環境とバージョン
- macOS Catalina
- jdk14.0.1
- JUnit5
- Maven 3.6.3_1
- STS 4.6.1
- Spring Boot 2.3.1
- spring-boot-starter-thymeleaf-2.3.1
フォームクラスにアノテーションでバリデーションを実装
フォームクラスに以下のアノテーションを追加しました。
-
@NotBlank
:nullまたは空文字でないこと1をチェックできます -
@Size
:属性minまたはmaxを使用して最小値・最大値を指定できます -
@Pattern
:属性値regexpで正規表現のパターン文字列を指定できます。今回は半角英数のみを許容する正規表現を使用しました
package com.example.form;
import java.io.Serializable;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotBlank;
public class EchoForm implements Serializable {
private static final long serialVersionUID = 1L;
@NotBlank
@Size(min = 4)
@Pattern(regexp = "[a-zA-Z0-9]*") //英数字であること
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
コントローラークラスにエラー時の分岐追加
変更を加えたechoメソッドのみ記述します。
変更点は以下2点です。
-
引数にBindingResultクラスを追加
しました。BindingResultには入力チェック結果が入っています。入力チェックの実行とBindingResultの生成はフレームワークが担ってくれる部分ですので、実装の必要はありません。(Spring徹底入門より) -
エラー時の分岐を追加
しました。
アノテーションによるチェックでエラーが発生した場合、「Hello ${ユーザーネーム}」の画面に行ってほしくないため、同じページをリターンするように変更しています。
@RequestMapping(value = "echo", method = RequestMethod.POST)
public String echo(@Validated EchoForm echoForm, BindingResult result, Model model) {
if (result.hasErrors() ) {
model.addAttribute("name", echoForm.getName());
return "index";
}
model.addAttribute("name", echoForm.getName());
return "echo";
}
index.htmlにエラー時のテキスト追加
エラーが出た際だけ、以下のように赤字のエラーメッセージを表示するようにしたいんですよね…
これ、Springならできちゃいます!
前回既にフォームオブジェクトをバインディングしているので、echoFormのエラー情報を取得してThymeleafにぶち込みHTMLを作ることができてしまうのです。
Springすごい。Thymeleafすごい。
form部分のみ記載します。
spanで囲っている場所で、オブジェクトがエラーである場合のみエラーメッセージを表示するようにしてあります2。具体的に言うと、th:errors属性にフォームオブジェクトのプロパティを設定しているため、指定したプロパティに対するエラーメッセージのみ表示されるようになっています。
エラーメッセージが複数ある場合は自動的に<br />
が入る仕様です。ありがたい。
<form th:object="${echoForm}" th:action="@{/echo}" method="POST">
<div>ユーザーネームを入れてください</div>
<div>(半角英数4文字以上)</div>
<div>
<input type="text" th:field="*{name}" />
<button>送信します</button>
</div>
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" style="color: red"></span>
</form>
エラー文言の日本語化
実は、ここまでの実装で実行すると、エラーメッセージがアノテーションのデフォルトメッセージ(英語)になってしまいますので、エラーが以下のようになってしまいます。
これはちょっと嫌ですね…上はまだオシャレなエラーメッセージ❤️で通せるかもですけど、sizeの数字に関してはユーザーから見たら意味不明ですものね…
ここは日本語のエラーメッセージに直しましょう!
Spring MVCによるBean Validationのエラーメッセージは、propertiesファイルに定義するのが望ましいようです。いくつか方法があるようですが、クラスパス直下にValidationMessages.propertiesを作成する方法が分かりやすかったので、そちらを採用しました。
resources配下にValidationMessages.propertiesを新規作成します。
中身は、使用したアノテーションのメッセージを書き換えるだけのシンプルな実装です。
org.hibernate.validator.constraints.NotBlank.message=入力必須です。
javax.validation.constraints.Size.message=4文字以上でなくてはいけません。
javax.validation.constraints.Pattern.message=半角英数のみ有効です。
ちなみに、上記をただValidationMessages.propertiesに貼り付けると、日本語入力してエンターを押すだけで自動的に以下のようになってしまいました…Spring Bootの標準BeanがUTF-8でないためマルチバイト文字で文字化けしてしまうようです。
org.hibernate.validator.constraints.NotBlank.message=\u5165\u529B\u5FC5\u9808\u3067\u3059\u3002
javax.validation.constraints.Size.message=4\u6587\u5B57\u4EE5\u4E0A\u3067\u306A\u304F\u3066\u306F\u3044\u3051\u307E\u305B\u3093\u3002
javax.validation.constraints.Pattern.message=\u534A\u89D2\u82F1\u6570\u306E\u307F\u6709\u52B9\u3067\u3059\u3002
こちらのQiitaのコメント欄でも言及があったのですが、自分もSpring 2系でJava11以上だからか、ファイルのプロパティでUTF-8にすればアプリケーションでも問題なく作動しました。
ファイルを右クリック > プロパティ > ResourceのText file encodingをデフォルトからUTF-8に変更するだけです。
これでファイルを保存しようとすると以下警告が出ますが、Save as UTF-8
で問題なく作動しました。
これで、以下のように日本語のメッセージになりました!
おわりに
今回はエラー時のテキスト追加部分のThymeleaf記法と、ValidationMessages.propertiesの日本語化でちょっと苦労しました!今回紹介した方法はSpring 1系だと怪しいので、適宜調べてみてください。
お読みいただき、ありがとうございました!