Edited at

Spring MVC でネストされたフォームデータを受け渡しする

More than 1 year has passed since last update.

前提として、フォームデータといっているのは 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"


ネストされたフォームデータ

今回扱うのはこんなデータ。


Receipt.java

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 では受け取らない。)


ReceiptController.java

@Controller

@RequestMapping("receipt")
public class ReceiptController {
private ReceiptService receiptService;

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void post(Receipt receipt) {
receiptService.create(receipt);
}
}



データの送信

以上のような場合に、どのようにデータを送信すればよいでしょうか。application/json で受けるわけではないので、JSON で送信することもできません。

以下に実際の送信例を挙げます。


receipt.html

<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 などを使用している場合には、以下のように書くこともできます。


receipt.js

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 のコントローラーにデータを渡せるようになります。

エンドポイントのコンテンツタイプなどにこだわって実装したい場合には、覚えておくと良いかもしれません。