カテゴリ: Spring 更新日: 2026/01/14

Springで日付・数値・Enumを安全にバインド!Formatterで入力エラーを防ぐ方法

日付/数値/Enumのバインド:フォーマッタで入力エラーを減らす
日付/数値/Enumのバインド:フォーマッタで入力エラーを減らす

先生と生徒の会話形式で理解しよう

生徒

「Springで日付や数値を入力させたときに、うまくバインドされないことがあるんですが、どうすればいいですか?」

先生

「Springでは、Formatterを使うことで、日付や数値、Enumの入力フォーマットを自由に定義できて、バインド時のエラーも減らせますよ。」

生徒

「Enumも文字列で渡すとエラーになりますよね?そのあたりもFormatterで対応できるんですか?」

先生

「はい、Formatterを使えばEnumの日本語表示も含めて制御できます。それでは実際に、日付・数値・Enumのバインド方法を丁寧に見ていきましょう。」

1. Springのバインドとは?

1. Springのバインドとは?
1. Springのバインドとは?

Spring MVCでは、フォームから送信された文字列データをコントローラーの引数やフォームオブジェクトのフィールドにバインド(紐づけ)します。日付(LocalDateDate)、数値(IntegerBigDecimal)、列挙型(Enum)などにバインドするには、型に応じた変換が必要です。

2. なぜFormatterが必要なのか?

2. なぜFormatterが必要なのか?
2. なぜFormatterが必要なのか?

Springのデフォルト設定でもある程度はバインドできますが、以下のような課題があります:

  • 日付形式が「yyyy/MM/dd」だとエラーになる
  • 数値に「カンマ付き」や「全角数字」が混ざるとエラー
  • Enumに日本語や別名で表示したいが変換できない

こうした問題を解決するのがFormatterの役割です。独自のフォーマット定義で、入力エラーを防ぎ、ユーザーに優しい入力体験を提供できます。

3. 日付のFormatter実装例

3. 日付のFormatter実装例
3. 日付のFormatter実装例

まずは日付(LocalDate)を「yyyy/MM/dd」形式でバインドするFormatterを実装します。


public class LocalDateFormatter implements Formatter<LocalDate> {
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");

    @Override
    public LocalDate parse(String text, Locale locale) {
        return LocalDate.parse(text, formatter);
    }

    @Override
    public String print(LocalDate object, Locale locale) {
        return formatter.format(object);
    }
}

そしてWebMvcConfigurerで登録します。


@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new LocalDateFormatter());
    }
}

4. 数値のFormatter実装例

4. 数値のFormatter実装例
4. 数値のFormatter実装例

金額などでよく使われるBigDecimalに対して、「1,000.00」のようなフォーマットを扱えるFormatterを実装します。


public class BigDecimalFormatter implements Formatter<BigDecimal> {
    private final DecimalFormat decimalFormat = new DecimalFormat("#,##0.00");

    @Override
    public BigDecimal parse(String text, Locale locale) throws ParseException {
        Number number = decimalFormat.parse(text.replace(",", ""));
        return new BigDecimal(number.toString());
    }

    @Override
    public String print(BigDecimal object, Locale locale) {
        return decimalFormat.format(object);
    }
}

日付と同様にWebConfigに登録します。

5. EnumのFormatterで日本語表示

5. EnumのFormatterで日本語表示
5. EnumのFormatterで日本語表示

Enum型に対しても、Formatterで独自の変換が可能です。たとえば以下のようなGender列挙型を使ってみましょう。


public enum Gender {
    MALE("男性"), FEMALE("女性");

    private final String label;

    Gender(String label) {
        this.label = label;
    }

    public String getLabel() {
        return label;
    }

    public static Gender fromLabel(String label) {
        for (Gender g : values()) {
            if (g.label.equals(label)) return g;
        }
        throw new IllegalArgumentException("不正な値: " + label);
    }
}

そしてFormatterを定義します。


