前提
- 应答报文都是JSON格式,即通过@RequestMapping中的produces={application/json}属性实现
线索梳理
1. 确认Controller中返回对象类型
Spring MVC返回Json字符串基本使用两种方式,第一,controller的方法直接返回Json格式的字符串, 第二, 返回Form,List, Map之类的可序列化对象,配置Spring集成Jackson进行json转换。
2. 确认StringHttpMessageConverter的配置编码(方式一)
因为controller返回的已经是字符串, Spring只需将其刷入response的outputStream中即可。但是刷入的时候用的具体编码是什么呢?
查看StringHttpMessageConverter的源码可以看到 DEFAULT_CHARSET = Charset.forName("ISO-8859-1")
, 只需要在dispatcher-servlet.xml中将其修改为UTF-8即可。
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<constructor-arg value="application"/>
<constructor-arg value="json"/>
<constructor-arg value="UTF-8"/>
</bean>
</list>
</property>
</bean>
3. 确认MappingJackson2HttpMessageConverter的配置编码(方式二)
该转换类的默认编码是UTF-8, 所以这里应该不会出现编码问题。如果手动配置是这样的。
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
4. Spring API 过时
当dispatcher-servlet.xml中使用<mvc:annotation-driven />时,如果是3.1之前已经默认注入AnnotationMethodHandlerAdapter,3.1之后默认注入RequestMappingHandlerAdapter。所以如果没有使用<mvc:annotation-driven />,需要手动添加声明,示例如下
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain; charset=UTF-8</value>
<value>text/html; charset=UTF-8</value>
<value>application/json; charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json; charset=UTF-8</value>
<value>application/x-www-form-urlencoded; charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
乱码场景1
controller中的方法定义如下,所以满足方式一,使用了<mvc:annotation-driven />,最终应答报文乱码。
解决方案有两种:
A. produces的值修改为 {"application/json; charset=utf-8"}, 最简单直观,但是所有的方法上面都要修改;
B. dispatcher-servlet.xml 中添加StringHttpMessageConverter的配置是没用的,因为你会发现怎么都不能生效!这是因为produces里面的只设定了 application/json, 在 StringHttpMessageConverter.getContentTypeCharset(MediaType contentType)
的入参中, MediaType永远只有application/json, 获取不到charset!
可采用上方 <mvc:annotation-driven>中添加 converter的方式,并确保删除 produces。
这个场景最终只说明一个问题,produces中的MediaType要完整,包括type(application) subtype(json)和charset(utf-8)
@RequestMapping(value = "queryIdCard", method = RequestMethod.POST, produces = {"application/json"})
@ResponseBody
public String queryIdCard(@RequestBody String idCardNo) {
MeResponse response = idCardBusiness.queryPersonInfo(idCardNo);
return JsonUtil.toJsonString(response);
}