日期:2014-05-17  浏览次数:20638 次

Spring MVC REST内容协商(同一资源,多种展现方式,html、xml、json等,通过ContentNegotiatingViewResolver)

突然对ruby on rails来了兴趣,便捣弄了两天,用脚手架做了个hello world,实质上也就是一行命令的事,的确够效率。看一下Controller,其REST风格实在太简洁了。

?

  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @posts }
    end
  end

?一直在关注着spring,如今一般的web项目,从前到后几乎可以用spring直接搞定了。因此,对spring mvc及REST相关内容自然也有所了解。

?

?

于是今天就在想,spring mvc应该也可以对同一资源,实现多种展现才是,前提当然是在同一个方法里。(之前是为json的处理单独写一个Controller的method的,倒也没什么问题。)

就如以下:

?

@RequestMapping(value={"/user/{id}","/user/{id}.json"})
	public ModelAndView show(@PathVariable(value="id")String id){
		User user=userService.get(Long.valueOf(id));
		ModelAndView mav=new ModelAndView("show");
		mav.addObject(user);
		return mav;
	}

?

?当我请求/user/1时,便会回应show的视图,当我请求/user/{id}.json时,便会回应json格式的数据。

?

而spring mvc中ContentNegotiatingViewResolver便能满足这个需求,除了json,还有xml/rss。

?

相关资讯可查看这里(里面还对RESTful中同一资源多种表述进行描述的三种方式进行了讨论。)。

我当前使用spring版本是3.2,在这个版本里,对ContentNegotiatingViewResolver作了修改,原样参照以上链接配置,出现java.lang.ClassCastException: java.lang.String cannot be cast to org.springframework.http.MediaType 的异常。版本原因造成这个问题。

在springsource的论坛里有人询问和解答,请看这里或者这里。

?

起作用的配置,例:

?

<!-- REST -->
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1" />
        <property name="contentNegotiationManager">
            <bean class="org.springframework.web.accept.ContentNegotiationManager">
                <constructor-arg>
                    <bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
                        <constructor-arg>
                            <map>
                                <entry key="json" value="application/json"/>
                                <entry key="xml" value="application/xml"/>
                            </map>
                        </constructor-arg>
                    </bean>
                </constructor-arg>
            </bean>
        </property>


        <property name="defaultViews">
            <list>
                <!-- JSON View -->
                <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />

                <!-- XML View -->
                <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <constructor-arg>
                        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                            <property name="packagesToScan">
                                <list>
                                    <value>documentLoader.domain</value>
                                </list>
                            </property>
                        </bean>
                    </constructor-arg>
                </bean>
            </list>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>
仅作小记,如果刚好对他人有用就更好了。