URLやAjaxで画面の変更ををサーバに送信する際、dataに配列形式のパラメータを追加してJavaのFormクラスでList型として受け取る方法を紹介します。
画面のテーブルにリストを表示し、データを編集した際などに利用したかったのですが方法がわからず、Google検索では上位に表示されずとても困りました。
あまり利用されていないのでしょうか。
一番下で実装例で紹介しているソースコードの、Ajaxの送信や画面の要素の取得にはjQueryを利用しています。
やりたいこと
例えば画面から配列構造のパラメータを送り、以下のような構造のFormクラスでList型のデータとして受け取りたい場合についてです。
/** 管理番号 */
public int controlNo;
/** ユーザリスト */
public List<UserInfoListDto> userInfoList; // ←これをパラメータから受け取りたい
/** ユーザID */
public String userId;
/** 氏名 */
public String name;
まず、URLを直接たたく場合(URLのクエリに指定する場合や試験など)では以下の形式で送信します。
~~/update?controlNo=1&userInfoList[0].userId=U001&userInfoList[0].name=太郎&userInfoList[1].userId=U002&userInfoList[1].name=花子
Ajaxの場合、以下の連想配列のオブジェクトをAjaxのdataとして指定することで、目的を達成することができます。
var sendList = {
"controlNo": 1,
"userInfoList[0].userId": "U001",
"userInfoList[0].name": "太郎",
"userInfoList[1].userId": "U002",
"userInfoList[1].name": "花子"
}
ポイントは、配列のkeyが”userInfoList[0].userId”のように全て文字列となっていることです。
リストということで、userInfoListの多次元配列にするのではないということに注意してください。
JavaScliptの実装
デーブルからデータを取得し、Ajaxで送る実装例です。
上に記したFormクラスの例に対応しています。
※サンプルのためHTMLは極力シンプルにしていますが、実際はtdタグの中にinputタグやselectタグなんかを置き、内容を編集したりして使うと思います。
ユーザID | 氏名 |
---|---|
U001 | 太郎 |
U002 | 花子 |
<label>管理番号:<input type="number" id="controlNo" value="1"></label>
<table id="userInfoTable">
<thead>
<tr>
<th>ID</th>
<th>氏名</th>
</tr>
</thead>
<tbody>
<tr>
<td class="userId">U001</td>
<td class="name">太郎</td>
</tr>
<tr>
<td class="userId">U002</td>
<td class="name">花子</td>
</tr>
</tbody>
</table>
<button id="submitButton">送信</button>
$("#submitButton").on("click", function(){
// サーバに送る連想配列
var sendList = {};
sendList["controlNo"] = $("#controlNo").val();
// ループ処理でテーブルからデータを取得し、sendListに格納
var tableData = $("#userInfoTable tbody tr");
tableData.each(function(i){
var $elm = $(this);
sendList["userInfoList[" + i + "].userId"] = $elm.find(".userId").text();
sendList["userInfoList[" + i + "].name"] = $elm.find(".name").text();
});
// Ajax通信でデータをサーバに送信する
$.ajax({
type : "POST",
url : "/update",
dataType : "json",
data : sendList,
timeout: 10000
}).done(function(resultData) {
// Ajax通信成功時の処理
}).fail(function(jqXHR, textStatus, errorThrown){
// Ajax通信失敗時の処理
});
});
事前知識として持っていない場合、ちょっと特殊のためトライ&エラーでたどり着くことのできない解ですよね。
自分でも時々忘れてしまうので、備忘録もかねてこうして記しておこうと思います。
[追記]
Spring Boot の Controller でメソッドに @RequestBody がついている場合はこれでは送れませんでした。
どうやらクライアントからContent-Typeをapplication/jsonでリクエストする際は、データの組み立て部分を以下のようにするようです。
// サーバに送る連想配列
var sendList = {};
var sendObj = [];
sendList["controlNo"] = $("#controlNo").val();
// ループ処理でテーブルからデータを取得し、sendListに格納
var tableData = $('#userInfoTable tbody tr');
tableData.each(function(i){
var $elm = $(elm);
var userId = $elm.find(".userId").text();
var name = $elm.find(".userId").text();
var tableObj = {"userId" : userId, "name" : name};
sendObj.push(tableObj);
});
sendList["userInfoList"] = sendObj;
console.log(sendList);
// ↑ {controlNo: "1", userInfoList: Array(2)}
console.log(sendList.userInfoList);
// ↑ [{userId: "U001", name: "太郎"}, {userId: "U002", name: "花子"}]