【Springフレームワーク】アノテーションを使ったバリデーションを実装しよう!

Webアプリケーションでなんらかの情報をDBに登録もしくは更新する際に、値のバリデーションはシステムを安全に運用していくためにも必須となってきます。

Webアプリケーションで使われるバリデーションの種類は決まっており、異なったWebアプリケーションでも同じようなバリデーションを行っています。

Springフレームワークを使えばこの定型的なバリデーションを簡単なアノテーションの追加だけで実装することができます。

(もちろんそのシステムに特化した相関チェックのような複雑なバリデーションも同じようなやり方で実装することができます。)

実装手順

おおまかな流れとしては下記の通りとなっています。

  1. hibernate-validatorの追加
  2. Entityにアノテーションの追加
  3. コントローラにエラーチェックの追加
  4. Viewにエラーメッセージ表示タグの追加

細かな流れについてそれぞれ見ていきましょう!

hibernate-validatorの追加

pom.xmlに依存関係を追加します。

hibernate-validatorのバージョンは、既に依存関係に追加してあるHibernateのバージョンと同じになるように"${hibernate.version}"としています。

        <!-- Hibernate / JPA -->
        <hibernate.version>5.4.3.Final</hibernate.version>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

Entityにアノテーションの追加

バリデーションのために追加したアノテーションは@NotEmpty(文字列データがNullもしくは空文字の場合にエラーとなります)@NotNull(日付データがNullの場合にエラーとなります)です。

それぞれmessageという引数にエラーとなった場合のメッセージを入力しています。

    @Column(name = "household_appliances_name")
    @NotEmpty(message="家電名を入力して下さい。")
    private String householdAppliancesName;

    @Column(name = "purchase_date")
    @NotNull(message="購入日時を選択して下さい。")
    private Date purchaseDate;

コントローラにエラーチェックの追加

保存処理に"@Validated"(バリデーションを行うことを宣言しています)"BindingResult result"(バリデーションの結果を受け取る変数を宣言しています)を追加しています。

上記2つを宣言することでフレームワークが自動的にバリデーション処理を行ってくれます。

バリデーションにエラーがあれば"result.hasErrors()"でtrueが返ってきます。

(1)バリデーションでエラーがあった場合は、登録画面を表示させます。

(2)バリデーションでエラーがなかった場合は、登録処理を行い一覧画面に遷移させます。

    @PostMapping("/save")
    public String save(
            @ModelAttribute("appliancesForm")
            @Validated
            HouseholdAppliances entity,
            BindingResult result) {
        if (result.hasErrors()) {
            //(1)バリデーションでエラーがあった場合
            return "displayNew";
        } else {
            //(2)バリデーションでエラーがなかった場合
            service.save(entity);
            return "redirect:/list";
        }
    }

Viewにエラーメッセージ表示タグの追加

    <ul>
        <li th:each="error:${#fields.detailedErrors()}"
            class="err" th:text="${error.message}" />
    </ul>

上記をエラーメッセージを表示させたい箇所に入力します。

エラーがあればerrorに情報が入るので、error.messageでエラーメッセージを表示させています。

eachを使うことで複数のerrorを表示させることができます。

errクラスを適用することで文字色を赤にしています。

<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>家電情報の新規登録</title>
    <style>
    table {
        border-collapse: collapse;
    }
    td {
        border: 1px solid gray;
        padding: 3px 8px;
    }
    .grayStyle {
        background: lightgray;
    }
    .err {
        color: red;
    }
    </style>
    <!-- jQuery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <!-- jQuery UI -->
    <!-- カレンダー表示するために使用 -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    <!-- jQueyr UI(日本語ライブラリ) -->
    <!-- カレンダーを日本語表示するために使用 -->
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
</head>
<body>
<h2>家電情報の新規登録</h2>

<p>
    <button id="btnBack">戻る</button>
</p>

<!-- 保存ボタンが押されると、appliancesFormをモデルとして /save アクションを呼び出す -->
<form th:action="@{/save}" method="post" th:object="${appliancesForm}">
    <p>
        <button id="btnSave" type="submit">保存</button>
    </p>
    <ul>
        <li th:each="error:${#fields.detailedErrors()}"
            class="err" th:text="${error.message}" />
    </ul>
    <table>
        <tr>
            <td>id</td>
            <td class="grayStyle">
                <!-- 新規登録の場合、idは自動採番されるのでその旨を表示 -->
                idは自動採番されます。
            </td>
        <tr>
            <td>家電名</td>
            <td><input id="householdAppliancesName" type="text" th:field="*{householdAppliancesName}"/></td>
        </tr>
        <tr>
            <td>購入日時</td>
            <td>
                <!-- 日付フォーマットが指定のものから崩れないようにカレンダーからのみ入力を許可する(←readonly) -->
                <input id="purchaseDate" type="text" th:field="*{purchaseDate}" readonly="readonly"/>
            </td>
        </tr>
    </table>
</form>

<script>
    $(function() {
        //日付ピッカーの設定
        $('#purchaseDate').datepicker({
            //日付フォーマットの指定
            dateFormat: 'yy/mm/dd',
            //年をリストから変更できるようにする
            changeYear: true,
            //月をリストから変更できるようにする
            changeMonth: true
        });

        //戻るボタン
        $('#btnBack').on('click', function() {
            location.href = '[[@{/list}]]';
        });
    });
</script>
</body>
</html>

実行してみる

  • 入力も選択もしないで保存ボタンを押下します。
  • エラーメッセージが表示されました。

おまけ

アノテーションによるバリデーションには、「javax.validation」と「Hibernate Validator」の2種類があります。

正確には「javax.validation」をより使いやすく拡張したものが「Hibernate Validator」になります。

「Hibernate Validator」では、"@NotEmpty"(nullもしくは空白だった場合エラー[今回使用])や"@Length"(文字列の長さ、文字数の範囲を指定できる)や"@Email"(電子メールアドレスかどうかチェック)なども使うことができます。

参考にした書籍

今回の内容は下記の書籍を参考にしました。




まとめ

アノテーションを追加することで実装できるバリデーションについて見てきましたが、いかがだったでしょうか?

同じようなバリデーションを複数の変数でしなければならない場合など、1つ1つバリデーションを実装していたら大変でミスもしてしまいそうです。

アノテーションによるバリデーションで実装すれば、簡単だしミスも少なくなりそうです!

みなさんもぜひ活用してみて下さいね。

最後までお読み頂きありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です