Spring MVC 响应报文乱码

spring 4.2.2 responsebody 乱码 utf-8

乱码问题一直是个比较头疼的话题,因为造成乱码的罪魁祸首千奇百怪,乱七八糟。。。
本文就作为收集各种与Spring MVC相关的案例的合集,持续更新吧。

前提

  • 应答报文都是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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容