【Java】Spring Boot 2.3.1でバリデーションをつけていく記事


はじめに

こんにちは!ゼロからJavaであそぶシリーズ第4弾です。いま名前つけました。

前回までの記事はこちら↓

  1. macでSTSの環境構築
  2. Spring BootでHelloWorld
  3. Spring Bootでエコーアプリケーション作成

今回は、前回作ったエコーアプリケーションに、バリデーションをつけていこうと思います。

現状、文字列も数字も環境依存文字も、何文字でも入れられてしまうガバ状態なので、怪文書を送ると以下のように表示崩れが発生してしまいます。

怖い。
名前にハテナが並んでると不穏な雰囲気になっちゃいますね。文字化けかな?
ゼロが画面幅を突き破ってしまっているのもなんか嫌ですね。

そこで今回は、何かのサービスのユーザーネームっぽく、以下の要件でバリデートするようにしちゃおうと思います。エラーの場合同じ画面内でエラーメッセージを出すイメージです。

  • 使用可能文字種:半角英数のみ
  • 文字数制限: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で正規表現のパターン文字列を指定できます。今回は半角英数のみを許容する正規表現を使用しました
EchoForm.java
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 ${ユーザーネーム}」の画面に行ってほしくないため、同じページをリターンするように変更しています。
EchoController.java
@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 />が入る仕様です。ありがたい。

index.html
<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を新規作成します。

中身は、使用したアノテーションのメッセージを書き換えるだけのシンプルな実装です。

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でないためマルチバイト文字で文字化けしてしまうようです

ValidationMessages.properties
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系だと怪しいので、適宜調べてみてください。

お読みいただき、ありがとうございました!


  1. nullのみチェックするには@NotNullを使用します 

  2. こちらのページの実装を参考にしました。