#16 Spring バリデーションのエラーメッセージの変更

# #16 Spring バリデーションのエラーメッセージの変更
今回はバリデーションにより発生するエラーメッセージを自分で作成したエラーメッセージに変更していきます。

# 前提条件
この記事はSpringの最低限の知識が必要になります。
また、なるべく分かりやすく書くつもりですが、この記事の目的は自分の勉強のアウトプットであるため、所々説明は省略します。

# 前回まで
Formクラスにバリデーション用のアノテーションを付与し、バリデーションによる入力チェックを行いました。

https://qiita.com/Jackoguro/items/f5a958dd03cf4f23562f

# 構築環境
1. 各バージョン
Spring Boot ver 2.7.5
jquery ver 3.6.1
bootstrap ver 5.2.2
webjars-locator ver 0.46

2. 依存関係
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/a3670e62-9faa-aef0-9b09-06a9782c2234.png)

# 成果物
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/d76016ef-6f4a-a8b0-dcd6-b064ad1e0a43.png)

# 今回行うこと
今回は以下の流れに沿って進めていきます。
1. SignupForm.javaの内容を変更
1. ValidationMessages.propertiesにエラーメッセージ内容を追加
1. messages.propertiesの内容を変更
1. 注意事項

## 1. SignupForm.javaの内容を変更
アノテーションの内容を変更しました。
```java:SignupForm.java

// 省略

@Data
public class SignupForm {
	
	@NotBlank
	@Email
	private String userId;
	
	private Integer phoneNumber;
	
	private Integer postal1;

	private Integer postal2;
	
	private String address;
	
	@NotBlank
	private String userName;
	
	@NotBlank
	@Pattern(regexp="^(?=.*[A-Z])[a-zA-Z0-9_]+$") // 少なくとも大文字が1つ含まれる
	@Length(min=8, max=24)
	private String password;
	
	@DateTimeFormat(iso=DateTimeFormat.ISO.DATE)
	@Past // 過去の日付
	private Date birthday1;
	
	@DateTimeFormat(pattern="yyyy/MM/dd")
	private Date birthday2;
	
	@Min(5)
	@Max(100)
	private Integer age;
	
	private MultipartFile accountIcon;
	
	private Integer gender;
}
```

## 2. ValidationMessages.propertiesにエラーメッセージ内容を追加
以前作成したValidationMessages.propertiesに追加でエラーメッセージを記述します。
今回は記述を省略しますが、ValidationMessages_en.propertiesも同様に行います。
```properties:ValidationMessages.properties
# ========================
# バインドエラーメッセージ
# ========================

# パターン1
typeMismatch.signupForm.age=数値を入力してください
typeMismatch.signupForm.birthday2=yyyy/MM/dd形式で入力してください

# 省略

# ========================
# バリデーションエラーメッセージ
# ========================

NotBlank={0}は入力必須です
EMail={0}はメールアドレス形式で入力してください
Pattern={0}は1文字以上大文字を含む半角英数字で入力してください
Length={0}は{2}文字以上{1}文字以下の範囲で入力してください
Max={0}は{1}歳以下でなければなりません
Min={0}は{1}歳以上で無ければなりません
```
``=``の左側に``SignupForm.java``で使用したバリデーション用のアノテーションを記述します。
``=``の右側にはエラーメッセージの内容を記述します。
``{0}``にはフィールド名が入ります。

