AIによる要約
@RequestParamは単発の値を受け取るときに便利です。一方、Formクラスは画面入力や検索条件のように複数項目を1つの入力として扱いたいときに向いています。迷ったら、値が業務上ひとまとまりかどうかで判断します。


Spring BootのControllerを書き始めると、@RequestParamで値を受け取る書き方と、Formクラスでまとめて受け取る書き方の両方が出てきます。
注文一覧にキーワードと状態を足す場合は @RequestParam で十分です。開始日と終了日が加わり、入力値とエラーを同じ検索画面に返すなら、GETでも @ModelAttribute でFormにまとめる理由があります。
この記事のポイント
@RequestParamは単発の値や簡単な検索条件に向く- Formクラスは複数項目を1つの入力として扱いたいときに向く
- 登録・更新フォームではFormクラスを使うとバリデーションしやすい
- 項目を一緒に検証する場合やエラー時に入力を残す場合はFormクラスを検討する
実行用サンプル
独立した2つの検索条件と、日付のエラーを画面に戻すFormを同じ注文データで比較します。 ソース全文、JUnitの検証コード、pom.xml、READMEを収録しています。JDK 17とMaven 3.9系で mvn test を実行します。Spring Boot 3.5.16のサンプルです。
@RequestParamは単発の値を受けるときに使いやすい
@RequestParamは、リクエストパラメータをControllerの引数で直接受け取るためのアノテーションです。検索キーワード、ページ番号、並び順など、単発で意味が分かる値に向いています。
OrderSearchController.java の抜粋。キーワードと状態だけを受け取るGET
@GetMapping("/demo/orders/simple")
@ResponseBody
public List<Order> simple(@RequestParam(name = "keyword", required = false) String keyword,
@RequestParam(name = "status", required = false) String status) {
return orderService.search(new OrderSearchCondition(keyword, status, null, null, null, 1));
}GET /demo/orders/simple?keyword=Coffee&status=CLOSED は注文3を返します。各項目は独立した絞り込み条件なので、2つの引数で受け取れば何を検索するか読めます。
Formクラスは入力項目をひとまとまりにする
一方で、入力項目が複数あり、それらを合わせて1つの検索条件や登録内容として扱うなら、Formクラスにまとめる方が自然です。
OrderSearchController.java の抜粋。6項目と入力エラーを受け取る検索GET
@GetMapping("/orders")
public String list(@Valid @ModelAttribute("searchForm") OrderSearchForm form,
BindingResult errors, Model model) {
if (!errors.hasFieldErrors("fromDate") && !errors.hasFieldErrors("toDate")
&& form.getFromDate() != null && form.getToDate() != null
&& form.getFromDate().isAfter(form.getToDate())) {
errors.rejectValue("toDate", "date.range", "終了日は開始日以降にしてください");
}
if (errors.hasErrors()) {
return "orders/list";
}
model.addAttribute("orders", orderService.search(form.toCondition()));
return "orders/list";
}GET /orders?keyword=Coffee&fromDate=bad では、Spring MVCが fromDate を LocalDate に変換できず、BindingResult にエラーを入れます。この例では検索を行わず、入力した Coffee と bad、日付のメッセージを検索画面に表示します。
登録画面ではFormクラスが基本になりやすい
登録や更新の画面では、名前、メールアドレス、電話番号、住所など、複数の値がセットで扱われます。この場合はFormクラスにまとめると、入力チェックも書きやすくなります。
登録では、たとえば名前とメールアドレスをフォームへまとめ、@NotBlank と @Email をフィールドに付けます。保存処理の前に BindingResult を見て、エラーなら入力画面を返します。このサンプルで実行するのは注文検索のGETです。
この形にしておくと、Controllerは「入力を受け取る」「エラーなら戻す」「問題なければServiceへ渡す」という役割に集中できます。
@RequestParamだけで頑張ると何が困るか
@RequestParamを大量に並べると、メソッドの引数が長くなり、何の画面入力なのか分かりにくくなります。レビューでは、まずここを見られます。
名前とメールアドレスをそれぞれ @RequestParam で受ける設計では、名前の空欄、メール形式、入力画面に戻すときの値をどこで扱うかも決めます。登録フォームにまとめると、入力の定義と検証をフィールド単位で見直せます。
判断が変わるのは引数が何個になったかより、入力を一緒に検証し、エラー時にそのまま表示する必要があるかです。2項目でも開始日と終了日なら、日付範囲としてFormを検討できます。
判断基準は、値が単発か、画面入力としてひとまとまりかです。単発なら@RequestParam、まとまりならFormクラスを検討します。
現場レビューではどう見られるか
レビューでは「日付の前後関係をどこで検証するか」「形式エラーのとき、入力した日付を画面に残せるか」まで確認します。
レビューで大事なのは、Formクラスを使っているかどうか自体ではありません。入力値のまとまりがコード上で表現されているか、変更しやすいか、入力チェックを置きやすいかです。
サンプルは、個別に受けた2項目で注文3を絞り込めることと、Formの型変換に失敗しても入力が画面に残ることをMockMvcで確かめています。両記事で使うサンプル全体の実行結果は以下です。
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0レビュー前のセルフチェック
確認リスト
- キーワードと状態のように、個別の引数で意図が伝わるか
- 登録・更新画面では入力値と項目ごとのエラーを同時に返せるか
- 開始日と終了日のように、合わせて検証する条件があるか
- Formクラスに画面入力以外の責務を持たせていないか
この記事とあわせて読みたい
まとめ
@RequestParamとFormクラスは、どちらが上位という関係ではありません。単発の値を受けるなら@RequestParam、複数項目を1つの入力として扱うならFormクラスが向いています。
新人のうちは、Controllerの引数が増えたときに一度立ち止まるだけでも十分です。入力値のまとまりを意識できると、Spring MVCのコードはかなり読みやすくなります。



