Spring WebMVCをやってみる (4) - AbstractViewを利用した独自Viewを利用する -

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

前回のSpring WebMVCをやってみる (3) – 返せるレスポンスタイプに関して -でも書いたように、レスポンスを返す型としてView型を返す事も出来る。又、ModelAndViewにsetViewNameを利用する事でも独自のViewを使ってレスポンスを返却させる事が出来る。という事で使ってみた

SampleView.java

jsonpullparserを使ってJSONを出力するだけな事やってみる

package sample;

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

import org.springframework.web.servlet.view.AbstractView;

public class SampleView extends AbstractView {

    @Override
    protected void renderMergedOutputModel(
        Map<string, Object> model,
        HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        Sample sample = null;

        if (model.containsKey("sample"))
            sample = (Sample)model.get("sample");

        response.setStatus(200);
        response.setContentType("application/json; charset=utf-8");
        SampleGen.encode(response.getWriter(), sample);
    }
}

renderMergedOutputModelメソッドでレスポンスを返却するような処理を実装すれば良いだけ。で

package sample;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.View;

@Controller
@RequestMapping("/sample")
public class SampleController {
    @RequestMapping("/test")
    public View test() {
        Sample sample = new Sample();
        sample.setName("hoge");

        SampleView view = new SampleView();
        view.getAttributesMap().put("sample", sample);

        return view;
    }
}

のようにAbstractViewな実装クラスのインスタンスを返却するだけでも構わないが

package sample;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/sample")
public class SampleController {
    @RequestMapping(value = "/test")
    public ModelAndView test() {
        Sample sample = new Sample();
        sample.setName("hoge");

        ModelAndView mav = new ModelAndView();
        mav.setViewName("sample");
        mav.addObject("sample", sample);

        return mav;
    }
}

上記でも書いたようにModelAndView#setViewNameを利用してレスポンスを返却するのに使うビューを指定する事も出来る。但しこれを利用するには別途な設定が必要になる

spring-web-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="sample" />

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="html" value="text/html" />
                <entry key="json" value="application/json" />
            </map>
        </property>
        <property name="viewResolvers">
            <list>
                <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
                    <property name="prefix" value="/WEB-INF/jsp/"/>
                    <property name="suffix" value=".jsp"/>
                    <property name="order" value="1" />
                </bean>
                <bean class="org.springframework.web.servlet.view.XmlViewResolver">
                    <property name="order" value="0" />
                    <property name="location" value="/WEB-INF/views.xml" />
                </bean>
            </list>
        </property>
    </bean>
</beans>

http://docs.spring.io/spring/docs/3.0.x/javadoc-api/org/springframework/web/servlet/view/InternalResourceViewResolver.html でも書かれているんだが

Note: When chaining ViewResolvers, an InternalResourceViewResolver always needs to be last, as it will attempt to resolve any view name, no matter whether the underlying resource actually exists.

というようにInternalResourceViewResolverを使うのであれば必ず最後に定義する事?的な感じなんじゃないのかなーと。でそれを意識せずに設定を行った場合だと、InternalResourceViewResolverでsetViewNameしてもそこで処理されて実際に要求しているViewResolverには作用しない事になる模様

んまぁそこは注意っすねって事で。んでXmlViewResolverな設定ファイル(/WEB-INF/views.xml)が必要なのでこれも作る

/WEB-INF/views.xml

<?xml version="1.0" ?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean name="sample" class="sample.SampleView" />

</beans>

<bean name="">で指定してやりゃ良い。そこに指定されたのがViewNameになる模様

んまぁあとはテスト書けば良いか

SampleControllerTest.java

package swmvc;

import org.junit.Test;

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 test5() throws Exception {
        mock.perform(get("/sample/test5"))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json; charset=utf-8"))
            .andReturn();
    }
}

終わり

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