首先请确保Spring版本为3.2.4
问题1:使用@ResponseBody注解,返回对象类型时,如Map,中文字符,在客户端会显示为???
解决办法:请检查依赖jar包,确保spring-context-support.jar的版本也是3.2.4,则可显示中文;
问题2:使用@ResponseBody注解,返回String时,中文字符,在客户端会显示为???,并且contextType中会缺失encoding值,即为text/html但是,没有后面的encode
解决办法:首先需要知道,在spring3.2以后,@RequestMapping使用了RequestMappingHandlerAdapter来处理请求,对于@ResponseBody,当为string时,会调用默认构造方法里面add的StringHttpMessageConverter,需要注意的是,这个converter默认的编码是“ISO-8859-1”,中文的大敌啊,而且这个converter是new出来的,因此无法采用替代注入的方式,而只能注入messageConverters,因此,我们需要重新申明一个RequestMappingHandlerAdapter,如下:
<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <beans:property name="messageConverters"> <beans:list> <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter"> <beans:constructor-arg value="UTF-8" /> <beans:property name="writeAcceptCharset" value="false"/> </beans:bean> <beans:bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></beans:bean> <beans:bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></beans:bean> <beans:bean class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter"></beans:bean> </beans:list> </beans:property> </beans:bean>
为什么除了StringHttpMessageConverter还有其他3个converter呢,因为默认RequestMappingHandlerAdapter构造函数是增加了4个converter的,如果不全写上,可能导致其他返回类型无法被转换,自己可以试试看,StringHttpMessageConverter有个writeAcceptCharset的设置,请自行查看源码。
重新定义了RequestMappingHandlerAdapter以后,中文能被正确写入到response,但是,默认情况下,客户端会看到response返回的contentType可能为"text/html",仍然没有编码显示,这时,需要主动设置response的encoding,或者采用filter。如果使用spring的CharacterEncodingFilter,请将forceEncoding设置为true。至此,客户端会看到contentType为 text/html;charset=UTF-8
!!补充:实际上,根据3.2.4文档可以看到,RequestMappingHandlerAdapter不仅add了以上默认的4个converter,而是更多,debug可以看到实际上是7个converter,这个是由mvc命名空间默认增加的,至于源码什么地方做的,我没找到。后来去看spring-mvc.xsd,学习到,annotation-driven标签下的message-converters可以直接替换或者增加converter,于是,我将自己做的StringHttpMessageConverter增加到了里面,而去掉了RequestMappingHandlerAdapter的bean,如下:
<annotation-driven> <message-converters> <!-- default StringHttpMessageConverter, solve encoding problem --> <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter"> <beans:constructor-arg value="UTF-8" /> <beans:property name="writeAcceptCharset" value="false" /> </beans:bean> </message-converters> </annotation-driven>
这可能是更好的解决办法,但是,现在converter就会变成8个,会有2个String的converter存在,目前测试没问题,自己做的converter优先级是最高的,可能这才是最好的解决办法。