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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值