谁在 Spring MVC (@ResponseBody)中设置响应内容类型

我的注释驱动的 Spring MVC Java web 应用程序运行在 jetty web 服务器上(目前使用的是 maven jetty 插件)。

我试图用一个只返回 String 帮助文本的控制器方法来做一些 AJAX 支持。资源是 UTF-8编码的,字符串也是,但是我从服务器得到的响应是

content-encoding: text/plain;charset=ISO-8859-1

即使我的浏览器发送

Accept-Charset  windows-1250,utf-8;q=0.7,*;q=0.7

我使用了弹簧的默认配置

我已经找到了将这个 bean 添加到配置中的提示,但是我认为它没有被使用,因为它说它不支持编码,而是使用了默认的编码。

<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain;charset=UTF-8" />
</bean>

我的控制器代码是(注意,这种响应类型的更改对我不起作用) :

@RequestMapping(value = "ajax/gethelp")
public @ResponseBody String handleGetHelp(Locale loc, String code, HttpServletResponse response) {
log.debug("Getting help for code: " + code);
response.setContentType("text/plain;charset=UTF-8");
String help = messageSource.getMessage(code, null, loc);
log.debug("Help is: " + help);
return help;
}
285783 次浏览

我使用的是在 web.xml 中配置的 CharterEncodingFilter。

    <filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>

仅仅声明 StringHttpMessageConverter bean 是不够的,您需要将其注入到 AnnotationMethodHandlerAdapter中:

<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<array>
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
</bean>
</array>
</property>
</bean>

但是,使用这种方法必须重新定义所有的 HttpMessageConverter,而且它也不能用于 <mvc:annotation-driven />

因此,也许最方便但丑陋的方法是用 BeanPostProcessor拦截 AnnotationMethodHandlerAdapter的实例化:

public class EncodingPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name)
throws BeansException {
if (bean instanceof AnnotationMethodHandlerAdapter) {
HttpMessageConverter<?>[] convs = ((AnnotationMethodHandlerAdapter) bean).getMessageConverters();
for (HttpMessageConverter<?> conv: convs) {
if (conv instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) conv).setSupportedMediaTypes(
Arrays.asList(new MediaType("text", "html",
Charset.forName("UTF-8"))));
}
}
}
return bean;
}


public Object postProcessAfterInitialization(Object bean, String name)
throws BeansException {
return bean;
}
}

-

<bean class = "EncodingPostProcessor " />

以防您还可以通过以下方式设置编码:

@RequestMapping(value = "ajax/gethelp")
public ResponseEntity<String> handleGetHelp(Locale loc, String code, HttpServletResponse response) {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "text/html; charset=utf-8");


log.debug("Getting help for code: " + code);
String help = messageSource.getMessage(code, null, loc);
log.debug("Help is: " + help);


return new ResponseEntity<String>("returning: " + help, responseHeaders, HttpStatus.CREATED);
}

我认为使用 StringHttpMessageConverter 比这更好。

感谢 digz6666,您的解决方案对我来说有一点小小的变化,因为我使用的是 json:

responseHeaders.add("Content-Type", "application/json; charset=utf-8");

Axtavt (你推荐的)给出的答案对我不起作用,即使我添加了正确的媒体类型:

if (conv instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) conv).setSupportedMediaTypes(
Arrays.asList(
new MediaType("text", "html", Charset.forName("UTF-8")),
new MediaType("application", "json", Charset.forName("UTF-8")) ));
}

如果上面的方法都不适合你在“ POST”而不是“ GET”上发送 ajax 请求,那么对我来说很有效... ... 上面的方法都不适合。我也有字符编码过滤器。

package com.your.package.spring.fix;


import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;


/**
* @author Szilard_Jakab (JaKi)
* Workaround for Spring 3 @ResponseBody issue - get incorrectly
encoded parameters     from the URL (in example @ JSON response)
* Tested @ Spring 3.0.4
*/
public class RepairWrongUrlParamEncoding {
private static String restoredParamToOriginal;


/**
* @param wrongUrlParam
* @return Repaired url param (UTF-8 encoded)
* @throws UnsupportedEncodingException
*/
public static String repair(String wrongUrlParam) throws
UnsupportedEncodingException {
/* First step: encode the incorrectly converted UTF-8 strings back to
the original URL format
*/
restoredParamToOriginal = URLEncoder.encode(wrongUrlParam, "ISO-8859-1");


/* Second step: decode to UTF-8 again from the original one
*/
return URLDecoder.decode(restoredParamToOriginal, "UTF-8");
}
}

在我为这个问题尝试了很多变通方法之后. . 我想出了这个方法,它工作得很好。

请注意,在 Spring MVC 3.1中,您可以使用 MVC 名称空间来配置消息转换器:

<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

