spring @ResponseBody String 中文乱码(显示问号)
根本原因:String
默认使用StringHttpMessageConverter
转换,而它默认编码是ISO-8859-1
。[1]
对StringHttpMessageConverter
进行配置可以统一地解决问题。
这里讨论了2种配置方法和2种配置位置,推荐方案在最后。
方法1:修改默认编码。[2]
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
如上,通过<constructor-arg value="UTF-8" />
指定构造函数的参数,从而设置默认编码。
方法2:添加支持的content-type类型(包含指定编码)。[3]
这里涉及content-type的匹配,网上一些配置是text/plain
,但spring默认可能是text/html
,这样就匹配不到(比如我的项目中就会导致最终由MappingJackson2HttpMessageConverter
来处理)。
如果希望所有String
返回值都用该converter处理,可以直接设置*/*
匹配所有:
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>*/*;charset=UTF-8</value>
</list>
</property>
</bean>
原理解释
各个转换器根据Controller
返回值和content-type判断使用与否。StringHttpMessageConverter
只接受String
类型,默认匹配text/plain
和*/*
(相当于匹配所有吧?)。另一方面,如果content-type中没有设置编码,则会使用默认编码。
关于配置位置
位置1:RequestMappingHandlerAdapter.messageConverters
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters" >
...
</property>
</bean>
这样子配置messageConverters
会覆盖原有的转换器(包括项目可能使用的json转换器),而自己再手动加上去就更麻烦了。
而且有个坑的地方:对使用@ExceptionHandler
进行异常处理的返回值无效。个人理解是因为RequestMappingHandlerAdapter
只处理正常请求,发生异常后由ExceptionHandlerExceptionResolver
处理。
位置2:<mvc:message-converters>
<mvc:annotation-driven>
<mvc:message-converters>
...
</mvc:message-converters>
</mvc:annotation-driven>
这样可以给上述2者都加上一个转换器(优先级较高),统一处理正常和异常的情况。
注意:位置1的配置也会覆盖位置2的配置。
最终推荐方案
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
其他参考:
Spring Mvc 3.1 之后如何配置messageConverters
SpringMVC-<mvc:annotation-driven>的作用