常常有讀者在公衆號上問 JavaWeb 亂碼的問題,昨天又有一個小夥伴問及此事,其實這個問題很簡單,可是想要說清楚卻並不容易,由於每一個人亂碼的緣由都不同,給每位小夥伴都把亂碼的緣由講一遍也挺費時間的,所以,鬆哥今天決定寫一篇文章,和大夥好好捋捋 JavaWeb 中的亂碼問題。html
對於一些老司機而言,其實並不太容易遇到亂碼問題,可是對於一些新手來講,亂碼幾乎是屢見不鮮,並且每當亂碼時,網上搜了一大堆解決方案,發現本身的問題仍是沒能解決,其實這就是平時研究代碼不求甚解致使的,亂碼問題,也要去分析,而後才能對症下藥,才能藥到病除。java
首先出現亂碼以後,要先去確認亂碼的地方,當一個網頁上出現亂碼,有多是瀏覽器顯示問題,也有多是 Java 編碼問題,也有可能數據庫中的數據自己就是亂碼的,因此咱們要作的第一件事就是確認亂碼發生的位置,縮小 bug 範圍,經過打印日誌或者 debug 首先去確認亂碼發生的位置,而後再去進一步解決,通常來講,亂碼的緣由大體上能夠分爲兩類:mysql
請求亂碼,多是由於參數放在 URL 地址中亂碼,也有多是參數放在請求體中亂碼,不一樣傳參方案也對應了不一樣的亂碼解決方案。若是是響應亂碼,那麼緣由就會比較多了,通常來講,有以下幾種可能的緣由:web
對於不一樣的亂碼緣由,會有不一樣的解決方案,對症下藥,才能藥到病除,因此當出現亂碼時,你們要作的第一件事就是分析亂碼發生的緣由,找到緣由了,才能找到解決方案。spring
發生亂碼是由於各自編碼不一樣致使的,因此,你們首先要有一個良好的開發習慣,項目編碼,文件編碼都要統一塊兒來,鬆哥有個同事就由於 Freemarker 亂碼,找了半天沒找到緣由,後來在鬆哥建議下修改了項目編碼,亂碼問題才解決了,通常來講,公司制度稍微成熟一些,都會對項目編碼,文件編碼有硬性規定的。在Eclipse 中,設置項目編碼方式以下(工程的編碼要提早設置,若是項目已經開發一半再去設置,已有的中文就會亂碼):sql
Window->Preferences->General數據庫
而後對於 JSP 文件也須要提早設置好編碼方式,以下:json
這是在 Eclipse 中設置文件編碼,若是是在 IntelliJ IDEA中,則不須要設置JSP文件編碼,由於默認就是 UTF-8,只須要提早設置下工程編碼便可:後端
除了開發工具的編碼,數據庫的編碼也要統一,通常來講,主要是設置一下數據庫的編碼和數據表的編碼,以下:瀏覽器
設置數據庫編碼:
CREATE DATABASE `vhr` DEFAULT CHARACTER SET utf8;
設置數據表編碼:
DROP TABLE IF EXISTS `adjustsalary`; CREATE TABLE `adjustsalary` ( `id` int(11) NOT NULL AUTO_INCREMENT, `eid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這些是準備工做,這些工做作好了,仍是有可能會遇到亂碼問題,接下來咱們就具體問題具體分析。
請求亂碼,就是說數據在瀏覽器中顯示是正常的,可是傳到 Java 後端以後,就亂碼了,這種亂碼通常來講,分爲兩種:
兩種亂碼緣由,對應了兩種不一樣的解決方案。分別來看。
這種亂碼主要發生在 GET 請求中,由於在 GET 請求中咱們通常經過 URL 來傳遞參數,這個問題能夠在代碼中解決,可是太過於麻煩,所以通常咱們直接在Tomcat配置中解決,修改 Tomcat的conf/server.xml 文件,修改 URL 編碼格式,以下:
這樣就能夠搞定 URL 地址中的參數亂碼。
請求體中的參數亂碼,咱們能夠在解析參數以前經過設置 HttpServletRequest 的編碼來解決,以下:
request.setCharacterEncoding("UTF-8");
可是同樣也太過於麻煩,因此若是是普通的 Servlet/JSP 項目,咱們就能夠直接定義一個過濾器來處理,以下:
public class EncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } }
過濾器配置:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.sang.filter.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在工程編碼和JSP/HTML編碼都沒問題的狀況下,請求亂碼基本上就是這兩種狀況。
若是在瀏覽器上加載頁面看到了亂碼,你們首先要確認在從服務端往瀏覽器寫數據的前一刻,這個數據尚未亂碼(即數據庫中查詢出來的數據是OK的,沒有發生亂碼的問題),那麼對於這種亂碼,咱們只須要設置響應數據的 ContentType 就能夠了,以下:
response.setContentType("text/html;charset=UTF-8");
若是從數據庫中查詢出來的數據就是亂碼的,那麼就須要去確認數據庫中的編碼是否 OK 。
前面提到的方案,都是在 Servlet/JSP 項目中咱們能夠採用的方案,在 SSM 框架中固然也可使用,可是,SpringMVC 框架自己也提供了一個過濾器,咱們能夠借用這個過濾器更加高效的解決響應亂碼問題,以下:
<filter> <filter-name>encoding</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>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
固然,上面這段配置並不能代替 Tomcat 中 conf/server.xml 中的編碼配置,若是是在 Spring Boot 中,配置能夠更加簡單,只須要在 application.properties 中添加以下配置便可:
server.tomcat.uri-encoding=UTF-8 spring.http.encoding.force-request=true spring.http.encoding.force-response=true
其餘亂碼主要是指使用一些第三方框架致使的亂碼,例如使用 Alibaba 的 fastjson,開發者就須要在配置 HttpMessageConverter 時指定編碼格式,不然就有可能出現亂碼,這種第三方框架的亂碼鬆哥無法窮舉,大夥在使用時須要注意看官方文檔,fastjson 的 HttpMessageConverter 配置以下:
@Bean FastJsonHttpMessageConverter fastJsonHttpMessageConverter() { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig config = new FastJsonConfig(); config.setCharset(Charset.forName("UTF-8")); converter.setFastJsonConfig(config); converter.setDefaultCharset(Charset.forName("UTF-8")); return converter; }
除了前面介紹的這幾種亂碼以外,還有一個比較隱蔽的亂碼,容易被不少初學者忽略的地方,就是數據在從 Java 應用傳遞到 MySQL 的過程當中,發生了亂碼,這種問題通常在 Windows 上不易發生,若是數據庫裝在 Linux 上,則這個問題就很容易發生,數據在代碼中命名沒有亂碼,存到 MySQL 上就亂碼了,可是若是直接使用 Navicat 等工具往 MySQL 上存儲數據,又不會亂碼,或者 MySQL 中數據沒有亂碼,可是用 Java 查詢出來就亂碼了,這種都是數據在 應用 和 數據庫 之間傳遞時發生了亂碼,解決方式很簡單,在數據庫鏈接地址上指定編碼便可,以下:
db.url=jdbc:mysql:///yuetong?useUnicode=true&characterEncoding=UTF-8
大體就這些,還有一些很是偶爾的狀況可能會用到 @RequestMapping 註解中的 produces 屬性,在這裏指定數據類型便可。
好了,差很少就這些,下次有人問你爲啥個人又亂碼了,直接把這篇文章甩給他。大夥有什麼解決亂碼的獨門密器也能夠一塊兒來討論。
關注公衆號【江南一點雨】,專一於 Spring Boot+微服務以及先後端分離等全棧技術,按期視頻教程分享,關注後回覆 Java ,領取鬆哥爲你精心準備的 Java 乾貨!