SpringMVC使用@ResponseBody输出字符串时遇到的乱码问题及解决办法

我们需要保持编码或者解码两头,所使用的字符集转换方向需要正好相反:使用 GBK --> UTF-8 与 UTF-8 --> GBK。由于Java采用了UTF-8编码,所以编码解码均以UTF-8为中介。 
对于翻译而言,就是先相当于: 先 中译英,对应的解码,反过来就是 英译中。 

遇到乱码问题,通常的检查项包括: 
1. 编辑器保存文件的字符集; 
2. 数据库的字符集; 
3. 应用服务器或者Web服务器处理字符串采用的字符集 
4. JSP对于字符集声明 
5. Servlet过滤器,以及MVC框架拦截器对于字符集的处理 
6. 其它涉及字符集处理的环节 

检查各个环节,统一按UTF-8设置。推断我这次碰到的问题属于上述第6中情况。 

因为是通过SpringMVC提供的注解@ResponseBody来返回一个JSON字符串,然后在客户端上解析JSON(现如今以JSON作为数据交换格式貌似越来越时髦了,客户端我用的比较多的是jqGrid或者ExtJS)。 

Controller代码如下: 

Java代码   收藏代码
  1. @Controller  
  2. @RequestMapping("/*")  
  3. public class HelloController {  
  4.     private transient final Log log = LogFactory.getLog(HelloController.class);  
  5.       
  6.     @Autowired  
  7.     private UserManager mgr = null;  
  8.       
  9.     @RequestMapping(value="hello_list.do", method = RequestMethod.POST)  
  10.     @ResponseBody  
  11.     public String helloList() {  
  12.         StringBuilder str = new StringBuilder("{totalProperty:100,root:[");  
  13.           
  14.         List<User> users = mgr.getUsers();  
  15.         for (User user : users) {  
  16.             str.append("{id: ").append(user.getId());  
  17.             str.append(", name:'").append(user.getLastName());  
  18.             str.append("', descn:'").append(user.getFullName()).append("'},");  
  19.         }  
  20.         str.append("{id:4, name:'생활', descn:'Китай'},");  
  21.         str.append("{id:5, name:'tchen8', descn:'中文'}]}");  
  22.           
  23.         log.info(str.toString());  
  24.           
  25.         return str.toString();  
  26.     }  
  27.   
  28. }  



在Spring配置文件里,默认如下: 

Xml代码   收藏代码
  1. <!-- Enables the Spring MVC @Controller programming model -->  
  2. <mvc:annotation-driven />  



调试程序,控制台输出日志看到是中文,但是在firebug中看到的服务器端送过来的字符串是???? (如果是 "口口口"这样的输出,需要先排除是否为系统的字体缺失),于是判断是服务器最后往端口写字符串流的时侯字符集不对。 

通过调试跟踪Spring的源码,声明@ResponseBody时,Spring会通过AnnotationMethodHandlerAdapter去寻找对应的HttpMessageConverter, 我们这里声明返回的类型是String,于是对应StringHttpMessageConverter。通过实验,猜测这个StringHttpMessageConverter也就是<mvc:annotation-driven />触发的默认的字符串转换工作类。 

比较不幸的是,StringHttpMessageConverter所使用的默认字符集是ISO-8859-1 

