转载自:http://www.cnblogs.com/shanrengo/p/6429291.html

问题背景

  本文并不是介绍@ResponseBody注解,也不是中文乱码问题的大汇总笔记,这些网上都有很多内容了。这边仅对几年前,一个卡壳了挺久时间的问题的解决过程做一个记录,以警惕自己,达到自醒得目的。  

  @ReponseBody 注解不用多介绍了,用过SpringMVC的同学都很熟了,@ResponseBody 将内容或对象作为 HTTP 响应正文返回,使用@ResponseBody将会跳过视图处理部分,而是调用适合的HttpMessageConverter,将返回值写入输出流。在日常工作中,通常使用封装好的ViewModel进行后台数据的返回,一切正常。但一次在使用@ReponseBody进行返回String数据的时候,竟会出现中文乱码。

  编程的过程免不了遇到各种问题,而遇到问题然后解决问题的这个过程我认为是最让人兴奋的事情。越棘手的问题,解决以后带来的快感也越大(PS:当然解决不了的话,就会越烦躁。。),还是言归正传,谈一下解决错误的过程。

问题分析

  最早我一直以为Spring配置一下编码过滤器就可以解决任何中文乱码问题,代码如下: 恩,确实一直是这样设置着,然并卵。

<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

  直接返回String会乱码,而返回ViewModel的那个不会乱码,这是为什么?

  其实也可以说是SpringMVC的一个bug,SpringMVC有一系列HttpMessageConverter去处理用@ResponseBody注解的返回值,如返回VM则使用MappingJacksonHttpMessageConverter,若返回String,则使用StringHttpMessageConverter,这个convert使用的是字符集是iso-8859-1,而且是final的,如下:

public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); 

  既然是String有问题,那自然就直接从适配器AnnotationMethodHandlerAdapter 的字符串解析器 StringHttpMessageConverter 入手,设置编码类型即可?

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
...

  NO!

那万金油response.setContentType("text/html; charset=UTF-8");呢?NO!

  那么重写StringHttpMessageConverter应该可以了吗?NO!

  上面方法都不行,就尝试着各种百度,说法多种多样,但答案还是:NO!

问题解决

  恩,看来我们得从源头开始再理一遍,既然问题在解析器,那么可以从配置文件配置解析器的配置文件入手。mvc-config.xml 文件从上到下:控制层扫描、国际化配置、文件上传表单解析器、自定义拦截器、视图配置。好像都不是,继续往下,一些HandlerMapping和HandlerAdapter,还有一句<mvc:annotation-driven/>。

  网上查阅了一下资料,果然发现问题其实就在这句<mvc:annotation-driven/>。

  <mvc:annotation-driven /> 是一种简写模式,它会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的,并且提供了其他一些支持。。。略

  上面使用为StringHttpMessageConverter设置编码模式其实正常是有效的,但是在使用了<mvc:annotation-driven />语句后,再次显示声明其他bean,可能就无效了。

<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

扩展:其他解决方案

  除了使用上面那种方案之外,还可以使用下面的: 

  1、完全不使用String返回,直接都通过统一的ViewModel去返回,如ResultModel等(正常也是这么干的,总还要错误信息等吧);
  2、通过@RequestMapping的属性处理,该注解的属性produces用于指定返回的内容类型,这算肯定可以了,代码如下:

@RequestMapping(value="/test", method=RequestMethod.POST, produces="text/html;charset=UTF-8")

  注意:既然使用了配置<mvc:annotation-driven>,还是建议在该配置内部进行处理。

编后语

   上面的问题记录是很多多年前的了,现在翻到博客上,只是为了告诫自己:

  天下文章一大抄,但是抄来抄去,不管是写的人,还是看的人,自己最好都能理解或者亲自去尝试一下;这个乱码问题网上总结太多太多了,不能说是错误的,但是又有几个正确得说清楚呢?

  如果放在现在来解决这个问题,最好的方案还是直接跟一下SpringMVC的源码,简单明了。String类型的返回值处理会进入StringHttpMessageConverter解析器,观察getContentTypeCharset方法的参数,可以看到当前解析编码是text/plain;charset=ISO-8859-1,即设置不成功,设置不成功可以继续看看适配器AnnotationMethodHandlerAdapter的属性设置,一层层反推,总会发现问题的。

  这里奉劝各位兄弟姐妹,网上的东西还是要仔细研究的,不要转来转去的。

