Java 中文乱码学习 与Spring @ResponseBody中的乱码 - Spring @ResponseBody中的乱码

来源:互联网 发布:jquery–1.4.2.min.js 编辑:程序博客网 时间:2024/06/06 02:09

如果在Spring的@Responsbody返回的内容中,发现乱码,需要从以下几方面来解决。

 

1. 确保在web.xml中配置Spring的Character Encoding Filter:

 

 

Xml代码  收藏代码
  1. <!-- Servlet Encoding Start -->  
  2.     <filter>  
  3.         <filter-name>Set Character Encoding</filter-name>  
  4.         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
  5.         <init-param>  
  6.             <param-name>encoding</param-name>  
  7.             <param-value>UTF-8</param-value>  
  8.         </init-param>  
  9.         <init-param>  
  10.             <param-name>forceEncoding</param-name>  
  11.             <param-value>true</param-value>  
  12.         </init-param>  
  13.     </filter>  
  14.     <filter-mapping>  
  15.         <filter-name>Set Character Encoding</filter-name>  
  16.         <url-pattern>/*</url-pattern>  
  17.     </filter-mapping>  
  18.     <!-- Servlet Encoding End -->  

 

 

2. 如果在@ResponseBody注释的方法下的返回值类型是String,则在结果返回给用户之前,如果在Spring的配置文件中配置了<mvc:annotation-driven />,则Spring默认会去调用一个叫StringHttpMessageConverter

的类进行内容的输出。为什么会出现乱码呢?

  解决方法1:       查看StringHttpMessageConverter的源码,发下StringHttpMessageConverter类中的默认编码是ISO-8859-1编码,改编码是西欧字符集编码,显然不会支持中文。(PS:感觉这是Spring的bug,明显应该用UTF-8嘛,我已经在Spring官网上中报了这个bug)

 

Java代码  收藏代码
  1. public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");  
  2.   
  3. private final Charset defaultCharset;  
  4.   
  5. private final List<Charset> availableCharsets;  

 

 

而且从上面的代码中可以看出,与字符相关的3个变量都是final的,意味着我们不能通过set或者构造器的注入去动态的更改上面3个值。

 

进一步分析源码可以看出,StringHttpMessageConverter继承与AbstractHttpMessageConverter<String>,分析该抽象类得,相关的操作字符编码的方法可以重写,于是我们可以自定义一个类继承StringHttpMessageConverter,然后重写相关的方法,代码如下:

 

Java代码  收藏代码
  1. /** 
  2.  *  
  3.  */  
  4. package com.chuanliu.platform.activity.basic.converter;  
  5.   
  6.   
  7.   
  8. import java.io.IOException;  
  9. import java.nio.charset.Charset;  
  10. import java.util.Arrays;  
  11. import java.util.List;  
  12.   
  13. import org.springframework.http.HttpOutputMessage;  
  14. import org.springframework.http.MediaType;  
  15. import org.springframework.http.converter.StringHttpMessageConverter;  
  16. import org.springframework.util.StreamUtils;  
  17.   
  18. /** 
  19.  * 用于处理中文乱码问题: Spring bug - 
  20.  *  
  21.  * In StringHttpMessageConverter, the default char set is ISO-8859-1(西欧字符集) 
  22.  *  
  23.  * @author Josh Wang(Sheng) 
  24.  * 
  25.  * @email  josh_wang23@hotmail.com 
  26.  */  
  27. public class UTF8StringHttpMessageConverter extends StringHttpMessageConverter {  
  28.   
  29.         private static final MediaType UTF8 = new MediaType("text""plain",   
  30.            Charset.forName("UTF-8"));  
  31.   
  32.     private boolean writeAcceptCharset = true;  
  33.       
  34.     @Override  
  35.     protected void writeInternal(String s, HttpOutputMessage outputMessage)  
  36.             throws IOException {  
  37.         if (this.writeAcceptCharset)  
  38.             outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());  
  39.           
  40.         Charset charset = UTF8.getCharSet();  
  41.           
  42.         StreamUtils.copy(s, charset, outputMessage.getBody());  
  43.           
  44.     }  
  45.   
  46.     @Override  
  47.     protected List<Charset> getAcceptedCharsets() {  
  48.         return Arrays.asList(UTF8.getCharSet());  
  49.     }  
  50.   
  51.     @Override  
  52.     protected MediaType getDefaultContentType(String t) throws IOException {  
  53.         return UTF8;  
  54.     }  
  55.   
  56.     public boolean isWriteAcceptCharset() {  
  57.         return writeAcceptCharset;  
  58.     }  
  59.   
  60.     public void setWriteAcceptCharset(boolean writeAcceptCharset) {  
  61.         this.writeAcceptCharset = writeAcceptCharset;  
  62.     }  
  63.       
  64.       
  65. }  

 

 

