Spring Bootの入力値をどこで受けるかを解説する記事のアイキャッチ。若手エンジニアがJava道場風の学習空間でControllerの引数を学ぶイラスト。

Spring

Spring Bootの入力値はどこで受ける?@RequestParam・@PathVariable・@RequestBodyの使い分け

AIによる要約

Spring Bootの入力値は、URLの一部なら@PathVariable、クエリ文字列なら@RequestParam、JSONボディなら@RequestBody、HTMLフォームならFormクラスで受けるのが基本です。値がどこから来るかを見ると迷いにくくなります。

新人SE
新人SE
Controllerの引数にいろいろなアノテーションが出てきて、どれを使えばいいか分かりません。
ポンコツSE
ポンコツSE
まずは入力値がURL、クエリ、フォーム、JSONのどこにあるかを見ます。アノテーション名だけで覚えるより、HTTPリクエストのどの部分を読むかで整理しましょう。

Spring BootのControllerでは、リクエストから値を受け取る方法が複数あります。

現場のコードを読むと、@RequestParam@PathVariable@RequestBody@ModelAttributeやFormクラスが混ざって出てきます。ここで迷うと、Controllerの修正が怖くなります。

この記事のポイント

  • URLの一部は@PathVariableで受ける
  • クエリ文字列や単発のフォーム値は@RequestParamで受ける
  • JSONのリクエストボディは@RequestBodyで受ける
  • HTMLフォームの複数項目はFormクラスで受ける

まず入力値がどこにあるかを見る

Springのアノテーションを暗記しようとすると混乱します。先に見るべきなのは、入力値がHTTPリクエストのどこに入っているかです。

  • URLの一部: /users/1010
  • クエリ文字列: /users?keyword=tanakakeyword
  • HTMLフォーム: 画面の入力欄からPOSTされる値
  • JSONボディ: APIクライアントから送られるJSON

ここが分かると、どのアノテーションを使うかはかなり整理できます。

@PathVariableはURLの一部を受ける

@PathVariableは、URLのパスに含まれる値を受け取ります。詳細画面、編集画面、削除処理など、対象リソースをURLで表すときによく使います。

@GetMapping("/users/{userId}")
public String detail(@PathVariable Long userId, Model model) {
    UserDetail user = userService.findDetail(userId);
    model.addAttribute("user", user);
    return "users/detail";
}

この例では、/users/10 にアクセスすると userId10 が入ります。検索条件ではなく、対象そのものを表す値だと考えると分かりやすいです。

@RequestParamはクエリ文字列や単発の値を受ける

@RequestParamは、URLの後ろにつくクエリ文字列や、単発のフォーム値を受け取るときに使います。

@GetMapping("/users")
public String list(@RequestParam(required = false) String keyword,
                   @RequestParam(defaultValue = "1") int page,
                   Model model) {
    model.addAttribute("users", userService.search(keyword, page));
    return "users/list";
}

検索キーワードやページ番号のように、単体で意味が分かる値に向いています。ただし、条件が増えすぎるならFormクラス化を考えます。

@RequestBodyはJSONを受ける

@RequestBodyは、リクエストボディのJSONをJavaオブジェクトへ変換します。画面フォームではなく、REST APIでよく使われます。

@PostMapping("/api/users")
public ResponseEntity<Void> create(@RequestBody UserCreateRequest request) {
    userService.create(request);
    return ResponseEntity.ok().build();
}

この場合、クライアントはJSONを送ります。URLの後ろに値を付けるのではなく、リクエストの本文に入力値が入ります。

POST /api/users
Content-Type: application/json

{
  "name": "田中",
  "email": "tanaka@example.com"
}

HTMLフォームはFormクラスで受けることが多い

Thymeleafなどの画面フォームでは、Formクラスで受ける形がよく使われます。入力値が複数あり、エラー時に画面へ戻す必要があるからです。

@PostMapping("/users")
public String register(@Valid UserRegisterForm form,
                       BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "users/new";
    }
    userService.register(form);
    return "redirect:/users";
}

画面入力では、入力チェック、エラーメッセージ、再表示がセットになります。そのため、単発の@RequestParamよりFormクラスの方が扱いやすい場面が多いです。

使い分けを表で整理する

URLの一部           -> @PathVariable
クエリ文字列         -> @RequestParam
HTMLフォームの複数項目 -> Formクラス
JSONボディ           -> @RequestBody

現場で迷ったら、この表に戻れば十分です。難しい理屈より、値がどこから来るかを先に確認しましょう。

現場でよくある間違い

注意点

  • JSONを@RequestParamで受けようとして値が入らない
  • URLのIDを@RequestParamで受けて設計意図が読みにくくなる
  • 登録フォームを大量の@RequestParamで受けてしまう
  • @RequestBodyにHTMLフォームの送信値が入ると思い込む

この記事とあわせて読みたい

まとめ

Spring Bootの入力値の受け取り方は、アノテーション名から覚えるより、リクエストのどこに値があるかで整理すると迷いにくいです。

URLの一部なら@PathVariable、クエリなら@RequestParam、JSONなら@RequestBody、画面フォームならFormクラス。この基本を押さえるだけで、現場コードはかなり読みやすくなります。

-Spring
-, , , ,