本文並非介紹@ResponseBody註解,也不是中文亂碼問題的大彙總筆記,這些網上都有不少內容了。這邊僅對幾年前,一個卡殼了挺久時間的問題的解決過程作一個記錄,以警戒本身,達到自醒得目的。 html
@ReponseBody 註解不用多介紹了,用過SpringMVC的同窗都很熟了,@ResponseBody 將內容或對象做爲 HTTP 響應正文返回,使用@ResponseBody將會跳過視圖處理部分,而是調用適合的HttpMessageConverter,將返回值寫入輸出流。在平常工做中,一般使用封裝好的ViewModel進行後臺數據的返回,一切正常。但一次在使用@ReponseBody進行返回String數據的時候,竟會出現中文亂碼。web
編程的過程免不了遇到各類問題,而遇到問題而後解決問題的這個過程我認爲是最讓人興奮的事情。越棘手的問題,解決之後帶來的快感也越大(PS:固然解決不了的話,就會越煩躁。。),仍是言歸正傳,談一下解決錯誤的過程。spring
最先我一直覺得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的那個不會亂碼,這是爲何?mvc
其實也能夠說是SpringMVC的一個bug,SpringMVC有一系列HttpMessageConverter去處理用@ResponseBody註解的返回值,如返回VM則使用MappingJacksonHttpMessageConverter,若返回String,則使用StringHttpMessageConverter,這個convert使用的是字符集是iso-8859-1,並且是final的,以下:app
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!url
那萬金油response.setContentType("text/html; charset=UTF-8");呢?NO!spa
那麼重寫StringHttpMessageConverter應該能夠了嗎?NO!code
上面方法都不行,就嘗試着各類百度,說法多種多樣,但答案仍是: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>
除了使用上面那種方案以外,還可使用下面的:
一、徹底不使用String返回,直接都經過統一的ViewModel去返回,如ResultModel等(正常也是這麼幹的,總還要錯誤信息等吧);
二、經過@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的屬性設置,一層層反推,總會發現問題的。
這裏奉勸各位兄弟姐妹,網上的東西仍是要仔細研究的,不要轉來轉去的。