问题:
在前端通过get请求服务端返回String类型的服务时,会出现中文乱码问题

原因:
由于spring默认对String类型的返回的编码采用的是 StringHttpMessageConverter
>>> spring mvc的一个bug,spring MVC有一系列HttpMessageConverter去处理用@ResponseBody注解的返回值,如返回list则使用MappingJacksonHttpMessageConverter,返回string,则使用StringHttpMessageConverter,这个convert使用的是字符集是iso-8859-1,而且是final的:
public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");

解决办法:
方案一:
对于需要返回字符串的方法添加注解,如下:只针对单个方法生效,不全局生效

  1. @RequestMapping(value = "/getUsers", produces = "application/json; charset=utf-8")
  2. public String getAllUser()throws JsonGenerationException, JsonMappingException, IOException{
  3.   List < User > users = userService.getAll();
  4.   ObjectMapper om = new ObjectMapper();
  5.   System.out.println(om.writeValueAsString(users));
  6.   DataGrid dg = new DataGrid();
  7.   dg.setData(users);
  8.   return om.writeValueAsString(dg);
  9. }

方案二:

在spring-servlet.xml中加入:

  1. <mvc:annotation-driven>
  2. <mvc:message-converters register-defaults="true">
  3. <bean class="org.springframework.http.converter.StringHttpMessageConverter">
  4. <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
  5. </bean>
  6. </mvc:message-converters>
  7. </mvc:annotation-driven>

方案三:
重写一个MessageConverter,然后注册到AnnotationMethodHandlerAdapter

  1. package com.h5.common.converter;
  2.  
  3. import org.springframework.http.HttpInputMessage;
  4. import org.springframework.http.HttpOutputMessage;
  5. import org.springframework.http.MediaType;
  6. import org.springframework.http.converter.AbstractHttpMessageConverter;
  7. import org.springframework.util.StreamUtils;
  8.  
  9. import java.io.IOException;
  10. import java.io.UnsupportedEncodingException;
  11. import java.nio.charset.Charset;
  12. import java.util.ArrayList;
  13. import java.util.List;
  14.  
  15. public class EncodingAdapter extends AbstractHttpMessageConverter < String > {
  16. public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
  17. private final Charset defaultCharset;
  18. private final List < Charset > availableCharsets;
  19. private boolean writeAcceptCharset;
  20.  
  21. public EncodingAdapter() {
  22. this(DEFAULT_CHARSET);
  23. }
  24.  
  25. public EncodingAdapter(Charset defaultCharset) {
  26. super(new MediaType[]{
  27. new MediaType("text", "plain", defaultCharset),
  28. MediaType.ALL
  29. });
  30. this.writeAcceptCharset = true;
  31. this.defaultCharset = defaultCharset;
  32. this.availableCharsets = new ArrayList(Charset.availableCharsets().values());
  33. }
  34.  
  35. public void setWriteAcceptCharset(boolean writeAcceptCharset) {
  36. this.writeAcceptCharset = writeAcceptCharset;
  37. }
  38.  
  39. public boolean supports(Class < ? > clazz) {
  40. return String.class == clazz;
  41. }
  42.  
  43. protected String readInternal(Class < ? extends String > clazz, HttpInputMessage inputMessage)throws IOException {
  44. Charset charset = this.getContentTypeCharset(inputMessage.getHeaders().getContentType());
  45. return StreamUtils.copyToString(inputMessage.getBody(), charset);
  46. }
  47.  
  48. protected Long getContentLength(String str, MediaType contentType) {
  49. Charset charset = this.getContentTypeCharset(contentType);
  50.  
  51. try {
  52. return Long.valueOf((long)str.getBytes(charset.name()).length);
  53. } catch (UnsupportedEncodingException var5) {
  54. throw new IllegalStateException(var5);
  55. }
  56. }
  57.  
  58. protected void writeInternal(String str, HttpOutputMessage outputMessage)throws IOException {
  59. if (this.writeAcceptCharset) {
  60. outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
  61. }
  62.  
  63. Charset charset = this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
  64. StreamUtils.copy(str, charset, outputMessage.getBody());
  65. }
  66.  
  67. protected List < Charset > getAcceptedCharsets() {
  68. return this.availableCharsets;
  69. }
  70.  
  71. private Charset getContentTypeCharset(MediaType contentType) {
  72. return contentType != null && contentType.getCharSet() != null ? contentType.getCharSet() : this.defaultCharset;
  73. }
  74. }

//注册方法一:

  1. <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  2. <property name="messageConverters">
  3. <util:list>
  4. <bean class="com.ctrip.hotel.h5.common.converter.EncodingAdapter ">
  5. <constructor-arg index="0" value="UTF-8"/>
  6. </bean>
  7. </util:list>
  8. </property>
  9. </bean>