《经久不衰的Spring框架:@ResponseBody 中文乱码》(转)的更多相关文章

  1. 转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》

    作者 | Vincent Mühle 编译 | 姗姗 出品 | 人工智能头条(公众号ID:AI_Thinker) [导读]随着深度学习方法的应用,浏览器调用人脸识别技术已经得到了更广泛的应用与提升.在 ...

  2. face-api.js:一个在浏览器中进行人脸识别的 JavaScript 接口

    Mark! 本文将为大家介绍一个建立在「tensorflow.js」内核上的 javascript API——「face-api.js」,它实现了三种卷积神经网络架构,用于完成人脸检测.识别和特征点检 ...

  3. TensorFlow.js之安装与核心概念

    TensorFlow.js是通过WebGL加速.基于浏览器的机器学习js框架.通过tensorflow.js,我们可以在浏览器中开发机器学习.运行现有的模型或者重新训练现有的模型. 一.安装     ...

  4. 在Java中直接调用js代码(转载)

    http://blog.csdn.net/xzyxuanyuan/article/details/8062887 JDK1.6版添加了新的ScriptEngine类,允许用户直接执行js代码. 在Ja ...

  5. 第十一章:WEB浏览器中的javascript

    客户端javascript涵盖在本系列的第二部分第10章,主要讲解javascript是如何在web浏览器中实现的,这些章节介绍了大量的脚本宿主对象,这些对象可以表示浏览器窗口.文档树的内容.这些章节 ...

  6. 在Java中直接调用js代码

    JDK1.6版添加了新的ScriptEngine类,允许用户直接执行js代码. 在Java中直接调用js代码 不能调用浏览器中定义的js函数,会抛出异常提示ReferenceError: “alert ...

  7. TensorFlow.js入门(一)一维向量的学习

    TensorFlow的介绍   TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理.Tensor(张量)意味着N维数组,Flow(流)意味着 ...

  8. JavaScript权威指南--WEB浏览器中的javascript

    知识要点 1.客户端javascript window对象是所有客户端javascript特性和API的主要接入点.它表示web浏览器的一个窗口或窗体,并且可以用window表示来引用它.window ...

  9. 解决webkit浏览器中js方法中使用window.event提示未定义的问题

    这实际上是一个浏览器兼容性问题,根源百度中一大堆,简要说就是ie中event对象是全局变量,所以哪里都能使用到,但是webkit内核的浏览器中却不存在这个全局变量event,而是以一个隐式的局部变量的 ...

  10. JS Date当前时间:获取日期时间方法在各浏览器中的差异

    转自:http://www.feiesoft.com/00047/<script type="text/javascript"> // JS Date当前时间获取方法在 ...

随机推荐

  1. linux nexus bulid

    1. 将下载好的nexus-2.5.1-bundle.tar.gz包,用FTP工具传至服务器上. 2. 解压安装包 解压命令: ? 1     tar -zvxf nexus-2.5.1-bundle ...

  2. 从事务隔离级别谈到Hibernate乐观锁,悲观锁

    数据库的事务,是指作为单个逻辑工作单元执行的一系列操作. 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源.通过将一组相关操作组合为一个要么全部成功要么全部失败的单 ...

  3. S3C2440串口的基本使用

    2440A有三个串口,我们使用串口0对它进行了解熟悉. 首先肯定是应该找到手册上串口0所对应的引脚,然后配置相应寄存器. 串口0对应GPIO H的 2,3 串口在单片机中我们已经有很多使用经验了,对于 ...

  4. 使用卷积神经网络CNN训练识别mnist

    算的的上是自己搭建的第一个卷积神经网络.网络结构比较简单. 输入为单通道的mnist数据集.它是一张28*28,包含784个特征值的图片 我们第一层输入,使用5*5的卷积核进行卷积,输出32张特征图, ...

  5. 基于jQuery鼠标点击弹出登陆框效果

    基于jQuery鼠标点击弹出登陆框效果.这是一款扁平样式风格的jQuery弹出层登陆框特效.效果图如下: 在线预览   源码下载 实现的代码. html代码: <input type=" ...

  6. 【转】全Javascript的Web开发架构:MEAN和Yeoman【译】

    引言 最近在Angular社区的原型开发者间,一种全Javascript的开发架构MEAN正突然流行起来.其首字母分别代表的是:(M)ongoDB——noSQL的文档数据库,使用JSON风格来存储数据 ...

  7. 【进阶修炼】——改善C#程序质量(6)

    90,不应为抽象类指定public的构造函数. 抽象类即使指定了public的构造函数,也是不能实例化的,编译通不过.抽象类的构造函数应该设定为protected,它的作用应该是初始化自己的成员,以及 ...

  8. linux软件管理(六)

    [教程主题]:linux软件管理 [1]软件包管理 在系统管理中,软件包的管理是最重要的,是系统管理的基础的基础, 只有我们学会软件包的管理才能谈得上其它的应用. RPM RPM是软件管理程序,提供软 ...

  9. 从PCD文件写入和读取点云数据

    (1)学习向PCD文件写入点云数据 建立工程文件ch2,然后新建write_pcd.cpp  CMakeLists.txt两个文件 write_pcd.cpp : #include <iostr ...

  10. 分治算法--寻找第k大数

    问题描述:给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k大的元素,(这里给定的线性集是无序的). 其实这个问题很简单,直接对线性序列集qsort,再找出第k个即可.但是这样的 ...