Spring WebMVCをやってみる (3) - 返せるレスポンスタイプに関して -

2013-12-06T00:00:00+00:00 Java Spring Framework

大まかにSpring WebMVCでコントローラーアクション(@RequestMappingで処理されるメソッド)で返せる値の形式は

  • String (redirect/forward等のプレフィックスも含む)
  • ModelAndView
  • Map<String, Object>
  • String、又はbyte[]等で@ResponseBodyなアノテーションを付与
  • ResponseEntityを使用
  • org.springframework.web.servlet.Viewを使用

っていうような感じで値を返す事が出来る。もちろん値を返さないvoidでも引数にHttpServletResponseを利用してレスポンスを出す事も可能

ModelAndViewはSpring WebMVCをやってみる (2) – アノテーションを使わないコントローラー -で既に検証済みなので省略する。又、最後のViewに関しては後日別途で記事を書く予定になっているので今回は省略する。という事でコントローラー書いてテスト書いて検証してみる

SampleController.java

package sample;

import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/sample")
public class SampleController {

    // Mapで返した場合にはそれに含まれているパラメーターがビューとなるJSP等で参照可能(例えば以下だと${data})
    @RequestMapping("/test1")
    public Map<String, Object> test(HttpServletResponse response)  throws Exception{
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("data", "hoge");

        return data;
    }

    @RequestMapping("/test2")
    @ResponseBody
    public String test2() {
        return "hoge";
    }

    @RequestMapping("/test3")
    public ResponseEntity<String> test3() {
        return new ResponseEntity<String>("hoge", HttpStatus.OK);
    }

    @RequestMapping("/test4")
    public String test4() {
        return "redirect:/sample/test3";
    }

    @RequestMapping("/test5")
    @ResponseBody
    public byte[] test5() {
        return "hoge".getBytes();
    }
}

んまぁあとはテスト書いて

SampleControllerTest.java

package swmvc;

import java.util.Map;

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

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 test1_Mapでパラメーターを返す() throws Exception {
        MvcResult result = mock.perform(get("/sample/test1"))
            .andExpect(request().attribute("data", notNullValue()))
            .andExpect(request().attribute("data", is("hoge")))
            .andReturn();

        MockHttpServletResponse response = result.getResponse();
        assertThat(response, notNullValue());
        assertThat(response.getStatus(), is(200));

        ModelAndView model = result.getModelAndView();
        assertThat(model, notNullValue());

        Map<String, Object> values = model.getModel();
        assertThat(values, notNullValue());
        assertThat(values, hasKey("data"));
        assertThat(values.get("data").toString(), is("hoge"));
    }

    @Test
    public void test2_ResponseBodyでStringを返す() throws Exception {
        MvcResult result = mock.perform(get("/sample/test2"))
            .andExpect(content().string("hoge"))
            .andReturn();

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

    @Test
    public void test3_ResponseEntityを返す() throws Exception {
        MvcResult result = mock.perform(get("/sample/test3"))
            .andExpect(content().string("hoge"))
            .andReturn();

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

    @Test
    public void test4_redirectプレフィックスを使う() throws Exception {
        int actualStatus = 302;

        MvcResult result = mock.perform(get("/sample/test4"))
            .andExpect(status().is(actualStatus))
            .andExpect(redirectedUrl("/sample/test3"))
            .andReturn();

        MockHttpServletResponse response = result.getResponse();
        assertThat(response, notNullValue());
        assertThat(response.getStatus(), is(actualStatus));
        assertThat(response.getRedirectedUrl(), is("/sample/test3"));
    }

    @Test
    public void test5_ResponseBodyでbyteアレイを返す() throws Exception {
        MvcResult result = mock.perform(get("/sample/test5"))
            .andExpect(content().bytes("hoge".getBytes()))
            .andReturn();

        MockHttpServletResponse response = result.getResponse();
        assertThat(response, notNullValue());
        assertThat(response.getStatus(), is(200));
        assertThat(response.getContentAsString(), is("hoge"));
        assertThat(response.getContentAsByteArray(), is("hoge".getBytes()));
    }
}

んまぁまだまだ色々ありそうだけど、とりまぁ現時点でのメモ。追記するかも

追記1: 引数にModelMapを利用する

package sample;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/sample")
public class SampleController {
    @RequestMapping("/test/{message}")
    public String test(@PathVariable String message, ModelMap model) {
        model.addAttribute("data", message.toUpperCase());

        return "test";
    }
}

っていう感じでも良い。ModelMapに入れられたデータ自体はJSP等でもEL式を用いて参照する事が可能な模様。ちなみにこの場合のテストは

package swmvc;

import org.junit.Test;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.ModelAndView;

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 {
        MvcResult result = mock.perform(get("/sample/test/hoge"))
            .andExpect(model().attributeExists("data"))
            .andExpect(model().attribute("data", is("HOGE")))
            .andReturn();

        ModelAndView mav = result.getModelAndView();
        assertThat(mav, notNullValue());

        ModelMap model = mav.getModelMap();
        assertThat(model, hasKey("data"));
        assertThat(model.get("data").toString(), is("HOGE"));
    }
}

っていう感じかと

Spring WebMVCをやってみる (4) - AbstractViewを利用した独自Viewを利用する - Spring WebMVCをやってみる (2) - アノテーションを使わないコントローラー -