• Spring框架:@ResponseBody 中文乱码----------我的主题站内单点登录


    问题背景

      本文并不是介绍@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的属性设置,一层层反推,总会发现问题的。

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

    我今天终于有了自己的qian,欢迎lady gentlemen为我的捧场! 虽然我不认识的所有GGMM,不过我相信我的空间一定是独一无二的! 我喜欢交朋友,如果你想和我多聊一些,给我留言,发小纸条或者直接加我好友吧! 另外,如果你在其他博客上有日记或者照片,可以用(http://n.qzone.qq.com/move/move_login.htm)把它们分享生活新体验!:)
  • 相关阅读:
    物联网操作系统HelloX开发者入门指南
    【 D3.js 高级系列 】 总结
    【 D3.js 高级系列 — 10.0 】 思维导图
    android fragment+ FragmentTabHost+viewpager 切换状态不保存的问题
    OpenGL 顶点缓存对象
    OpenGL顶点数组
    【 D3.js 高级系列 — 9.0 】 交互式提示框
    如何在 Linux 上录制你的终端操作
    程序员诗词大赛开始了_你看过吗?
    程序员与代码的搞笑日常
  • 原文地址:https://www.cnblogs.com/paper-file/p/9175993.html
Copyright © 2020-2023  润新知