Java代码   收藏代码
  1. ......  
  2. public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {  
  3.   
  4.     public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");  
  5. ......  



这里不得不提的是与StringHttpMessageConverter 同级的类MappingJacksonHttpMessageConverter,天知道是什么原因:同一个作者,对于这两个类,默认字符集一个是ISO-8859-1,一个是UTF-8。 

既然事已如此,那就想办法把这个地方用到的ISO-8859-1也改成UTF-8了。有两个思路: 
1. 替换默认字符集; 
2. 替换StringHttpMessageConverter 

搜索了一下,先看到这个解决办法: 
http://forum.springsource.org/showthread.php?t=81858 
这里提供的是使用一个所谓的ConfigurableStringHttpMessageConverter来替代StringHttpMessageConverter,基本的思路技术是:由于StringHttpMessageConverter中的默认字符集变量声明为final,无法直接通过继承去覆盖,那就把StringHttpMessageConverter照抄一遍,构造函数中新增一个代表字符集的输入参数,然后在配置文件里面通过构造方法注入UTF-8。在配置文件中,将这个Bean声明在<mvc:annotation-driven />前面,从而能够先于StringHttpMessageConverter被Spring识别和注入。 

但是这个方法多少有些蛮干的味道,基于它简化的一个版本可以如下,即通过继承StringHttpMessageConverter,然后在子类中注入我们想要的字符集配置: 

Java代码   收藏代码
  1. public class MyStringHttpMessageConverter extends StringHttpMessageConverter {  
  2.   
  3.     public MyStringHttpMessageConverter(Charset defaultCharset) {  
  4.         List<MediaType> mediaTypeList = new ArrayList<MediaType>();  
  5.         mediaTypeList.add(new MediaType("text", "plain", defaultCharset));  
  6.         mediaTypeList.add(MediaType.ALL);  
  7.         super.setSupportedMediaTypes(mediaTypeList);  
  8.     }  
  9.       
  10. }  



Bean的配置依然类似: 

Xml代码   收藏代码
  1. ...  
  2. ...  
  3.     <beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
  4.         <beans:property name="messageConverters">  
  5.             <util:list>  
  6.                 <beans:bean id="stringHttpMessageConverter" class="org.tchen8.myapp.common.ConfigurableStringHttpMessageConverter">  
  7.                     <beans:constructor-arg value="UTF-8" />  
  8.                 </beans:bean>  
  9.             </util:list>  
  10.         </beans:property>  
  11.     </beans:bean>  
  12.   
  13.     <!-- Enables the Spring MVC @Controller programming model -->  
  14.     <mvc:annotation-driven />  
  15. ...  
  16. ...  



上面的办法是以属性注入的方式,替换了默认的字符集,但为此也需要把converter替换。 



另外一个比较简洁的办法,则不需要自己写converter类,而是直接通过属性注入,修改StringHttpMessageConverter的默认配置。 

Xml代码   收藏代码
  1. ...  
  2.     <beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">    
  3.         <beans:property name="messageConverters">    
  4.             <util:list>    
  5.                 <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter">    
  6.                     <beans:property name="supportedMediaTypes">    
  7.                         <util:list>  
  8.                             <beans:value>text/html;charset=UTF-8</beans:value>  
  9.                         </util:list>    
  10.                     </beans:property>    
  11.                 </beans:bean>    
  12.             </util:list>    
  13.         </beans:property>    
  14.     </beans:bean>  
  15. ...  


上面的这个办法,实际上通过setSupportedMediaTypes方法,其实也就是StringHttpMessageConverter在类注释中所提到的办法: 



如果再多看一下StringHttpMessageConverter的源码,可以到它的父类中AbstractHttpMessageConverter有这么个方法: 

Java代码   收藏代码
  1. ...  
  2.     /** 
  3.      * Returns the default content type for the given type. Called when {@link #write} 
  4.      * is invoked without a specified content type parameter. 
  5.      * <p>By default, this returns the first element of the 
  6.      * {@link #setSupportedMediaTypes(List) supportedMediaTypes} property, if any. 
  7.      * Can be overridden in subclasses. 
  8.      * @param t the type to return the content type for 
  9.      * @return the content type, or <code>null</code> if not known 
  10.      */  
  11.     protected MediaType getDefaultContentType(T t) {  
  12.         List<MediaType> mediaTypes = getSupportedMediaTypes();  
  13.         return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null);  
  14.     }  
  15. ...  



注释中写的明白:"Can be overridden in subclasses." 那就不必客气了。于是我们大概也能有如下的做法: 

Java代码   收藏代码
  1. ...  
  2. public class MyStringHttpMessageConverter2 extends StringHttpMessageConverter {  
  3.       
  4.     private static final MediaType utf8 = new MediaType("text", "plain", Charset.forName("UTF-8"));   
  5.   
  6.     @Override  
  7.     protected MediaType getDefaultContentType(String dumy) {  
  8.         return utf8;  
  9.     }  
  10.       
  11. }  
  12. ...  


