在Spring MVC中,使用@ResponseBody时如何设置mime类型标头


76

我有一个Spring MVC Controller,它返回一个JSON字符串,我想将mimetype设置为application / json。我怎样才能做到这一点?

@RequestMapping(method=RequestMethod.GET, value="foo/bar")
@ResponseBody
public String fooBar(){
    return myService.getJson();
}

业务对象已经可以作为JSON字符串使用,因此使用MappingJacksonJsonView不是我的解决方案。@ResponseBody是完美的,但如何设置模仿类型?


使用spring 3.2及其新的测试功能...如果不使用ResponseEntity,是否有解决方案?
NimChimpsky

使用HttpHeaders.setContentType-以下是一些使用方法的示例
drorw

@drorw,这个问题问世多年后才引入:-)
肖恩·帕特里克·弗洛伊德

Answers:


40

我会考虑重构服务以返回您的域对象而不是JSON字符串,并让Spring处理序列化(通过MappingJacksonHttpMessageConverter编写时的)。从Spring 3.1开始,实现看起来很整洁:

@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, 
    method = RequestMethod.GET
    value = "/foo/bar")
@ResponseBody
public Bar fooBar(){
    return myService.getBar();
}

评论:

首先,<mvc:annotation-driven />@EnableWebMvc必须添加到您的应用程序配置中。

接下来,注释的Produces属性@RequestMapping用于指定响应的内容类型。因此,应将其设置为MediaType.APPLICATION_JSON_VALUE(或"application/json")。

最后,必须添加Jackson,以便Java和JSON之间的任何序列化和反序列化都将由Spring自动处理(Spring检测到Jackson依赖关系,并且MappingJacksonHttpMessageConverter将在后台进行)。


这个答案应该是第一位的,让Spring为您完成工作!!
chrismarx 2013年

8
根据javadoc,属性产生的目的是匹配请求的Accept标头。这就解释了为什么价值产生是值的列表。因此,产生不是添加任何响应头的可靠方法。根据javadoc,它与响应标头无关。
rwitzel

123

使用ResponseEntity代替ResponseBody。这样,您可以访问响应标题,并可以设置适当的内容类型。根据Spring文档

HttpEntity类似于 @RequestBody@ResponseBody。除了访问请求和响应主体HttpEntity(以及特定于响应的子类 ResponseEntity)之外,还允许访问请求和响应头

代码如下所示:

@RequestMapping(method=RequestMethod.GET, value="/fooBar")
public ResponseEntity<String> fooBar2() {
    String json = "jsonResponse";
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.setContentType(MediaType.APPLICATION_JSON);
    return new ResponseEntity<String>(json, responseHeaders, HttpStatus.CREATED);
}

嗨,我想返回一个序列化的对象,但是使用您的方法我遇到了一个问题,它无法编译,因为它说:HttpHeaders是抽象的,无法实例化....您能同时向我解释一下返回对象的序列化?现在,如果不使用ResponseEntity,它就可以正常工作
Lince81

@ Lince81 org.springframework.http.HttpHeaders不是抽象类(static.springsource.org/spring/docs/3.0.x/javadoc-api/org/…)。查看您的导入是否正确以及库是否已更新。
哈维尔·费雷罗

@ Lince81示例的要点是在设置其他Content-Type时以String形式返回已序列化的对象。如果您想让Spring序列化一个对象(如XML,JSON等),请使用@ResponseBody并配置适当的MessageConverters(请参阅答案中的链接)
Javier Ferrero

1
只是想指出,Spring MVC 3.1允许您在RequestMapping中为“产生”指定一个值。因此,您仍然可以使用@ResponseBody,但是需要@RequestMapping(method = RequestMethod.GET,value =“ / fooBar”,producer =“ application / json”)。
2012年

2
使用这种方法,您可以使同一个方法返回不同的内容类型,而这对于Spring的“农产品”是无法做到的。另外,这是最少介入的方法,即您不必创建/实例化自己的MessageConverters。
dewtea

7

您可能无法使用@ResponseBody做到这一点,但是类似的事情应该可以起作用:

package xxx;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class FooBar {
  @RequestMapping(value="foo/bar", method = RequestMethod.GET)
  public void fooBar(HttpServletResponse response) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    out.write(myService.getJson().getBytes());
    response.setContentType("application/json");
    response.setContentLength(out.size());
    response.getOutputStream().write(out.toByteArray());
    response.getOutputStream().flush();
  }
}

他需要写响应,还是只设置标头就可以了?
博佐2010年

1
好答案。如果mime类型是动态的,那么字节数组一定也必须是动态的,因此只写字节数组就没有@ResponseBody的魔力是有意义的。唯一的修改是直接编写OutputStream,而不是将其加载到内存(out.toByteArray)中。
詹姆斯·沃特金斯

@JamesWatkins您需要将JSON加载到内存中才能计算内容长度。如果您的JSON对象相当小(通常应该是!),则无需担心。
Stefan Haberl,2014年

我认为问题的真正本质是:“如何设置mime类型并同时发送非HTML响应?” 我可能有一个非常大的文件,我想流式传输到客户端。此外,“内容长度”是可选的,还有其他方法可以导出(从数据库等)。
詹姆斯·沃特金斯


3

注册org.springframework.http.converter.json.MappingJacksonHttpMessageConverter为消息转换器,然后直接从方法中返回对象。

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="webBindingInitializer">
    <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"/>
  </property>
  <property name="messageConverters">
    <list>
      <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
    </list>
  </property>
</bean>

和控制器:

@RequestMapping(method=RequestMethod.GET, value="foo/bar")
public @ResponseBody Object fooBar(){
    return myService.getActualObject();
}

这需要依赖org.springframework:spring-webmvc


是的,可能是最佳实践,但是在我编写对象时,我的对象已经是JSON字符串,我只想使用正确的mime类型将它们写出来。
肖恩·帕特里克·弗洛伊德

您要引用的Bean的Maven依赖项是什么?
瑞安·蒙哥马利


-2

我的现实版本。加载HTML文件并将其流式传输到浏览器。

@Controller
@RequestMapping("/")
public class UIController {

    @RequestMapping(value="index", method=RequestMethod.GET, produces = "text/html")
    public @ResponseBody String GetBootupFile() throws IOException  {
        Resource resource = new ClassPathResource("MainPage.html");
        String fileContents = FileUtils.readFileToString(resource.getFile());
        return fileContents;
    }
}

您知道Spring MVC可以直接提供静态资源吗?
肖恩·帕特里克·弗洛伊德

Spring不仅需要做大量的工作,而且还破坏了Spring可以自动为您处理和管理的其他许多事情,并公开了安全性问题和其他故障点。
BrianC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.