Sping Mvc中Http请求返回String中文乱码问题深度解析

时间:2022-10-06 05:46:20

前言

  • SpringMVC中,可以使用@RequestBody@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Spring3.x中新引入的HttpMessageConverter即消息转换器机制。而这种消转换机制的原理是什么,大家可以去具体的分析一下SpringMvc的源码。

HttpMessageConverter机制大致原理

  • 当我们在Handler的某个方法上加上注解@ResponseBody后,服务器可以给客户端返回json格式的数据,当然,其本质就是字符串。因为Http请求和响应报文本质上都是一串字符串,当请求报文来到java世界,它会被封装成为一个ServletInputStream的输入流,供我们读取报文。响应报文则是通过一个ServletOutputStream的输出流,来输出响应报文。
  • 我们从输入流中,只能读取到原始的字符串报文,同样,我们在输出流中,也只能写原始的字符。而在java世界中,处理业务逻辑,都是以一个个有业务意义的对象为处理维度的,那么在报文到达SpringMVC和从SpringMVC出去,都存在一个字符串到java对象的阻抗问题。这一过程,不可能由开发者手工转换。
  • -

下面是原理的大致流程图

Sping Mvc中Http请求返回String中文乱码问题深度解析

遇到的问题

@ResponseBody加到某个返回String的方法上时,当方法返回字符串中有汉字时,客户端接收到就会产生乱码问题,具体Demo如下所示。

@ResponseBody
@RequestMapping(value="/queryJson")
public String queryJson(HttpServletRequest request,HttpServletResponse response,Model model) throws Exception {
//将学生信息列表在页面上展示
List<Student> list = new ArrayList<Student>();
Student student = new Student();
student.setId("id1");
student.setName("小学生");
student.setAge(8);
student.setAddress("北京市海淀区");
list.add(student);
return list.toString();
}

返回效果图

Sping Mvc中Http请求返回String中文乱码问题深度解析

  • 本来name应该显示为“小学生”,address显示成”北京市海淀区”,但是现在全部变成了? 这是怎么一回事那?

问题的原因

  • 这个问题的原因是HttpMessageConverte机制在处理请求和响应的时候出现的问题,Springmvc有一系列HttpMessageConverter去处理用@ResponseBody注解的返回值,如返回list或其它则使用 MappingJacksonHttpMessageConverter,若返回String,则使用 StringHttpMessageConverter,而返回String这个convert使用的是字符集是iso-8859-1,而且是final的。所以在当返回String中有中文时会出现乱码。下面是源码。
public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");      

解决方法

在@RequestMapping中设置一下MediaType

@RequestMapping(value="/queryJson", produces =MediaType.APPLICATION_JSON_VALUE)

或者这样

@RequestMapping(value="/queryJson", produces ="application/json" + ";charset=utf-8")

这两个效果是一样的

在springmvc配置文件设置

<mvc:annotation-driven>
<mvc:message-converters>
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">

<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=utf-8</value>
<value>text/html;charset=UTF-8</value>
<value>text/json;charset=UTF-8</value>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

小结

  • 解决方式不止一种,个人推荐第二种方式,这种方式一劳永逸,方便程序员开发。