前提として、フォームデータといっているのは Content-Type: application/x-www-form-encoded
で送信されるデータのことです。
Spring MVC のコントローラーで、ネストされたデータ構造を持つオブジェクトとして、フォームデータを受け取るとき、どのように送信すればよいか、というのが今回のテーマです。
環境
- Java 1.8.0_91
- Maven 3.3.9 (Maven wrapper)
- Spring Boot 1.4.0.RELEASE
$ ./mvnw -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T01:41:47+09:00)
Maven home: /Users/yo1000/.m2/wrapper/dists/apache-maven-3.3.9-bin/2609u9g41na2l7ogackmif6fj2/apache-maven-3.3.9
Java version: 1.8.0_91, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "10.11.5", arch: "x86_64", family: "mac"
ネストされたフォームデータ
今回扱うのはこんなデータ。
public class Receipt {
private long receiptId;
private String shopName;
private List<Item> items = new ArrayList<>();
// Getter, Setter
public static class Item {
private long itemId;
private String itemName;
private int price;
private int quantity;
// Getter, Setter
}
}
これをコントローラーで、以下のように受けたい場合を想定。@RestController
や、@RequestBody
は使用しないのが今回のポイント。(application/json
では受け取らない。)
@Controller
@RequestMapping("receipt")
public class ReceiptController {
private ReceiptService receiptService;
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void post(Receipt receipt) {
receiptService.create(receipt);
}
}
データの送信
以上のような場合に、どのようにデータを送信すればよいでしょうか。application/json
で受けるわけではないので、JSON で送信することもできません。
以下に実際の送信例を挙げます。
<form action="/receipt" method="post">
<input type="text" name="receiptId">
<input type="text" name="shopName">
<input type="text" name="items[0].itemId">
<input type="text" name="items[0].itemName">
<input type="text" name="items[0].price">
<input type="text" name="items[0].quantity">
<input type="text" name="items[1].itemId">
<input type="text" name="items[1].itemName">
<input type="text" name="items[1].price">
<input type="text" name="items[1].quantity">
..
</form>
このように、ネストされたフィールドへアクセスするのに必要なパスを、name
属性にガッツリ書いてあげないといけません。リストだと添え字の指定も必要なのでよりわかりづらい。
Javacript で jQuery などを使用している場合には、以下のように書くこともできます。
var receipt = {
receiptId: "1000",
shopName: "おみせ"
};
for(var i = 0; i < 5; i++) {
receipt['items[' + i + '].itemId'] = "200" + i; // 2000, 2001, ..
receipt['items[' + i + '].itemName'] = "しょうひん" + i; // しょうひん0, しょうひん1, ..
receipt['items[' + i + '].price'] = "50" + i; // 500, 501, ..
receipt['items[' + i + '].quantity'] = "1" + i; // 10, 11, ..
}
$.post({
url : "/receipt",
data : $.param(data),
processData : false
}).done(function (data, textStatus, jqXhr) {
// anything to do.
})
こちらの書き方もなかなかにアレですね。
と、こんな具合にすることで、Content-Type: application/x-www-form-encoded
で、Spring MVC のコントローラーにデータを渡せるようになります。
エンドポイントのコンテンツタイプなどにこだわって実装したい場合には、覚えておくと良いかもしれません。