例えば、下記のように設定されている項目``userId``の入力フォームに何も入力しなかった場合、``{0}=userId``となるエラーメッセージが出力されます。
```java:SignupForm.java
	@NotBlank
	@Email
	private String userId;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/fe7ef214-0a15-ec96-4f5c-607913465956.png)

また、``{0}``以降の数字には、そのアノテーション内で設定した属性値を入れることができます。
例えば、``@Length(min=8, max=24)``のアノテーションが付与されていた場合、``{1}=24(max)``、``{2}=8(min)``となります。
``Length={0}は{2}文字以上{1}文字以下の範囲で入力してください``のようなエラーメッセージを記述した場合、チェックに引っかかると以下の画像のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/f80e3bea-e1bb-fafa-5405-63311d00b329.png)

``{1}``、``{2}``などの順番は属性名の **名前の順(昇順)** で決定されます。
今回の場合、``min``と``max``では``max``の方が早いので``{1}``は``ma``になります。

## 3. messages.propertiesの内容を変更
現状のエラーメッセージはフィールド名がそのまま表示されてしまっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/1c35817c-dc85-ed77-27d3-497ecdfe002e.png)

messages.propertiesで記述した内容をSignupFormに記述した項目名と一致するよう変更します。
```properties:messages.properties
# 共通部分
login = ログイン
userId = ユーザーID
password = パスワード

# ログイン画面
toSignup = 新規登録はこちらから

# 新規登録画面
usreRegistration = ユーザー登録
phoneNumber = 電話番号
postalNumber = 郵便番号
address = 住所
userName = ユーザー名
birthday = 誕生日
age = 年齢
accountIcon = アカウントアイコン(任意)
gender = 性別
male = 男性
female = 女性
```
変更する部分はバリデーション用のアノテーションを付与している項目だけで良いのですが見栄えの良さを取って上記のようにしました。
また、今回は記述を省略していますが、画面上(signup.html、login.html)で関連する部分も編集してあります。

:::note
messages.propertiesとFormクラスの項目名は一致させた方が良い
:::

以上の編集を行うと、下記のようにエラーメッセージがmessages.propertiesで記述した項目名として出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/e911dfbc-c202-0ce8-619f-a7893aeef7c9.png)

## 4. 注意事項
messages.propertiesにバリデーション用のアノテーションを記述するときに注意することがあります。
例えばユーザーIDとパスワード両方に``@pattern``アノテーションを付与した際に、同じアノテーションでもその内容は違うことがあります。
```java:SignupForm.java
	@NotBlank(groups = ValidGroup1.class)
	@Pattern(regexp="^[a-zA-Z0-9_]+$", groups = ValidGroup2.class) // 半角英数字(大文字を含める必要はない)
	private String userName;
	
	@NotBlank(groups = ValidGroup1.class)
	@Pattern(regexp="^(?=.*[A-Z])[a-zA-Z0-9_]+$", groups = ValidGroup2.class) // 少なくとも大文字が1つ含まれる
	@Length(min=8, max=24 , groups = ValidGroup2.class)
	private String password;
```

```properties:ValidationMessages.properties
Pattern={0}は1文字以上大文字を含む半角英数字で入力してください
```
以下の画像のように``ValidationMessages.properties``で登録したメッセージが出てきてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/6dec35d6-7e16-f650-b6d1-088d28b47cf2.png)

**よって、同じアノテーションでも内容の違いから違うメッセージを表示させたい場合、個別にメッセージを登録してあげる必要があります。**

その場合、``messages.properties``の``@Pattern``を削除して以下のようにするのが良いと思います。
```java:SignupForm.java
	@NotBlank(groups = ValidGroup1.class)
	@Pattern(regexp="^[a-zA-Z0-9_]+$", message="{0}は半角英数字で入力してください") // 半角英数字(大文字を含める必要はない)
	private String userName;
	
	@NotBlank(groups = ValidGroup1.class)
	@Pattern(regexp="^(?=.*[A-Z])[a-zA-Z0-9_]+$", message="{0}は1文字以上大文字を含む半角英数字で入力してください") // 少なくとも大文字が1つ含まれる
	@Length(min=8, max=24 , groups = ValidGroup2.class)
	private String password;
```

# 最後に
以上で、エラーメッセージの変更は完了しました。
しかし、パスワードの項目を見るとエラーメッセージが複数出力されています。入力欄が空白の場合、``パスワードは入力必須です``以外のエラーメッセージは出力する必要はありません。
次回は、エラーメッセージの出力順を変更していきたいと思います。