【Java・SpringBoot・Thymeleaf】日本語でエラーを表示（SpringBootアプリケーション実践編5）

ログインをして、ユーザー一覧を表示するアプリケーションを作成し、
Springでの開発について勉強していきます🌟
前回のエラーメッセージ実装に引き続き**バリデーションエラーメッセージを編集して日本語化**します

前回の記事🌟
[【Java・SpringBoot・Thymeleaf】バリデーションエラーメッセージを変更（SpringBootアプリケーション実践編4）](https://qiita.com/suema0331/items/dd91d21168080b747c8d)

#英語のメッセージを編集
* バリデーションのエラーメッセージを編集するには、`messages.properties`にエラーメッセージを設定
* **エラーメッセージ設定方法**
    * ①：**<アノテーション名>.<ModelAttributeのキー名>.<フィールド名>=<エラーメッセージ>**
    * ②：**<アノテーション名>.<フィールド名>=<エラーメッセージ>**
    * ③：**<アノテーション名>.<フィールドのデータ型>=<エラーメッセージ>**
    * ④：**<アノテーション名>=<エラーメッセージ>**
    * ⑤：**<独自のキー名>=<エラーメッセージ>**
        * ⑤：**フォームクラスのフィールドと、独自のキーを紐付けなければいけない**ので、フォームクラスの修正が必要
        * ①～④：**Springが自動でフォームクラスとメッセージの紐付け**を行ってくれる
* 以下でそれぞれ使い方を確認します🌟

##パターン①
* **`<アノテーション名>.<ModelAttribute名>.<フィールド名>=<エラーメッセージ>`**

###フィールド名の表示
* エラーメッセージの中にフィールド名を含めたい場合、**{0}**とメッセージ内に入力することで、フォームクラスのフィールド名を出してくれる
* フィールド名が`userId`の時は、`userIdを入力してください`と表示されます

###メッセージ変更
* 変更したいときは、**`<Model.Attribute名>.<フィールド名>=<日本語のフィールド名>`**で設定できる
    * **`signupForm.userId=ユーザーID`**の場合、エラーメッセージは
    * `ユーザーIDを入力してください`と表示される
    * (パターン③～⑤でも使える)

###パラメーターの表示
* エラーメッセージの中に、パラメーターを表示したいときは
    * ex: `パスワードは４桁以上、１００桁以下で入力してください`など
    * フィールド名{0}以降の数値を指定することで、**各パラメーターの値をメッセージに含める**ことができる
        * `Length.signupForm.password={0}は、{2}桁以上、{1}桁以下で入力してください`
        * SignupFormのpasswordフィールドに`@Length(min=4,max=100)`というアノテーションを設定
        * →maxが{1}、minが{2}に入る
* **パラメーターを修正してもメッセージに反映されるので、変更に強くなる！**


```messages.properties
#ユーザーID
signupForm.userId=ユーザーID
NotBlank.signupForm.userId={0}を入力してください
Email.signupForm.userId={0}にはメールアドレスを入力してください

#パスワード
signupForm.password=パスワード
NotBlank.signupForm.password={0}を入力してください
Length.signupForm.password={0}は、{2}桁以上、{1}桁以下で入力してください
Pattern.signupForm.password={0}は半角英数字で入力してください

#ユーザー名
signupForm.userName=ユーザー名
NotBlank.signupForm.userName={0}を入力してください

#誕生日
signupForm.birthday=誕生日
NotNull.signupForm.birthday={0}を入力してください

#年齢
signupForm.age=年齢
Min.signupForm.age={0}は{1}以上を入力してください
Max.signupForm.age={0}は{1}以下を入力してください

#結婚ステータス
AssertFalse.signupForm.marriage=未婚の方のみ登録できます

```

##パターン②
* **`<アノテーションクラス名>.<フィールド名>=<エラーメッセージ>`**
* **アノテーション名とフィールド名だけ**を書く
* 他のフォームクラスで同じフィールド名を使用した場合、同じメッセージが適用される

```messages.properties
#ユーザーID
userId=ユーザーID
NotBlank.userId={0}を入力してください(パターン2)
Email.userId={0}にはメールアドレスを入力してください(パターン2)

#パスワード
password=パスワード
NotBlank.password={0}を入力してください(パターン2)
Length.password={0}は、{2}桁以上、{1}桁以下で入力してください(パターン2)
Pattern.password={0}は半角英数字で入力してください(パターン2)

#ユーザー名
userName=ユーザー名
NotBlank.userName={0}を入力してください(パターン2)

#誕生日
birthday=誕生日
NotNull.birthday={0}を入力してください(パターン2)

#年齢
age=年齢
Min.age={0}は{1}以上を入力してください(パターン2)
Max.age={0}は{1}以下を入力してください(パターン2)

#結婚ステータス
AssertFalse.marriage=未婚の方のみ登録できます(パターン2)
```

##パターン③
* **`<アノテーション名>.<フィールドのデータ型>=<エラーメッセージ>`**
* **データ型に対してメッセージが紐付け**られます。

```messages.properties
#フィールド名
userId=ユーザーID
password=パスワード
userName=ユーザー名
birthday=誕生日
age=年齢

#バリデーションエラーメッセージ
NotBlank.java.lang.String={0}は必須入力です(パターン3)
Email.java.lang.String={0}はメールアドレス形式で入力してください(パターン3)
Length.java.lang.String={0}は、{2}桁以上、{1}桁以下で入力してください(パターン3)
Pattern.java.lang.String={0}は半角英数字で入力してください(パターン3)
NotBlank.java.lang.String={0}は必須入力です(パターン3)
NotNull.java.util.Date={0}を入力してください(パターン3)
Min.int={0}は{1}以上を入力してください(パターン3)
Max.int={0}は{1}以下を入力してください(パターン3)
AssertFalse.boolean=未婚の方のみ登録できます(パターン3)
```

##パターン④
* **`<アノテーション名>=<エラーメッセージ>`**
* **アノテーションに対してメッセージを紐付ける**

```messages.properties
#フィールド名
userId=ユーザーID
password=パスワード
userName=ユーザー名
birthday=誕生日
age=年齢

#バリデーションエラーメッセージ
NotBlank={0}は必須入力です(パターン4)
Email={0}はメールアドレス形式で入力してください(パターン4)
Length={0}は、{2}桁以上、{1}桁以下で入力してください(パターン4)
Pattern={0}は半角英数字で入力してください(パターン4)
NotBlank={0}は必須入力です(パターン4)
NotNull={0}は必須入力です(パターン4)
Min={0}は{1}以上を入力してください(パターン4)
Max={0}は{1}以下を入力してください(パターン4)
AssertFalse=falseのみ登録できます(パターン4)
```

##パターン⑤
* **`<独自のキー名>=<エラーメッセージ>`**
    * パターン①~④は、messages.properties編集のみでエラーメッセージを編集できたがパターン⑤の場合、コードを修正する
* **独自のキーを設定する場合、各アノテーションと、独自キーの紐付けが必要**になる
* アノテーションにmessage属性を付けると、**message.propertiesの独自キーと紐付けることができる**
    * `message="{<独自キー名>}"`
    * `@NotBlank(message = "{require_check}")`
    * {}を付けない場合、設定した文字列がエラーメッセージとして表示される
* 直接エラーメッセージを指定する場合は

```java
@NotBlank(message="パスワードを入力してください")
String password;
```


```SignupForm.java
package com.example.demo.login.domain.model;
import java.util.Date;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Data;

@Data
public class SignupForm {
    //入力形式、メールアドレス形式
    @NotBlank(message = "{require_check}")
    @Email(message = "{email_check}")
    private String userId; //ユーザーID

    //入力必須、長さ4-100桁まで、半角英数字のみ
    @NotBlank(message = "{require_check}")
    @Length(min= 4 ,max = 100, message = "{length_check}")
    @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "{pattern_check}")
    private String password; //パスワード

    //入力必須
    @NotBlank(message = "{require_check}")
    private String userName; //ユーザー名

    //入力必須
    @NotNull(message = "{require_check}")
    @DateTimeFormat(pattern = "yyyy/MM/dd")
    private Date birthday; //誕生日

    //値は20-100
    @Min(value=20, message = "{min_check}")
    @Max(value=100, message = "{max_check}")
    private int age; //年齢

    //falseのみ可能
    @AssertFalse(message = "{false_check}")
    private boolean marriage; //結婚ステータス

}
```

* 独自キーを使う場合は`ValidationMessages.properties`というファイルにメッセージを書く必要があるが、以下のmessages.propertiesファイルでも独自キーを使えるように設定する
* 独自キーを使う場合、**デフォルトのままでは日本語を使うと文字化け**するため、文字コードの設定も必要

##messages.propertiesを編集
* ユーザー登録用のフォームクラスに`@NotNull(message="{require_check}")`を追加した
* message="{<キー名>}"に当たる部分とメッセージを、以下のように設定
    * `require_check={0}は必須入力です(パターン5)`

```messages.properties
#フィールド名
userId=ユーザーID
password=パスワード
userName=ユーザー名
birthday=誕生日
age=年齢

#必須入力チェック
require_check={0}は必須入力です(パターン5)
#メールアドレス形式チェック
email_check={0}はメールアドレス形式で入力してください(パターン5)
#入力文字数チェック
length_check={0}は、{2}桁以上、{1}桁以下の桁数で入力してください(パターン5)
#フォーマットチェック
pattern_check={0}は半角英数字で入力してください(パターン5)
#下限値チェック
min_check={0}は{1}以上を入力してください(パターン5)
#上限値チェック
max_check={0}は{1}以下を入力してください(パターン5)
#ステータスチェック
false_check=falseの場合のみ登録できます(パターン5)
```

##WebConfig.javaを作成
* フォームクラスとメッセージの紐付けを行う

```WebConfig.java
package com.example.demo;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class WebConfig {

    @Bean
    public MessageSource messageSource() {

        ReloadableResourceBundleMessageSource bean = new ReloadableResourceBundleMessageSource();
        //メッセージのプロパティファイル名（デフォルト）を指定します
        //下記ではmessages.propertiesファイルがセットされます
        bean.setBasename("classpath:messages");
        //メッセージプロパティの文字コードを指定します
        bean.setDefaultEncoding("UTF-8");
        return bean;
    }

    @Bean
    public LocalValidatorFactoryBean localValidatorFactoryBean() {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(messageSource());
        return localValidatorFactoryBean;
    }
}


```

#画面確認！
* http://localhost:8080/login
* ユーザー登録画面で、何も入力せずにユーザー登録ボタンをクリック
* これで、**入力チェックのエラーメッセージを日本語化**できました〜〜〜
* エラーメッセージを一覧表示するより、どこが間違っているのかを個別に表示した方が分かりやすいので、次回エラーメッセージを個別に表示する実装をします^^

![日本語エラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/8a115ed8-3d85-18eb-0d72-013d55dfa027.png)

* （補足）プロパティファイルにメッセージを定義するのではなく、ソースコードにエラーメッセージを直接指定することもできます

```java
@NotBlank(message="必須入力です")
private String userId;
```