或基于代码的配置:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {


private static final Charset UTF8 = Charset.forName("UTF-8");


@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", UTF8)));
converters.add(stringConverter);


// Add other converters ...
}
}

我在 内容协商视图解析器 bean 的 MarshallingView 中设置了内容类型:

<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller" />
</constructor-arg>
<property name="contentType" value="application/xml;charset=UTF-8" />
</bean>
</list>
</property>

我最近一直在努力解决这个问题,并在 Spring 3.1中找到了一个更好的答案:

@RequestMapping(value = "ajax/gethelp", produces = "text/plain")

因此,就像所有注释指出的那样,JAX-RS 非常简单。

我找到了 Spring 3.1的解决方案,使用了@ResponseBody 注释。 下面是控制器使用 Json 输出的例子:

@RequestMapping(value = "/getDealers", method = RequestMethod.GET,
produces = "application/json; charset=utf-8")
@ResponseBody
public String sendMobileData() {


}

您可以向 RequestMapping 添加 products = “ text/plain; charset = UTF-8”

@RequestMapping(value = "/rest/create/document", produces = "text/plain;charset=UTF-8")
@ResponseBody
public String create(Document document, HttpServletRespone respone) throws UnsupportedEncodingException {
    

Document newDocument = DocumentService.create(Document);
    

return jsonSerializer.serialize(newDocument);
}
public final class ConfigurableStringHttpMessageConverter extends AbstractHttpMessageConverter<String> {


private Charset defaultCharset;


public Charset getDefaultCharset() {
return defaultCharset;
}


private final List<Charset> availableCharsets;


private boolean writeAcceptCharset = true;


public ConfigurableStringHttpMessageConverter() {
super(new MediaType("text", "plain", StringHttpMessageConverter.DEFAULT_CHARSET), MediaType.ALL);
defaultCharset = StringHttpMessageConverter.DEFAULT_CHARSET;
this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
}


public ConfigurableStringHttpMessageConverter(String charsetName) {
super(new MediaType("text", "plain", Charset.forName(charsetName)), MediaType.ALL);
defaultCharset = Charset.forName(charsetName);
this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
}


/**
* Indicates whether the {@code Accept-Charset} should be written to any outgoing request.
* <p>Default is {@code true}.
*/
public void setWriteAcceptCharset(boolean writeAcceptCharset) {
this.writeAcceptCharset = writeAcceptCharset;
}


@Override
public boolean supports(Class<?> clazz) {
return String.class.equals(clazz);
}


@Override
protected String readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
}


@Override
protected Long getContentLength(String s, MediaType contentType) {
Charset charset = getContentTypeCharset(contentType);
try {
return (long) s.getBytes(charset.name()).length;
}
catch (UnsupportedEncodingException ex) {
// should not occur
throw new InternalError(ex.getMessage());
}
}


@Override
protected void writeInternal(String s, HttpOutputMessage outputMessage) throws IOException {
if (writeAcceptCharset) {
outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
}
Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
}


/**
* Return the list of supported {@link Charset}.
*
* <p>By default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses.
*
* @return the list of accepted charsets
*/
protected List<Charset> getAcceptedCharsets() {
return this.availableCharsets;
}


private Charset getContentTypeCharset(MediaType contentType) {
if (contentType != null && contentType.getCharSet() != null) {
return contentType.getCharSet();
}
else {
return defaultCharset;
}
}
}

配置示例:

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list>
<bean class="ru.dz.mvk.util.ConfigurableStringHttpMessageConverter">
<constructor-arg index="0" value="UTF-8"/>
</bean>
</util:list>
</property>
</bean>

您可以使用生成来指示从控制器发送的响应的类型。这个“生产”关键字在 Ajax 请求中非常有用,在我的项目中非常有用

@RequestMapping(value = "/aURLMapping.htm", method = RequestMethod.GET, produces = "text/html; charset=utf-8")


public @ResponseBody String getMobileData() {


}

在 Spring3.1.1中解决这个问题的简单方法是: 在 servlet-context.xml中添加以下配置代码

    <annotation-driven>
<message-converters register-defaults="true">
<beans:bean class="org.springframework.http.converter.StringHttpMessageConverter">
<beans:property name="supportedMediaTypes">
<beans:value>text/plain;charset=UTF-8</beans:value>
</beans:property>
</beans:bean>
</message-converters>
</annotation-driven>

不需要覆盖或实现任何东西。

根据 链接,“如果没有指定字符编码,Servlet 规范要求使用 ISO-8859-1编码”。如果您正在使用 spring 3.1或更高版本,请使用允许的配置将 charset = UTF-8设置为响应主体
@ RequestMapping (value = “ your map url”,products = “ text/Plain; charset = UTF-8”)

如果您决定通过以下配置修复此问题:

<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

您应该确认在所有的 * . xml 文件中应该只有一个 mvc: Annotation 驱动的标记。 否则,配置可能无效。