はじめに (対象読者・この記事でわかること)
この記事は、Java と Spring MVC を使って Web アプリケーションを開発しているエンジニア(初心者から中級者)を対象としています。特に、フロントエンドで DataGrid(例:jQuery EasyUI、AG Grid、Vaadin Grid) を利用している際に、入力したデータがサーバ側のコントローラで取得できない、という問題に悩んでいる方に向けています。
本記事を読むことで、以下が実現できるようになります。
- DataGrid の行データが HTTP リクエストとして正しく送信される仕組みを理解する
- Spring MVC 側で
@ModelAttributeや@RequestBodyを正しく設定し、データを受け取る方法を習得する - よくあるバインドエラー(名前付きパラメータの不一致、型変換エラー、リクエストサイズ制限)を防止・対処できる
この問題は、フロントエンドとバックエンドのデータフォーマットが微妙にずれるだけで起きやすく、調査に時間がかかるケースが多いです。実務で即座に解決できるよう、具体的な手順とコード例を交えて解説します。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- Java の基本文法とオブジェクト指向の概念
- Spring Framework(特に Spring MVC)の基礎知識
- HTML と JavaScript(jQuery など)で簡単なフロントエンドが作れること
DataGridとSpring MVCのデータ受け取り概要
DataGrid は、テーブル形式で大量のデータを表示・編集できる UI コンポーネントです。ユーザーがセルを編集したとき、通常は JSON 配列 や Form データ としてサーバへ送信します。一方、Spring MVC はリクエストパラメータやリクエストボディを自動的に Java のオブジェクトに変換(バインド)する仕組みを提供します。
しかし、以下のようなミスマッチが起きると「データが受け取れない」状態になります。
| ミスマッチ例 | 具体例 |
|---|---|
| パラメータ名の不一致 | DataGrid が rows[] で送信するが、コントローラ側は items を期待 |
| 配列要素の型が合わない | JSON の数値が文字列として送られ、int フィールドにバインド失敗 |
| 期待するコンテンツタイプが違う | application/x-www-form-urlencoded を想定しているが、実際は application/json |
このセクションでは、まず DataGrid がどのようにデータを送信するか、次に Spring MVC のバインディング機構 を簡潔に整理し、問題の根本原因を把握します。
- DataGrid の送信形式
- FormData:
name=value&name=value...形式。複数行はrows[0].field=...のようにインデックス付きで展開。 -
JSON:
[{ "id":1, "name":"A" }, …]形式でapplication/jsonヘッダーと共に POST。 -
Spring MVC の受け取り方法
@ModelAttribute→ フォームデータ(URLエンコード)をオブジェクトへバインド。@RequestBody→ JSON や XML をHttpMessageConverterが変換。
この基本を理解した上で、次のセクションで「実際に DataGrid のデータを受け取る手順」を示します。
Spring MVCでDataGridの入力データを正しく受け取る手順
以下では、代表的な DataGrid ライブラリ jQuery EasyUI を例に、JSON 形式 でデータを送信し、Spring MVC 側で受け取るまでの全工程を解説します。使用する Java バージョンは Java 17、Spring Boot 3.x、Spring MVC の標準機能だけで完結します。
ステップ1 フロントエンド側の設定:JSON で送信する
EasyUI の DataGrid は toolbar の保存ボタンや onEndEdit イベントで編集済み行を取得できます。取得したデータを JSON.stringify で文字列化し、$.ajax の contentType: "application/json" と共に POST します。
Html<table id="dg" class="easyui-datagrid" style="width:700px;height:250px" data-options="singleSelect:true,toolbar:'#tb'"> <thead> <tr> <th data-options="field:'id',width:50">ID</th> <th data-options="field:'name',width:150,editor:'text'">名前</th> <th data-options="field:'price',width:80,editor:'numberbox'">価格</th> </tr> </thead> </table> <div id="tb"> <a href="javascript:void(0)" class="easyui-linkbutton" onclick="save()">保存</a> </div> <script> function save(){ const rows = $('#dg').datagrid('getChanges'); // 編集済み行だけ取得 $.ajax({ url: '/products/save', method: 'POST', data: JSON.stringify(rows), contentType: 'application/json', success: function(){ $.messager.alert('Info','保存しました','info'); } }); } </script>
ポイント:
getChanges()により 変更された行だけ を送信でき、通信量を削減。contentTypeを application/json に設定し、サーバ側が JSON と認識できるようにする。
ステップ2 コントローラ側の受け取り設定:@RequestBody と List
サーバ側では、受け取った JSON 配列を List<Product> に変換します。そのために、エンティティクラス Product と、コントローラメソッドを用意します。
Java// src/main/java/com/example/demo/model/Product.java package com.example.demo.model; public class Product { private Long id; private String name; private Integer price; // EasyUI の numberbox は数値として送られる // getter & setter (省略可) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } }
Java// src/main/java/com/example/demo/controller/ProductController.java package com.example.demo.controller; import com.example.demo.model.Product; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/products") public class ProductController { @PostMapping("/save") public ResponseEntity<String> saveProducts(@RequestBody List<Product> products) { // ここでビジネスロジック(バリデーション・DB保存等)を実行 products.forEach(p -> System.out.println("受信: " + p.getId() + ", " + p.getName() + ", " + p.getPrice())); return ResponseEntity.ok("保存完了"); } }
ポイント:
@RestControllerと@RequestBodyにより、JSON → Java オブジェクト の変換が自動で行われる。List<Product>と宣言することで、配列全体を受け取れる。- Jackson がデフォルトの
HttpMessageConverterとして機能し、型変換エラーが起きにくい。
ステップ3 カスタムバインディングが必要になるケース
(a) 日付や独自フォーマットのプロパティ
DataGrid が yyyy/MM/dd 形式の文字列を送るが、Java 側は LocalDate にしたい場合は @JsonFormat か ObjectMapper のカスタム設定が必要です。
Javapublic class Order { @JsonFormat(pattern = "yyyy/MM/dd") private LocalDate orderDate; // getter / setter }
(b) フィールド名がスネークケース(snake_case)とキャメルケース(camelCase)の不一致
Jackson の PropertyNamingStrategies.SNAKE_CASE を全体に設定すれば、order_date → orderDate が自動変換されます。
Java@Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); return mapper; }
ハマった点やエラー解決
| 発生したエラー | 原因 | 解決策 |
|---|---|---|
JSON parse error: Unexpected character ('[') at position 0 |
@ModelAttribute で受け取ろうとしていたが、リクエストは JSON だった |
メソッドシグネチャを @RequestBody List<Product> に変更 |
Failed to convert property value of type java.lang.String to required type java.lang.Integer |
フロント側が数値を文字列 "10" で送信した |
Jackson が自動的に変換できるが、ObjectMapper の DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT を有効化、またはフロントで数値型に変換 |
org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing |
contentType が application/json でない、もしくは data が空文字列 |
Ajax 呼び出しの contentType を必ず設定し、JSON.stringify([]) のように空配列でも送信する |
実際にハマったケース:リクエストサイズ制限
Spring Boot のデフォルト設定では、spring.mvc.dispatcherServlet.maxHttpHeaderSize が 8KB で、巨大な JSON 配列を送信すると Request Entity Too Large (413) が返ってきました。
対策:
Yaml# src/main/resources/application.yml server: max-http-header-size: 16KB tomcat: max-swallow-size: -1 # 無制限に設定(サイズが大きい場合のみ) spring: servlet: multipart: max-request-size: 10MB max-file-size: 10MB
完全な動作確認手順
- フロント側で DataGrid に数行データを入力し、保存ボタンをクリック。
- ブラウザの開発者ツールでリクエストペイロードが
application/jsonの配列であることを確認。 - Spring Boot アプリが起動していることを確認し、コンソールに
受信:と表示されるかチェック。 - Postman等で同様の JSON 配列を手動送信し、ステータス 200 とレスポンス
保存完了が返ることを確認。
これらの手順が全て成功すれば、DataGrid の入力データが Spring MVC に正しくバインドされ、ビジネスロジックで利用できる状態です。
まとめ
本記事では、DataGrid の入力データが Spring MVC で受け取れない 典型的な原因と、その解決手順を体系的に解説しました。
- フロント側は JSON 形式で送信し、
contentTypeを正しく設定することが基本 - サーバ側は
@RequestBody List<T>を使い、Jackson の自動変換を活用 - 型不一致や命名規則の違いは カスタムシリアライズ設定で対応し、エラーはログと例外メッセージで素早く切り分ける
これらを実践すれば、開発者は データ受け取りに関するトラブルシューティング時間を大幅に削減 でき、機能実装に集中できるようになります。次回は、WebSocket と DataGrid のリアルタイム同期について詳しく書く予定です。
参考資料
- Spring Boot 公式ドキュメント – Web MVC
- Jackson Databind – JSON 変換設定
- jQuery EasyUI – DataGrid API
- Spring MVC – @RequestBody と HttpMessageConverter の仕組み