public class GenderFormatter implements Formatter<Gender> {
    @Override
    public Gender parse(String text, Locale locale) {
        return Gender.fromLabel(text);
    }

    @Override
    public String print(Gender object, Locale locale) {
        return object.getLabel();
    }
}

このFormatterを登録することで、フォームで「男性」「女性」と表示して、内部的にはGender.MALEなどにバインドできます。

6. HTMLフォームとの連携

6. HTMLフォームとの連携
6. HTMLフォームとの連携

Formatterを使えば、HTMLフォームのinputselectとも自然に連携できます。以下は日付と性別を入力するフォームの例です。


<form th:action="@{/submit}" th:object="${form}" method="post">
    <div class="mb-3">
        <label for="birthDate">生年月日</label>
        <input type="text" th:field="*{birthDate}" class="form-control" placeholder="2025/09/04">
        <div th:if="${#fields.hasErrors('birthDate')}" th:errors="*{birthDate}" class="text-danger"></div>
    </div>

    <div class="mb-3">
        <label for="amount">金額</label>
        <input type="text" th:field="*{amount}" class="form-control" placeholder="1,000.00">
        <div th:if="${#fields.hasErrors('amount')}" th:errors="*{amount}" class="text-danger"></div>
    </div>

    <div class="mb-3">
        <label for="gender">性別</label>
        <select th:field="*{gender}" class="form-select">
            <option value="">選択してください</option>
            <option th:value="男性">男性</option>
            <option th:value="女性">女性</option>
        </select>
        <div th:if="${#fields.hasErrors('gender')}" th:errors="*{gender}" class="text-danger"></div>
    </div>

    <button type="submit" class="btn btn-primary">送信</button>
</form>

7. 入力エラーの対策とバリデーション

7. 入力エラーの対策とバリデーション
7. 入力エラーの対策とバリデーション

Formatterを使うことで、日付や数値の形式に柔軟に対応できますが、それでも入力ミスは起こります。そのため、@ValidBindingResultを使って、ユーザーに丁寧なエラーメッセージを返すことが重要です。


@PostMapping("/submit")
public String handleSubmit(@Valid @ModelAttribute UserForm form, BindingResult result, Model model) {
    if (result.hasErrors()) {
        return "form-page";
    }
    // 正常処理
    return "success-page";
}

エラーメッセージは、バリデーションアノテーション(@NotNull@Pastなど)と組み合わせて使うと効果的です。

カテゴリの一覧へ
新着記事
JavaのLinkedHashMapを徹底解説!初心者でもわかる順序付きマップの基本と応用
Springで日付・数値・Enumを安全にバインド!Formatterで入力エラーを防ぐ方法
Javaのパッケージと修飾子を完全ガイド!初心者でもわかるimport文とアクセス制御
JavaのListインターフェースを完全ガイド!初心者でもわかるリスト操作
人気記事
No.1
Java&Spring記事人気No1
JavaのIntegerクラスの使い方を完全ガイド!初心者でもわかる整数操作
No.2
Java&Spring記事人気No2
Javaのラムダ式で配列を扱う!Arrays.streamの基本と注意点を初心者向けに解説
No.3
Java&Spring記事人気No3
JavaのRuntimeExceptionを完全解説!初心者でもわかるjava.langパッケージの基礎
No.4
Java&Spring記事人気No4
Spring BootとJavaの互換性一覧!3.5/3.4/3.3はJava 21・17に対応してる?
No.5
Java&Spring記事人気No5
Springの@Serviceアノテーションの使い方を徹底解説!初心者でもわかるSpring フレームワーク入門
No.6
Java&Spring記事人気No6
JavaのBigDecimalクラスcompareToメソッド完全ガイド!初心者でもわかる大小比較の基本
No.7
Java&Spring記事人気No7
JSPの基本タグ一覧と使い方まとめ!実務で使えるタグを紹介
No.8
Java&Spring記事人気No8
Thymeleaf(タイムリーフ)入門!初心者でもわかるSpring Bootとテンプレートエンジンの使い方