//注册方法二:
在webconfig.java中:

  1. @Override
  2. public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
  3.   EncodingAdapter stringConverter = new EncodingAdapter();
  4.   converters.add(0, stringConverter);
  5. }

方案四:

直接新建一个如下的类,放入代码即可。

  1. package com.h5.common.encode;
  2.  
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.beans.factory.config.BeanPostProcessor;
  5. import org.springframework.http.MediaType;
  6. import org.springframework.http.converter.HttpMessageConverter;
  7. import org.springframework.http.converter.StringHttpMessageConverter;
  8. import org.springframework.stereotype.Component;
  9. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
  10. import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
  11.  
  12. import java.nio.charset.Charset;
  13. import java.util.Arrays;
  14. import java.util.List;
  15.  
  16. /**
  17. * Created by xingyuzhu on 2017/2/27.
  18. * 解决@ResponseBody返回的响应中中文乱码问题.
  19. */
  20. @Component
  21. public class EncodingPostProcessor implements BeanPostProcessor {
  22. @Override
  23. public Object postProcessBeforeInitialization(Object bean, String beanName)
  24. throws BeansException{
  25. if (bean instanceof RequestMappingHandlerAdapter) {
  26. List < HttpMessageConverter < ? >> convs = ((RequestMappingHandlerAdapter)bean).getMessageConverters();
  27. for (HttpMessageConverter < ? > conv : convs) {
  28. if (conv instanceof StringHttpMessageConverter) {
  29. ((StringHttpMessageConverter)conv).setSupportedMediaTypes(
  30. Arrays.asList(new MediaType("text", "html",
  31. Charset.forName("UTF-8"))));
  32. }
  33. }
  34. }
  35. if (bean instanceof RequestResponseBodyMethodProcessor) {
  36. List < HttpMessageConverter < ? >> convs = ((RequestMappingHandlerAdapter)bean).getMessageConverters();
  37. for (HttpMessageConverter < ? > conv : convs) {
  38. if (conv instanceof StringHttpMessageConverter) {
  39. ((StringHttpMessageConverter)conv).setSupportedMediaTypes(
  40. Arrays.asList(new MediaType("text", "html",
  41. Charset.forName("UTF-8"))));
  42. }
  43. }
  44. }
  45. return bean;
  46. }
  47.  
  48. @Override
  49. public Object postProcessAfterInitialization(Object bean, String beanName)
  50. throws BeansException{
  51. return bean;
  52. }
  53. }

方案五:
在我们的webconfig.java中,注册一个bean:该方法有缺陷RequestMappingHandlerAdapter中的其他messageconverter丢失,导致其他问题,比如返回的是一个jsp页面,就会挂掉

  1. @Bean
  2. public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
  3. RequestMappingHandlerAdapter reqMapHAdapter = new RequestMappingHandlerAdapter();
  4. ArrayList < HttpMessageConverter < ? >> msgConvs = new ArrayList < > ();
  5. StringHttpMessageConverter stringConverter = new
  6. StringHttpMessageConverter(Charset.forName("UTF-8"));
  7. stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
  8. msgConvs.add(stringConverter);
  9. reqMapHAdapter.setMessageConverters(msgConvs);
  10. return reqMapHAdapter;
  11. }

方案六:
在webconfig.java中:

  1. @Override
  2. public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
  3.   StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
  4.   converters.add(0, stringConverter);
  5. }

方案七:(篡改框架的编码,推荐使用)
在webconfig.java中,篡改一下StringHttpMessageConverter的编码方式

  1. @Override
  2. public void extendMessageConverters(List < HttpMessageConverter < ? >> converters) {
  3. HttpMessageConverter converter = Iterables.find(converters, new Predicate < HttpMessageConverter < ? >> () {
  4. @ Override
  5. public boolean apply( @ Nullable HttpMessageConverter < ? > input) {
  6. return input != null && input instanceof StringHttpMessageConverter;
  7. }
  8. }, null);
  9. if (converter == null) {
  10. StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
  11. stringConverter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "html", Charset.forName(UTF8))));
  12. converters.add(1, stringConverter); //默认的StringHttpMessageConverter在第二个位置
  13. return;
  14. }
  15. StringHttpMessageConverter stringHttpMessageConverter = (StringHttpMessageConverter)converter;
  16. stringHttpMessageConverter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "html", Charset.forName(UTF8))));
  17. }