定义好上面的类后,只需要将该类注册到Spring的annotaion 处理序列中即可,于是当@ResponseBody中返回的类型是String类型时,Spring将会调用上面自定义类中复写的方法,从而返回UTF-8的编码:

 

 

Xml代码  收藏代码
  1. <mvc:annotation-driven>  
  2.     <mvc:message-converters register-defaults="true">  
  3.     <bean class="com.chuanliu.platform.activity.basic.converter.UTF8StringHttpMessageConverter"/>  
  4.   </mvc:message-converters>  
  5. </mvc:annotation-driven>    

 

 

解决方法2:最简单的方法:

在@Responsebody标注的方法上加上:produces="application/json;charset=utf-8"

如:

Java代码  收藏代码
  1. @RequestMapping(value="/circle/{cid}", produces="application/json;charset=utf-8")  
  2. @ResponseBody  

 

 

解决方法3:指定返回值为对象不要返回String

既然上面分析了其原因是上面的StringHttpMessageConverter类中使用了ISO-8859-1编码,那么如果业务逻辑允许,我们完全可以不要返回一个字符串(String),完全可以返回一个对象,这样Spring默认会去调用一个叫MappingJackson2HttpMessageConverter的类,该类不仅会将你返回的对象转换成JSON返回,而且该类中使用的是我们想要的UTF-8字符集,相关代码为:

 

 

Java代码  收藏代码
  1. public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");  

 

 

这种方法其实也是种很好的方法,因为更多的时候我们希望我们返回的对象直接转换成一个json字符串返回。如果你想判断Spring中最终有没有调用:MappingJackson2HttpMessageConverter或者是StringHttpMessageConverter或者是自定义的UTF8StringHttpMessageConverter的方法,你可以在这两个类的源码的writeInternal()等方法中设置断点。如果没有按期望的去调用MappingJackson2HttpMessageConverter中的writeInternal()等方法,则可能你需要配置让Spring对默认返回的视图按Json来处理,在我的应用中,我只只需要在如下的内容协商器中设置json viewer即可:

 

Xml代码  收藏代码
  1. <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">  
  2.       
  3.         <!-- 设置为true以忽略对Accept Header的支持 -->  
  4.         <property name="ignoreAcceptHeader" value="true" />  
  5.           
  6.         <!-- 在没有扩展名时即: "/user/1" 时的默认展现形式 -->  
  7.         <property name="defaultContentType" value="text/html" />  
  8.       
  9.         <!-- 扩展名至mimeType的映射,即 /user.json => application/json -->  
  10.         <property name="mediaTypes">  
  11.             <map>  
  12.                 <entry key="html" value="text/html"/>      
  13.                 <entry key="json" value="application/json" />  
  14.                 <entry key="xml" value="application/xml" />  
  15.             </map>  
  16.         </property>  
  17.       
  18.         <!-- 用于开启 /userinfo/123?format=json 的支持,false为关闭之,其实.json的方式更简洁 -->  
  19.         <property name="favorParameter" value="false" />  
  20.       
  21.         <property name="viewResolvers">  
  22.             <list>  
  23.                 <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />  
  24.                     <bean  
  25.                         class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
  26.                         <property name="prefix" value="/WEB-INF/jsp/"></property>  
  27.                         <property name="suffix" value=".jsp"></property>  
  28.                     </bean>  
  29.             </list>  
  30.         </property>  
  31.   
  32.         <<strong>property name="defaultViews">  
  33.             <list>  
  34.                 <!-- for application/json -->  
  35.                 <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />  
  36.             </list></strong>  
  37.         </property>  
  38.     </bean>   
  39.    
  40.       
  41.   
  42.     <!-- Default view resolver will be used if the upper resolve unavailable(the default format is html) -->  
  43.     <bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="3">  
  44.         <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>  
  45.         <property name="contentType" value="text/html"/>          
  46.         <property name="prefix" value="/WEB-INF/jsp/"/>  
  47.         <property name="suffix" value=".jsp"/>  
  48.     </bean>  
  49.   
  50.     <!-- json view -->  
  51. <!--     <bean id="defaultJsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/> -->  
  52.       

 

原文:http://josh-persistence.iteye.com/blog/2085015

0 0
原创粉丝点击