クエリパラメータの受け取り
このレッスンでは、@RequestParam でクエリパラメータを受け取り、必須かどうかと既定値を制御できるようになります。
クエリ文字列とは何か
URL のうち、疑問符から後ろの部分をクエリ文字列と呼びます。
プレーンテキスト
/users?page=2&size=10&sort=nameここでは page が 2、size が 10、sort が name です。key=value の組をアンパサンドでつないだだけの、とても素朴な形式です。パス変数が「どのリソースか」を決めるのに対し、クエリパラメータは「その集合をどう見せるか」を調整します。
@RequestParam で受け取る
Java
@GetMapping("/users")
public List<UserResponse> list(@RequestParam int page,
@RequestParam int size) { ... }@PathVariable と同じように、名前が一致するパラメータが引数に入ります。文字列から int への変換も Spring が行います。名前を変えたい場合は @RequestParam("page") int pageNumber のように書きます。
required と defaultValue
ここからが本題です。@RequestParam は既定で 必須 です。パラメータが無いリクエストが来ると、そのまま 400 になります。
Java
@RequestParam int page // 必須。無ければ 400
@RequestParam(required = false) Integer page // 任意。無ければ null
@RequestParam(defaultValue = "1") int page // 無ければ 1 が入る2 番目に注意が必要です。required = false にした場合、値が無いときに null が入るので、受け取る型は int ではなく Integer にしなければなりません。int のままだと null を代入できず落ちます。
3 番目の defaultValue を指定すると、required は自動的に false 扱いになります。既定値があるのだから必須にする意味がないからです。ページングのように「指定されなければ 1 ページ目の 20 件」と決まっているものは、この形が一番読みやすくなります。
| 書き方 | パラメータあり | パラメータなし |
|---|---|---|
@RequestParam int page | その値 | 400 エラー |
@RequestParam(required = false) Integer page | その値 | null |
@RequestParam(defaultValue = "20") int size | その値 | 20 |
既定値は文字列で書く
defaultValue = "20" のように、数値でも文字列で書きます。アノテーションの属性値として使えるのが定数式に限られるため、Spring は一度文字列で受け取ってから引数の型へ変換する、という設計になっています。defaultValue = 20 とは書けないので覚えておいてください。
パラメータをまとめて受け取る
パラメータが増えてきたら、専用のクラスにまとめる書き方もあります。
Java
@GetMapping("/users")
public List<UserResponse> list(UserSearchCondition condition) { ... }アノテーションを付けずにオブジェクトを引数に取ると、Spring は同名のプロパティへセッター経由で値を詰めてくれます。検索条件が 5 つも 6 つもあるような画面では、引数を並べるよりこちらの方が読みやすくなります。
演習で確かめます
Spring では、クエリ文字列を key と value に分解して型変換し、無ければ defaultValue を入れる、という一連の処理をフレームワークが引き受けています。今回はその中身を自分の手で書きます。page=2&size=10 のような文字列を解析し、page と size を取り出してください。指定が欠けていたときは page が 1、size が 20 という既定値を使います。
要件
- アンパサンドで区切り、さらに等号で key と value に分けて解析すること
- page が無ければ 1、size が無ければ 20 を使うこと
- 戻り値は入力の順番によらず page=2,size=10 の順に並べること
入出力例
parseQuery("page=2&size=10") → "page=2,size=10"
parseQuery("size=50&page=3") → "page=3,size=50"
parseQuery("page=5") → "page=5,size=20"
parseQuery("size=100") → "page=1,size=100"
parseQuery("") → "page=1,size=20"
parseQuery("sort=name&page=4") → "page=4,size=20"