Spring MVC @ResponseBody响应中文乱码的更多相关文章

  1. Spring下@ResponseBody响应中文内容乱码问题

    引言: 在JQuery的Ajax请求中,收到的基于后台返回回来的结果出现乱码,在后台其内容正确,到了前台之后,确是乱码??????,该怎样解决呢? 1.  问题的提出 前端基于JQuery的Ajax进 ...

  2. 解决Spring MVC @ResponseBody返回中文字符串乱码问题

    spring mvc使用的默认处理字符串编码为ISO-8859-1 解决方法: 第一种方法: 对于需要返回字符串的方法添加注解,如下: @RequestMapping(value="/use ...

  3. spring mvc get请求中文乱码问题

    使用Spring MVC进行get请求时发现get请求带上中文参数,后台收到的是乱码,即使加了encoding filter也没用. 原因是,encoding filter 是针对post请求的,to ...

  4. Spring MVC @ResponseBody返回中文字符串乱码问题

    朋友做小项目练手的时候遇到的,着实让他郁闷够呛..这个问题的确很恶心.. 项目中引用的json包,直接用@ResponseBody注解返回json字符串..有关这个的乱码问题网上很多,各种花样各种转码 ...

  5. 解决Spring MVC @ResponseBody出现问号乱码问题

    原因是SpringMVC的@ResponseBody使用的默认处理字符串编码为ISO-8859-1,而我们前台或者客户端的编码一般是UTF-8或者GBK.现将解决方法分享如下! 第一种方法: 对于需要 ...

  6. spring mvc后台接收中文乱码

    可从如下几方面着手 1.jsp页面编码 2.web.xml配置字符过滤器,该字符过滤器最好放在开头 3.tomcat下server.xml添加URIEncoding="UTF-8" ...

  7. spring mvc请求参数中文乱码解决方案

    POST 请求 在web.xml中加上增加过滤器 <filter> <filter-name>encodingFilter</filter-name> <fi ...

  8. 1、spring mvc jsp页面中文乱码

    jsp 页面头部 的page标签中加个 contentType="text/html;charset=utf-8"

  9. Springboot @ResponseBody返回中文乱码

    最近我在把Spring 项目改造Springboot,遇到一个问题@ResponseBody返回中文乱码,因为response返回的content-type一直是application/json;ch ...

随机推荐

  1. Linux中一些约定俗成的文件扩展名

    注:Linux中的所有内容均以文件的形式保存,但不依靠扩展名区分文件类型(根据权限区分),约定俗成的文件扩展名是为了方便管理员对文件进行区分 压缩包:“*.gz”.“*.bz2”.“*.tar.bz2 ...

  2. 企业级监控nagios实践

    nagios 监控服务应用指南 小区:视频监控,保安 企业工作中为什么要部署监控系统 监控系统相当于哨兵的作用,监控几百台上千台服务器,监控系统非常重要. 监控系统都需要监控 1. 本地资源:负载up ...

  3. 【MVC】使用笔记

    1,在ASP.NET MVC中,路由机制特别碉堡,直接对应于动作方法.没有必要给每一个动作方法添加视图,当视图返回View时,路由系统会自动寻找指定目录下的视图资源. public ViewResul ...

  4. python+RobotFramework

    今天有人问我,她想在在robot里面用到数据库的一个值的随机数,但是不知道怎么实现,我用python写了一段代码链接数据库给表中所需的字段的值取随机数,代码如下: import random,pymy ...

  5. LibreOJ2302 - 「NOI2017」整数

    Portal Description 有一个整数\(x=0\),对其进行\(n(n\leq10^6)\)次操作: 给出\(a(|a|\leq10^9),b(b\leq30n)\),将\(x\)加上\( ...

  6. VirtualBox - 虚拟机下主机与虚拟机、虚拟机与虚拟机之间通信配置

    看了一下网上别人写的文章:http://www.it165.net/os/html/201401/7063.html 文章里面使用的是Debian,我这里配置的虚拟机系统一个是Ubuntu 14.10 ...

  7. csu 1600: Twenty-four point

    传送门 1600: Twenty-four point Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 490  Solved: 78[Submit][S ...

  8. HDU 5360 【优先队列+贪心】

    题意: 给定N个无序区间. 对合法区间的定义是: 在这个区间之前已经选出了至少l个合法区间,最多选出了r个合法区间.则该区间为合法区间. 输出最多能挑选出多少个合法区间,并输出合法区间的数量. 思路: ...

  9. 分享一下然让显卡满血复活的小技巧(GTX)

    分享一下然让显卡满血复活的小技巧 笔者在玩大型游戏卡顿15fps下载如下操作 GTX950玩大型游戏都不会卡帧率稳定在30fps 下载GeForce Experience下载更新最新驱动 下载如下程序 ...

  10. oracle字段的所有类型

    字段类型    中文说明    限制条件    其它说明 CHAR    固定长度字符串    最大长度2000    bytes VARCHAR2    可变长度的字符串    最大长度4000   ...