やりたいこと(目的)
SpringのGETリクエスト(URLパラメータ)を複雑なオブジェクト(Bean)にマッピングする。
- ネスト構造
- リスト構造
結論
Mapping用のアノテーションを使用しない。
または
@ModelAttribute
を使用する。
※変数名とURLパラメータのキーを合わせる必要あり。
環境
Spring Boot:2.1.6
その他使用ライブラリ
lombok
テキトーな検証ソース
マッピング先
親オブジェクト
@Data
@ToString
public class ComplexBean {
private String hoge;
private ChildBean childBean;
private List<ItemBean> itemBeans;
}
ネスト用の子オブジェクト
@Data
@ToString
public class ChildBean {
private String piyo;
}
リスト用のオブジェクト
@Data
@ToString
public class ItemBean {
private String fuga;
}
※@Data
,@ToString
はlombokのアノテーション
@ToString
は検証用
コントローラ
@RestController
public class DemoRestController {
@GetMapping(value = "/param")
@ResponseBody
public String getParam(@RequestParam ComplexBean bean) {
System.out.println(bean.toString());
return bean.toString();
}
@GetMapping(value = "/model")
@ResponseBody
public String getModel(@ModelAttribute ComplexBean bean) {
System.out.println(bean.toString());
return bean.toString();
}
@GetMapping(value = "/direct")
@ResponseBody
public String getDirect(ComplexBean bean) {
System.out.println(bean.toString());
return bean.toString();
}
}
検証
Restlet Client - REST API Testingを用いて各エンドポイントにアクセス
検証するURLパラメータ
hoge=hoge&childBean.piyo=piyo&itemBeans[0].fuga=fuga0&itemBeans[2].fuga=fuga2
結果
@RequestParam
を使用する場合
(http://localhost:8080/param?hoge=hoge&childBean.piyo=piyo&itemBeans[0].fuga=fuga0&itemBeans[2].fuga=fuga2
)
マッピング情報が足りないのでパースできずエラーになる。
Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required ComplexBean parameter 'bean' is not present]
@ModelAttribute
を使用する場合
(http://localhost:8080/model?hoge=hoge&childBean.piyo=piyo&itemBeans[0].fuga=fuga0&itemBeans[2].fuga=fuga2
)
想定どおりマッピングされる。
アノテーションなしの場合
(http://localhost:8080/direct?hoge=hoge&childBean.piyo=piyo&itemBeans[0].fuga=fuga0&itemBeans[2].fuga=fuga2
)
想定どおりマッピングされる。
まとめ
以下の構造を持つURLパラメータでも
- ネスト構造
- リスト構造
Mapping用のアノテーションを使用しない。
または
@ModelAttribute
を使用する。
とすればマッピングできるがGETのリクエストでこんなオブジェクトにマッピングしなきゃいけなくなった時点で設計を見直そう。
なお、検証のように配列番号を飛ばした場合は飛ばされた枝番はnull
が設定される。(⇒空のオブジェクトにはならない)