在 Spring-MVC 控制器中支持多种内容类型

Posted

技术标签:

【中文标题】在 Spring-MVC 控制器中支持多种内容类型【英文标题】:Supporting multiple content types in a Spring-MVC controller 【发布时间】:2011-05-23 03:56:27 【问题描述】:

Rails 控制器可以很容易地支持多种内容类型。

respond_to do |format|
  format.js  render :json => @obj 
  format.xml
  format.html
end

美丽。在一个控制器操作中,我可以很容易地响应多种内容类型,并且对于我希望呈现的内容具有很大的灵活性,无论是模板、我的对象的序列化形式等。

我可以在 Spring-MVC 中做类似的事情吗? Spring中支持多种内容类型的标准是什么?我见过涉及视图解析器的解决方案,但这看起来很难管理,特别是如果我想支持除了 xhtml 和 xml 之外的 JSON。

欢迎提出任何建议,但更简单、更优雅的解决方案将受到更多赞赏;)

编辑

如果我断言视图解析器难以管理是不正确的,请随时纠正我并提供示例。最好是可以返回 xml、xhtml 和 JSON 的。

【问题讨论】:

【参考方案1】:

这里是工作示例控制器,它根据请求标头“Content-Type”呈现 JSON 和 HTML。

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PersonService 
    @RequestMapping(value = "/persons/userId", method = RequestMethod.GET)
    public ResponseEntity<?> getPersonByName(@RequestHeader("Content-Type") String contentMediaType,
            @PathVariable("userId") String userId,@RequestParam("anyParam") boolean isAscending) throws IOException 

        Person person = getPersonById(userId);
        if (isJSON(contentMediaType)) 
            return new ResponseEntity<Person>(person, HttpStatus.OK);
        

        return new ResponseEntity("Your HTML Goes Here", HttpStatus.OK);
        //Note: Above you could use any HTML builder framework, like HandleBar/Moustache/JSP/Plain HTML Template etc.
    


    private static final boolean isJSON(String contentMediaType) 
        if ("application/json".equalsIgnoreCase(contentMediaType)) 
            return true;
        

        return false;
    


【讨论】:

【参考方案2】:

在 Spring 3 中,您想使用 org.springframework.web.servlet.view.ContentNegotiatingViewResolver

它需要一个媒体类型列表和ViewResolvers。来自Spring docs:

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
  <property name="mediaTypes">
    <map>
      <entry key="atom" value="application/atom+xml"/>
      <entry key="html" value="text/html"/>
      <entry key="json" value="application/json"/>
    </map>
  </property>
  <property name="viewResolvers">
    <list>
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
      </bean>
    </list>
  </property>
  <property name="defaultViews">
    <list>
      <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
    </list>
  </property>
</bean>
<bean id="content" class="com.springsource.samples.rest.SampleContentAtomView"/>

控制器:

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

@Controller
public class BlogsController 

    @RequestMapping("/blogs")
    public String index(ModelMap model) 
        model.addAttribute("blog", new Blog("foobar"));
        return "blogs/index";
        

您还需要包含 Jackson JSON jar。

【讨论】:

是否像 Rails 一样简单和“漂亮”?不。但按照 Java 标准,可能与我们将得到的一样好。 P.S. - 我只测试了 HTML 和 JSON 内容类型。我现在正在研究原子。 @Todd:谢谢!不过这有点令人困惑。如果我返回字符串“blogs/index”,我的任何视图如何与我的模型交互?我期待它返回一个 ModelAndView 对象,我们会将字符串“blogs/index”传递给该对象,然后如果客户端请求 JSON,Spring 将忽略该字符串并通过 Jackson 序列化该对象。你能解释一下你的例子是如何工作的吗? @Samo,博客模型在模型中设置,传入(通过引用)并作为“博客”提供给视图。视图“blogs/index”映射到“WEB-INF/jsp/blogs/index.jsp”。是的,当我将 .json 添加到我的 url 时,“/blogs.json”视图被忽略并打印 "blog":"name":"foobar" @Samo,你也可以使用 ModelAndView。我刚试过。 @RequestMapping("/blogs") public ModelAndView index() Blog blog = new Blog("foobar"); ModelAndView model = new ModelAndView("blogs/index", "blog", blog);返回模型;

以上是关于在 Spring-MVC 控制器中支持多种内容类型的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring-MVC 中将数据从视图传递到控制器?

在实现接口的控制器上使用 @Controller 的 Spring-MVC 问题

Spring-MVC:如何从控制器流式传输 mp3 文件

MVC5 找到与名为“Home”的控制器匹配的多种类型

NopCommerce支持多种类型的数据库

如何在 spring-mvc 中为 REST 查询提供对象列表?