在搞清tomcat中的编解码一文中,已经详细讨论过各个参数乱码的成因及解决办法,但是未说明一个问题:即response的乱码问题。
一般来说,在使用spring时只要配置了encoding filter,则其会自动帮助你过滤request和response。
<filter>
<filter-name>encodingFilter</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>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
但是,在使用了@ResponseBody时,则仍会出现中文乱码问题。
究其原因,是因为spring在responsebody内部的messageConverter使用了一个hardcode的编码,默认为iso8859-1,所幸spring的扩展性够强,只需要扩展utf8的messageconverter即可搞定。
比较合适的解决办法有两种,第一种是自定义MessageConverter,完成编码;第二种是在需要responsebody的地方使用HttpServletResponse的write方法。
其中,第一种方法相对优雅,其自定义实现如下:
public class UTF8StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private final List<Charset> availableCharsets;
private boolean writeAcceptCharset = true;
public UTF8StringHttpMessageConverter() {
super(new MediaType("text", "plain", DEFAULT_CHARSET), MediaType.ALL);
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 DEFAULT_CHARSET;
}
}
}
只需要在springmvc中配置如下定义,即可解决该问题
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.sap.cesp.creditinsight.web.app.utils.UTF8StringHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
而第二种方法则需要在每个输出的地方输出即可
HttpServletResponse.getWriter().write(str);
参考: http://blog.csdn.net/jpr1990/article/details/7710110