zoukankan      html  css  js  c++  java
  • [Spring MVC] @ResponseBody返回结果乱码问题的解决

    发现问题

    在Controller类方法上加@ResponseBody,直接返回字符串。结果乱码。
    例如以下所看到的:

    MockHttpServletResponse:
                  Status = 200
           Error message = null
                 Headers = {Content-Type=[text/plain;charset=ISO-8859-1], Content-Length=[45]}
            Content type = text/plain;charset=ISO-8859-1
                    Body = {
     "Msg":"????

    ????

    ??????

    ?nameEntTypeCode?

    ?

    "
    }

    用浏览器訪问也是乱码。

    分析问题

    1、分析日志

    日志级别设为DEBUG,查看日志。节选例如以下:
    (1)
     <Method [handleRuleException] returned [{
     "Msg":"调用时规则时未传入必要參数:“nameEntTypeCode”。

    "
    }]>
    到这里还是对的。Handle调用完毕。获得了返回值。接下来归View了。


    (2)
    ModelAndViewMethodReturnValueHandler@12eae9c] supports [class java.lang.String]>
    web.method.annotation.ModelMethodProcessor@12c50a4] supports [class java.lang.String]>
    web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler@56a5b] supports [class java.lang.String]>
    web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@9463a0] supports [class java.lang.String]>
    web.method.annotation.ModelAttributeMethodProcessor@1aad6f4] supports [class java.lang.String]>
    web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@1c45fa4] supports [class java.lang.String]>
    快找到元凶了。
    accept.PathExtensionContentNegotiationStrategy$JafMediaTypeFactory]
            Loading Java Activation Framework FileTypeMap from class path resource
                    [org/springframework/mail/javamail/mime.types]    //默认支持的类型是从这里读取的

    mvc.method.annotation.AbstractMessageConverterMethodProcessor<Written [{
    "Msg":"调用时规则时未传入必要參数:“nameEntTypeCode”。"
    }] as "text/plain;charset=ISO-8859-1" using [org.springframework.http.converter.StringHttpMessageConverter@1efa83c]>
    找到元凶。他是如何作案的呢?
    我猜。大概是StringHttpMessageConverter注入了AbstractMessageConverterMethodProcessor。
    “text/plain;charset=ISO-8859-1”是StringHttpMessageConverter的属性。

    2、尝试解决

    (1)AbstractMessageConverterMethodProcessor是抽象类,在StringHttpMessageConverter上想办法。
    (2)
    假设org.springframework.http.converter.StringHttpMessageConverter是单例,能够自己配置一下看看
    <bean id="stringHttpMessageConverter"
      class="org.springframework.http.converter.StringHttpMessageConverter">
      <property name="supportedMediaTypes">
       <list>
        <value>text/plain;charset=UTF-8</value>
       </list>
      </property>
     </bean>
     在<xxx>-servlet.xml中配置无效。

    确认放在<mvc:annotation-driven>之前了。


     (3)注入的姿势不正确,还是老实看看Spring源码吧

    3、寻找注入口

    (1)
     RequestMappingHandlerAdapter构造函数中:
     public RequestMappingHandlerAdapter() {
           StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
           ...
          this.messageConverters.add(stringHttpMessageConverter);
     }
     直接这么new啊。太粗暴了。
     这仅仅是默认行为,应该有覆盖办法的。


    (2)
     跟代码。跟到
     private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
      List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

      // Single-purpose return value types
      handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));

      // Annotation-based return value types
      handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
    }
     
     然后找到:
      public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
              this.messageConverters = messageConverters;
     }

    (3)

    试试看:
     <mvc:annotation-driven>
         <mvc:message-converters>
             <bean class="org.springframework.http.converter.StringHttpMessageConverter">
              <property name="supportedMediaTypes">
         <list>
          <value>text/plain;charset=UTF-8</value>
         </list>
        </property>
             </bean>
         </mvc:message-converters>
     </mvc:annotation-driven>
     
    这就是老版本号的报错吧:
    cvc-complex-type.2.1: 元素 'mvc:annotation-driven' 必须不含字符或元素信息项 [子级], 由于该类型的内容类型为空。
    看mvc命名空间中xsd版本号。
    好吧,就是这里:
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd

    (4)

    修正,好了:
    MockHttpServletResponse:
                  Status = 200
           Error message = null
                 Headers = {Content-Type=[text/plain;charset=UTF-8], Content-Length=[79]}
            Content type = text/plain;charset=UTF-8
                    Body = {
     "Msg":"调用时规则时未传入必要參数:“nameEntTypeCode”。"
    }
           Forwarded URL = null
          Redirected URL = null
                 Cookies = []

    总结

    1、遇到问题多看日志,多看代码。

    2、Spring MVC注入口非常多,太爽了,但应该慎重使用,考虑影响范围。

    3、HttpMessageConverter是神器,能够完毕传入參数和返回值的转换。通过自己定义Media Type可实现奇妙效果,有机会好好研究下。

  • 相关阅读:
    TXSQL:云计算时代数据库核弹头——云+未来峰会开发者专场回顾
    游戏场景下的DDoS风险分析及防护
    一站式机器学习平台TI-ONE是什么?——云+未来峰会开发者专场回顾
    带有Apache Spark的Lambda架构
    攻克数据库核心技术壁垒,实现百万级QPS的高吞吐
    想学大数据?大数据处理的开源框架推荐
    可怕!数据库竟然打破安迪-比尔定律
    什么?云数据库也能C位出道?
    协同过滤的R语言实现及改进
    Android代码规范----按钮单击事件的四种写法
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7065286.html
Copyright © 2011-2022 走看看