Controller書くときに「どうやってデータ受け取ればいいんだっけ」と悩むのでまとめておく
いつも既存コードコピペじゃまずいので動作確認
SpringBoot3.3.1 で動作確認
前提として知っとくといいこと
「リクエストパラメータ」についておさらい
- GET
GET /book?id=2&title=sampleBook
-
?
の後ろに書いていくやつ - 「URLパラメータ」「クエリパラメータ」呼び方が安定してない気がする
- 基本的に参照型に使う
- データ長制限あり。長い文字列を扱うときは注意
- POST
POST /addBook id=2 author=John
- パラメータは「リクエストボディ」に記載
- curlコマンドの
-d
- curlコマンドの
- 更新系に使う
- 文字数制限なし
- Jsonとの相性がいい
- PUT,DELETE,その他もろもろは無視
実際のところ
- aタグ
- GET
- formタグによるsubmit
- GET,POST選べる
- POSTの場合は
Content-Type:application/x-www-form-urlencoded
→@RequestBody
では受け取れない
- JSのfetch関数
- GET,POST選べるけど
- jsonと連携できるこれが強い
fetch("/submit", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ username: "testuser", age: 25 })
});
- ちょっと古いがJqueryのajax関数
- GET,POST選べる
- POST,
data
を使う場合はContnet-Type:application/x-www-form-urlencoded
となる
$.ajax({
url: "/api/data",
method: "POST",
data: {
username: "John",
age: 30
}
});
結論
アノテーション | GET | POST | 説明 |
---|---|---|---|
@RequestParam |
○ | ○ | クエリパラメータ (?key=value ) やフォームの application/x-www-form-urlencoded を取得 |
@PathVariable |
○ | ○ | URL のパスパラメータ (/users/{id} ) を取得 |
@RequestBody |
× | ○ | JSON データをリクエストボディから取得 (application/json ) |
@ModelAttribute |
○ | ○ | フォームの application/x-www-form-urlencoded を DTO にマッピング |
- モダンなAPIはjsonでやりとりする(偏見)ので、
@RequestBody
が柔軟で優秀- しかし、GETで使えないというデメリットあり
- ただやっぱりJson連携は超絶便利なので実は全部POSTで受けるってのもありなのでは?
- フロントエンドなにもわからん
- GETの場合は随時適切なアノテーションを選択する
@RequestParam
@GetMapping("/book")
public String getBook(@RequestParam(name = "title", required = false) String title) {
// クエリパラメータから受け取ったデータを処理します
return "Book title: " + title;
}
URLパラメータを受け取るやつ
curlで叩くには
curl -X GET "http://localhost:8080/book?title=SampleBook"
(name = "title")
をつけないと以下エラー
java.lang.IllegalArgumentException: Name for argument of type [java.lang.String] not specified, and parameter name information not available via reflection. Ensure that the compiler uses the '-parameters flag
名前を明示的につけなくても問題ないんじゃなかった?と思ったけどSpring Framework 6.1以降は明示しないとダメらしい
https://qiita.com/mitecha/items/a95546652c13cf041f54
required
はデフォルトtrue
引数の型もいい感じにバインドしてくれる
@GetMapping("/book")
public String getBook(
@RequestParam(name="title", required = false) String title,
@RequestParam(name = "id") int id,
@RequestParam(name = "available") boolean available,
@RequestParam(name = "tags") List<String> tags,
@RequestParam(name = "publishedDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate publishedDate
) {
// クエリパラメータから受け取ったデータを処理します
return String.format(
"Book title: %s\nBook ID: %d\nAvailable: %b\nTags: %s\nPublished date: %s",
title, id, available, String.join(", ", tags), publishedDate
);
}
curl -X GET "http://localhost:8080/book?title=Sample+Book&id=1&available=true&tags=fiction&tags=adventure&publishedDate=2025-03-18"
Listは2回指定
日付型も柔軟に受け入れできる
当然カスタムクラスもいける
@GetMapping("/filter")
public String filterBooks(BookFilter filter) {
// カスタムクラスから受け取ったデータを処理します
return "Filtering books by genre: " + filter.getGenre() + ", author: " + filter.getAuthor();
}
//カスタムクラスの定義
public class BookFilter {
private String genre;
private String author;
// ゲッターとセッター
}
curl -X GET "http://localhost:8080/filter?genre=fiction&author=John+Doe"
やりたいことはだいたいできる
べんり
@PathVariable
@GetMapping("/book/{id}")
public String getBookById(@PathVariable(name = "id") int id) {
// idから本を取得する処理
return "Book id: " + id;
}
curl -X GET "http://localhost:8080/book/2"
パスパラメータを受け取りたいときに使う
性質上IDなどを受け取りがち
カスタムクラスと両立することもあるけど、基本はIDなどの識別子だけ@PathVariable
をつけるのが一般的か
@GetMapping("/book/details/{id}")
public String getBookDetails(@PathVariable(name = "id") int id, BookFilter filter) {
return String.format("Book ID: %d, Genre: %s, Author: %s", id, filter.getGenre(), filter.getAuthor());
}
curl -X GET "http://localhost:8080/book/details/123?genre=fiction&author=JohnDoe"
フィルター部分はクエリパラメータで指定する
@ModelAttribute
基本的に複雑なデータを受け取りたいときに使う
渡したいパラメータが多い!→クラス(Model)にまとめよう→ModelAttribute使おう
GET,POSTは問わない
// GET
@GetMapping("/book/model/details")
public String getBookDetailsByModelGet(@ModelAttribute BookFilter filter) {
// フィルターから本の詳細を取得する処理
return String.format("Get! Genre: %s, Author: %s", filter.getGenre(), filter.getAuthor());
}
// POST
@PostMapping("/book/model/details")
public String getBookDetailsByModelPost(@ModelAttribute BookFilter filter) {
// フィルターから本の詳細を取得する処理
return String.format("Post! Genre: %s, Author: %s", filter.getGenre(), filter.getAuthor());
}
//GETにリクエスト
curl -X GET "http://localhost:8080/book/model/details?genre=fiction&author=JohnDoe"
//POSTにリクエスト
curl -X POST -d "genre=fiction&author=JohnDoe" "http://localhost:8080/book/model/details"
@RequestBody
APIつくるときは基本これ
jsonを受け取るときはこれでいい
基本的には引数はカスタムクラス1つにピチッとまとめて使いがち
どうせjsonだしまとめたほうがええやんみたいな考え
@PostMapping("/books")
public String createBook(@RequestBody BookRequest bookRequest) {
// ここで受け取ったデータを処理
return String.format(
"Book received: %s\nBook ID: %d\nAvailable: %b\nTags: %s\nPublished date: %s",
bookRequest.getTitle(), bookRequest.getId(), bookRequest.isAvailable(), String.join(", ", bookRequest.getTags()), bookRequest.getPublishedDate()
);
}
curl -X POST http://localhost:8080/addBook -H "Content-Type: application/json" -d '{
"title": "New Book",
"available": true,
"tags": ["fiction", "adventure"],
"publishedDate": "2025-03-18"
}'
と思ったらこういうパターンもあった
@PathVariable
で変更値対象のidを取得
@RequestBody
で変更内容データを取得
@PostMapping("/updateBook/{id}")
public String updateBook(@PathVariable(name = "id") int id, @RequestBody BookRequest bookRequest) {
// ここで受け取ったデータを処理
return String.format(
"Book updated: %s\nAvailable: %b\nTags: %s\nPublished date: %s",
bookRequest.getTitle(), bookRequest.isAvailable(), String.join(", ", bookRequest.getTags()), bookRequest.getPublishedDate()
);
}
curl -X POST http://localhost:8080/updateBook/1 -H "Content-Type: application/json" -d '{
"title": "Updated Book",
"available": true,
"tags": ["fiction", "adventure"],
"publishedDate": "2025-03-18"
}'
参考
プロになるためのSpring入門――ゼロからの開発力養成講座
[改訂新版]プロになるためのWeb技術入門
Spring徹底入門 第2版 Spring FrameworkによるJavaアプリケーション開発