对应的配置: 

Xml代码   收藏代码
  1. <beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
  2.     <beans:property name="messageConverters">  
  3.         <util:list>  
  4.             <beans:bean id="myStringHttpMessageConverter2" class="org.tchen8.myapp.common.MyStringHttpMessageConverter2" />  
  5.         </util:list>  
  6.     </beans:property>  
  7. </beans:bean>   
  8.   
  9. <!-- Enables the Spring MVC @Controller programming model -->  
  10. <mvc:annotation-driven />  



以上的几个方法,都能解决@ResponseBody导致的乱码问题,虽然StringHttpMessageConverter将来确实有可能把默认字符集修改成UTF-8,从而导致上述功夫最后变成白忙活。但也确实感谢有这么个小阻碍,迫使自己去分析问题寻找答案。收获不在于结果,而在过程吧 

《PCI Express体系结构导读1》-- PCI简介 请先阅读完一遍此书再来看文章哦,这样效率更高~ 阅读详情

相关推荐

5分钟搞定!用FunASR在本地快速部署达摩院Paraformer语音识别模型(附常见问题解决)

本文详细介绍了如何在本地快速部署阿里达摩院开源的Paraformer语音识别模型。通过FunASR工具包,用户可在5分钟内完成环境配置、模型下载与基础识别,并掌握批量处理、性能调优及构建API服务等进阶技巧。文章重点解析了Paraformer的非自回归架构带来的速度优势,并提供了音频格式转换、依赖冲突、显存不足等常见问题的实战解决方案,助力开发者实现高效、离线的语音转写应用。

p1q2r的博客 705

request、response 中文乱码问题与解决方式

request乱码指的是:浏览器向服务器发送的请求参数中包含中文字符,服务器获取到的请求参数的值是乱码; response乱码指的是:服务器向浏览器发送的数据包含中文字符,浏览器中显示的是乱码; 乱码产生的原因:不管是request乱码还是response乱码,其实都是由于客户端(浏览器)跟服务器端采用的编码格式不一致造成的。以request乱码为例:浏览器向服务器发...

ddak56357的博客 2638

百度API实现人流量数量检测(动态)

百度的这个API还挺好用的,对与不追求高精度的人来说非常适用,结合他官方给的文档,极易上手。 需要做的就是通过API Key和Secret Key获取的access_token。 然后稍微修改下代码就行,但是他给的代码并没有直接从摄像头获取视频,而是读取一个文件夹,那么就需要自己先对摄像头的输出视频进行处理。 识别结果如下,"person_num"是当前画面的人数,in是累计进入的人数,out是累计走出去的人数。 他这个有个缺点就是返回值里边并没有实时返回in和out的值,而是都是0,但是这个图片上有,图片

qq_42479987的博客 3382

四、SpringMVC获取请求参数的方式与设置编码

首先,我们从浏览器发送的请求首先会被@RequestMapping这个注解进行匹配,如果匹配成功,那么就会由我们的控制器方法来处理请求,但是也说过,我们在之前web.xml中注册前端控制器,我们浏览器发出的请求先要被前端控制器处理,之后又执行了相对应的控制器方法,所以说将我们的请求与@RequestMapping进行匹配,来找到我们的控制器方法这个过程,就是由DispatcherServlet所完成的,所以说当我们的DispatcherServlet间接调用控制器方法(中间还有其他组件),在...

qq_52971866的博客 1030

Hypack 应用于地形测量的高级设置操作要领

Hypack 是业界公认最好的水文导航测量软件,是目前世界上应用广泛的专业测量疏浚软件。它能够接收,处理,存储和输出各种数据。Hypack支持绝大部分GPS,测深仪(国内如海鹰HY1603单波束测沙仪),多波束测深仪,旁扫声纳,涌浪补偿器,水位仪,验潮仪以及声速剖面仪。利用 Hypack 可以进行导航,单波束测量,多波束测量,旁扫测量以及疏浚实时监测等。软件界面友好,使用方便。本文简要阐述Hypack 应用于地形测量的几个重要操作要领。

