Spring WebMVCをやってみる (7) - @RequestBody -

2013-12-11T00:00:00+00:00 Java JavaScript Spring Framework

まぁアノテーション名で分かるようにHTTPリクエストボディを引数にマッピング出来る的な感じの解釈で良いんじゃないかと。例えばJSONデータをぶっこんでコントローラーでパースして利用するような場合とかに使うとかなんですかね

とりあえずやってみた

SampleController.java

JSONリクエストを受け取って、それをパースしてidをレスポンスとして出力するだけ(パース出来なかった場合には0を出力)

※JSONをパースする仕組み的な所はjsonpullparserを使用

package sample;

import java.io.IOException;

import net.vvakame.util.jsonpullparser.JsonFormatException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/sample")
public class SampleController {
    @RequestMapping(
        value = "/test",
        method = RequestMethod.POST,
        headers = {
            "content-type=*",
            "accept=application/json"
        }
    )
    @ResponseBody
    public String test(@RequestBody String body) {
        int id = 0;

        try {
            Sample sample = SampleGen.get(body);
            id = sample.getId();
        } catch (JsonFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return String.valueOf(id);
    }
}

@RequestBodyを持つ引数を定義する。それを利用してJSONリクエストをパース

SampleControllerTest.java

package swmvc;

import java.io.IOException;
import java.io.StringWriter;

import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MvcResult;

import sample.Sample;
import sample.SampleGen;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

public class SampleControllerTest extends AbstractTestCase {

    @Test
    public void test() throws Exception {
        Sample sample = new Sample();
        sample.setId(1);

        MvcResult result = mock.perform(
            post("/sample/test")
                .accept(MediaType.APPLICATION_JSON)
                .contentType(MediaType.ALL)
                .content(toJson(sample))
            )
            .andExpect(status().isOk())
            .andReturn();

        MockHttpServletResponse response = result.getResponse();
        assertThat(response, notNullValue());
        assertThat(response.getContentAsString(), is("1"));
    }

    private String toJson(Sample sample) throws IOException {
        StringWriter writer = new StringWriter();
        SampleGen.encode(writer, sample);

        return writer.toString();
    }
}

なぜリクエストにContent-Typeを指定しなきゃならんのかっていう所として、Acceptヘッダー等によるリクエスト制限を行いたい場合等にはcontent-typeまで指定しないと「Unsupported Media Type」のようなエラーが出る。そのため許容するリクエストにContent-Typeを指定することでMedia Typeを識別する為に必要な模様。理論的な根拠までは判明していないので判明したら追記する予定

んまぁこれはJUnitテストでやってるだけなので、Ajaxとかでやる場合には

$(document).ready(function() {
  $.ajax({
    type: "POST",
    url: "/swmvc/sample/test.action",
    dataType: "json",
    data: JSON.stringify({ "id": 1 }),
    contentType: "application/json",
    success: function(data) {
      console.log(data);
    }
  });
});

っていうような感じになるかと

Spring WebMVCをやってみる (8) - @ModelAttribute - Spring WebMVCをやってみる (6) - @RequestParam -