AIによる要約
BindingResultは、@Validで検出した入力エラーをControllerで受け取るための引数です。重要なのは、@Validを付けたFormの直後に置くことです。順番を間違えると、期待通りにエラー処理できません。


Spring MVCで入力チェックを実装すると、@Validと一緒にBindingResultが出てきます。
新人のうちは、サンプルコードを写して動かすことはできても、なぜその順番で書くのかまでは分かりにくいです。この記事では、現場でよくレビューされる注意点に絞って整理します。
この記事のポイント
BindingResultは入力チェック結果を受け取るために使う@Validを付けたFormの直後に置く- エラーがあればServiceへ進まず入力画面に戻す
- REST APIでは例外ハンドリングに寄せる現場もある
BindingResultは入力チェック結果を受け取る
BindingResultは、FormクラスやRequest DTOに対する入力チェック結果をControllerで受け取るためのオブジェクトです。
@PostMapping("/users")
public String register(@Valid UserRegisterForm form,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "users/new";
}
userService.register(form);
return "redirect:/users";
}
bindingResult.hasErrors()がtrueなら、入力値に問題があります。この時点でServiceへ進まず、入力画面へ戻すのが基本です。
@Validの直後に置く理由
最重要ポイントは、BindingResultを@Valid対象の直後に置くことです。Springは、直前の検証対象に対するエラー結果としてBindingResultを扱います。
// OK
public String register(@Valid UserRegisterForm form,
BindingResult bindingResult,
Model model) {
// ...
}
この順番なら、UserRegisterFormの入力チェック結果をbindingResultで受け取れます。
順番を間違えるとどうなるか
よくあるミスは、@ValidとBindingResultの間に別の引数を挟むことです。
// NG
public String register(@Valid UserRegisterForm form,
Model model,
BindingResult bindingResult) {
// ...
}
この形は、入力エラーを画面で受け止める前に例外になったり、期待通りにエラーを扱えなかったりします。新人のレビューでかなり指摘されやすいポイントです。
エラーがあればServiceへ進まない
形式チェックでエラーがある状態でServiceを呼ぶと、Service側で想定外の値を扱うことになります。Controllerでは、エラーの有無を見て処理を止めます。
if (bindingResult.hasErrors()) {
return "users/new";
}
userService.register(form);
ここでやっているのは、業務処理ではありません。入力画面に戻すための制御です。Serviceの前に止めることで、Serviceは正常な形式の入力を前提に処理しやすくなります。
Thymeleafでエラーを表示する
画面側では、Formのフィールドに紐づくエラーを表示します。
<form th:action="@{/users}" th:object="${userRegisterForm}" method="post">
<input type="text" th:field="*{name}">
<p th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p>
<input type="email" th:field="*{email}">
<p th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p>
</form>
ControllerでBindingResultを受け、同じ画面に戻すと、Thymeleaf側でエラー内容を表示できます。
REST APIでは扱い方が変わることもある
画面フォームではBindingResultを使って入力画面に戻す実装が分かりやすいです。一方、REST APIでは、入力エラーを例外ハンドラでまとめてJSONレスポンスにする現場もあります。
@PostMapping("/api/users")
public ResponseEntity<Void> create(@RequestBody @Valid UserCreateRequest request) {
userService.create(request);
return ResponseEntity.ok().build();
}
APIでは画面へ戻すのではなく、400エラーとエラー内容を返す設計になります。プロジェクトのエラー処理方針に合わせましょう。
レビュー前のセルフチェック
確認リスト
BindingResultが@Valid対象の直後にあるか- エラー時にServiceを呼ばず、入力画面へ戻しているか
- 画面側でForm名とフィールド名が一致しているか
- APIと画面フォームでエラー処理を混同していないか
この記事とあわせて読みたい
- Spring Bootの@RequestParamとFormクラスの違いは?使い分けを解説
- Spring Bootの@Validと@Validatedの違いは?入力チェックの使い分け
- Spring Bootの入力チェックはどこでやる?ControllerとServiceの役割
まとめ
BindingResultは、@Validの結果をControllerで受け取るためのものです。最も大事なのは、@Validを付けた引数の直後に置くことです。
新人のうちは、順番、エラー時にServiceへ進まないこと、画面に戻したときにエラーが表示されること。この3点を押さえれば十分実務で使えます。