中游鱼的博客 2801

UM982上位机调试【精简版】

分享一些关于UM982卫导模块上位机调试的简快捷单小功能。

在线求职中... 1万+

springboot @requestbody的编码问题

最近遇到一个很蛋疼的问题,机器发来http请求,信息都放在body Data里用gb2312编码,然后后台用@RequestBody来接受,这时问题来了,机器发来的请求没有设置content-type,于是默认就是content-type:application/x-www-form-urlencoded,然后spring容器就默认设置CharacterEncoding为utf-8,来解码。更奇怪...

qq_36804701的博客 1万+

自动驾驶开发者必看:nuscenes数据集23类物体标注全解析(附避坑指南)

本文深入解析nuscenes数据集的23类物体标注系统,为自动驾驶开发者提供全面的标注规范解读和实战避坑指南。涵盖多模态数据组织、类别细分规则、属性系统应用技巧以及标注质量验证方法,帮助开发者高效利用这一标杆数据集提升模型性能。

weixin_29041767的博客 258

【转载】SpringMVC使用@ResponseBody输出字符串时遇到的乱码问题及解决办法

【转载】SpringMVC使用@ResponseBody输出字符串时遇到的乱码问题及解决办法

NoAskXD的博客 417

ubuntu18.04安装xenomai3.1(百分百成功版)

ubuntu18.04安装xenomai3.1(百分百成功版),保姆级教学!!!

h542812556sdu的博客 2065

飞牛fnNAS搭建Web网页版OFFICE(WPS)软件

本文介绍了如何在飞牛NAS上通过Docker容器部署WPS Office办公软件。主要内容包括:启用Docker服务、准备项目文件夹结构、使用Compose方式构建容器、解决端口冲突问题、配置中文输入法和字体库,以及通过ZeroTier实现远程访问。文章详细说明了每个步骤的操作方法,包括容器启动、输入法设置、字体添加和文件存储位置配置。最后还介绍了使用ZeroTier内网穿透技术实现远程访问NAS上WPS服务的方法,让用户可以在不同设备上随时编辑NAS中的文件。整个部署过程完整清晰,为NAS用户提供了便捷的

dgnankai的专栏 1702

SpringMVC使用@ResponseBody注解返回中文字符串乱码的问题

SpringMVC使用@ResponseBody注解返回中文字符串乱码的问题 spring boot没有出现问题,在别的后台项目通过form表单提交post请求,中文乱码 return "&lt;form name=\"punchout_form\" method=\"post\" action=\"" + actionUrl + " \"&gt;" + "&lt;

zhouleizhao的专栏 874

笔试题-2023-星宸-数字IC设计【纯净题目版】

4 笔试题-2023-星宸-数字IC设计【纯净题目版】

w0shishabi的博客 1172

springMVC 返回中文字符串时乱码

SpringMVC的@ResponseBody注解可以将请求方法返回的对象直接转换成JSON对象,但是当返回值是String的时候,中文会乱码,原因是因为其中字符串转换和对象转换用的是两个转换器,而String的转换器中固定了转换编码为"ISO-8859-1",网上也很多种解决方法,有通过配置Bean编码的,也有自己重写转换器的,我这里多次尝试未果,只能自己解决。 第一种:在@Reque

yaov_yy的专栏 1万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SpringMVC @ResponseBody返回中文字符串出现乱码的解决方法

在spring-mvc.xml中进行设置,将默认处理字符集改为utf-8格式

qq_57389269的博客 2574

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

SpringMVC 使用@ResponseBody返回json 中文乱码

场景    小编在springMVC框架中使用@ResponseBody注解从controller层想ajax返回String类型的参数的时候,发现中文乱码,这确实个尴尬的问题,于是小编跟踪了一下spring的源码,看了看string类型的转换问题,在这个方法中我们可以看到,spring中解析字符串的转换器默认的编码竟然是ISO-8859-1,这就是问题所在了:        既然找

Jack 架构师之路 2099

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

上一篇: RelativeLayout设置居中对齐问题
下一篇: PostgreSQL时间运算
weixir123
博客等级 码龄16年 1粉丝 207原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值