Spring BootのControllerで様々なjsonデータを受け取ってClassにマッピングする方法

Spring BootのControllerで文字列(String)型としてjsonデータを受け取って、Java Beansにマッピングする方法をご紹介します。

マッピングにはSpring Bootに同梱されているライブラリJacksonを使用します。

どんな時に使うか

先日の記事でHTMLテーブルのデータをjsonに変換、そのデータをControllerで受け取る方法をご紹介しました。このとき、テーブルの構造が決まっていればそれに合わせてJava Beansを作成してデータを受け取ることが出来ます。

しかし、送信されてくるHTMLテーブルデータの構造が動的な場合、上記の方法の方法だとその都度メソッドを用意しなければなりません。100通りのデータ構造がある場合に100個のメソッドを作ることになり、これは大変面倒です。

こんなときに、1度データを文字列(String)型で受け取ってしまってその後で処理する方法が便利です。

サンプル

ボタンをクリックするとテーブルデータをjsonデータに変換しControllerに文字列として送信するサンプルを作成します。

ソースコード

index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>JSON TEST</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/table-to-json@1.0.0/lib/jquery.tabletojson.min.js"></script>
<script src="js/script.js"></script>
</head>
<body>
  <form>
    <input type="button" id="toController" class="btn btn-primary" value="toController">
  </form>
  <table id="sampleTable" class="table">
    <thead>
      <tr>
        <th>#</th>
        <th>first</th>
        <th>last</th>
        <th>handle</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>Mark</td>
        <td>Otto</td>
        <td>@mdo</td>
      </tr>
      <tr>
        <td>2</td>
        <td>Jacob</td>
        <td>Thornton</td>
        <td>@fat</td>
      </tr>
      <tr>
        <td>3</td>
        <td>Larry</td>
        <td>the Bird</td>
        <td>@twitter</td>
      </tr>
    </tbody>
  </table>
</body>
</html>

script.js
$(function() {

  $("#toController").on("click", function() {
    var table = $('#sampleTable').tableToJSON({
      ignoreColumns : [ 0 ]
    });

    console.log(JSON.stringify(table));

    var request = $.ajax({
      url : "/",
      method : "POST",
      data : JSON.stringify(table),
      contentType : 'application/text'
    });

    request.done(function(data, textStatus, jqXHR) {
      console.log("done !");
    });

    request.fail(function(jqXHR, textStatus, errorThrown) {
      console.log("failed : " + textStatus);
    });

    request.always(function() {
      console.log("always");
    });

  });

});

JsonController.java
package com.demo.app.controller;

import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.servlet.ModelAndView;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
public class JsonController {

  @Autowired
  private ObjectMapper objectMapper;

  @GetMapping(value = "/")
  public ModelAndView index(HttpServletResponse response, ModelAndView mav) {
    mav.setViewName("index");
    return mav;
  }

  @PostMapping("/")
  public ModelAndView postSimpleModel(@RequestBody String model, ModelAndView mav) {
    List<JsonModel> jsonModelList = null;
    try {
      jsonModelList = objectMapper.readValue(model, new TypeReference<List<JsonModel>>() {
      });
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    System.out.println(jsonModelList);
    mav.setViewName("index");
    return mav;
  }

}

JsonModel.java
package com.demo.app.controller;

import lombok.Data;

@Data
public class JsonModel {
  private String first;
  private String last;
  private String handle;
}

動作確認

まずは画面から送信します。

ログ出力を確認すると、無事にjsonデータの文字列が送信されたことが確認できます。

次にController側です。Break Pointで処理を止めてデータの中身を確認します。

マッピングしたClassの中身にデータが入っていることが確認できます。これで動作確認が出来ました。

以上、Spring BootのControllerで様々なjsonデータを受け取ってClassにマッピングする方法でした。