MySQL中文亂碼問題的完整解決方法
轉載於https://www.cnblogs.com/nista/archive/2013/04/16/3023279.html
本文描述了在基於JSP +MySQL構建網站時,發生網頁中文顯示為亂碼情況的解決辦法。最終希望使用的編碼是:統一的UTF-8編碼。
試驗網站的開發執行環境:
OS: Ubuntu 12.04 及 Windows 7
IDE: eclipse, Juno Service Release 2
Web Server: Tomcat 7.0.27
DataBase: MySQL 5.5.29
本文的一些觀點應該也能推廣到其他編碼、平臺或資料庫。
網站的中文輸入輸出產生或接收到亂碼的原因,可能發生在資料流動的任意節點處。但是,如果保證所有的位置都使用了統一的編碼,則可以消除中文亂碼的情況。這些可能發生轉碼的地方包括網頁的編碼定義,JSP頁面的編碼,Java程式碼檔案的編碼,Tomcat讀取的web.xml中的定義,MySQL的client、server、connection以及每個資料庫、每個表、甚至每個欄位的編碼設定。根據之前查詢的一些資料,和剛剛做完的實驗,將相關的設定總結如下:
在這個過程中,首先應保證資料庫在儲存資料、存入資料以及資料時應一致。其次,在進行網頁伺服器後臺處理和傳遞的過程中應保證編碼的一致。最後應保證,資料在進行瀏覽器前臺顯示和資料傳遞的過程中編碼的一致。只要保證這一切都採用統一的編碼格式,就不會產生中文亂碼的問題。
(1) MySQL 資料庫的相關定義和配置方法。
MySQL中有關於字符集的概念主要有兩個,一個是字符集(Character Set),一個是字元序(collation)。MySQL內部會採用如下的變數進行字符集的設定:
– character_set_server:預設的內部操作字符集
– character_set_client:客戶端來源資料使用的字符集
– character_set_connection:連線層字符集
– character_set_results:查詢結果字符集
– character_set_database:當前選中資料庫的預設字符集
– character_set_system:系統元資料(欄位名等)字符集
– 還有以collation_開頭的同上面對應的變數,用來描述字元序。
MySQL中的字符集轉換過程如下:
① MySQL 客戶端庫收到請求時將請求資料從character_set_client轉換為character_set_connection;
② MySQL伺服器受到請求進行內部操作前將請求資料從character_set_connection轉換為內部操作字符集,其確定方法如下:
• 使用每個資料欄位的CHARACTER SET設定值;
• 若上述值不存在,則使用對應資料表的DEFAULT CHARACTER SET設定值(MySQL擴充套件,非SQL標準);
• 若上述值不存在,則使用對應資料庫的DEFAULT CHARACTER SET設定值;
• 若上述值不存在,則使用character_set_server設定值。
③ 將操作結果從內部操作字符集轉換為character_set_results。
(以上內容引用自Shunnar Meng
http://hi.baidu.com/shunnarmeng/item/97108dafb4b93638030a4dee)
每個字符集都有一個或多個與之對應的字元序,MySQL中的字元序末尾ci表示大小寫不敏感,si表示大小寫敏感。一般情況下,可以不用設定字元序,因為系統會自動設定所選字符集的首選字元序,如選定字符集utf-8,則會自動選擇預設字元序utf8_general_ci。
更多基本定義,可以參閱MySQL參考手冊:
http://dev.mysql.com/doc/refman/5.1/zh/charset.html
因此,只要在MySQL的配置檔案中進行如下的修改:
(Ubuntu下,一般位於/etc/mysql/my.cnf)
[client] 中,新增 default-character-set = utf8
[mysqld]中,新增
character-set-server = utf8
character-set-client = utf8
collation = utf8_general_ci
[mysql]中,新增 default-character-set = utf8
隨後重啟MySQL服務,$ sudo service mysql restart
之後進入MySQL,輸入 mysql> show VARIABLES like ‘char%’;
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
這可以檢查MySQL在各個處理層次所採用的編碼
(2) eclipse開發環境編碼的設定。
在eclipse的Window選單中選擇 Preferences → General → Workspace,在右側的Text file encoding欄中,將Default(GBK) 改選為Other,並選擇 UTF-8 項。
在Preferences → Web 中,可以將CSS、HTML等檔案的預設編碼形式進行更改。
隨後可以在 Preferences → General → Content Types 中,找到右邊的Text,選擇JSP,在下方的Default encoding中輸入UTF-8,這將會設定程式碼檔案本身的編碼儲存格式。
但是,如果以前有大量原始碼檔案不是UTF-8編碼格式的,可以使用Linux下的iconv或其他工具進行轉碼。
(如果使用NetBeans,也基本按照這個思路,在配置中找)
(3) 在編寫JSP頁面時,應該注意的相關程式碼。
① HTML程式碼部分,應在<head></head>中新增:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
從而保證瀏覽器在解析網頁進行顯示的過程中能夠選擇正確的編碼方式。其他網頁所引用的相關檔案中也應新增字符集標識。
如,CSS頭部新增:
@charset "utf-8";
② JSP內碼表頭部新增:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
③ 如果在Windows環境下,編寫程式碼,注意程式碼檔案本身的編碼也很重要,應保證以UTF-8格式進行儲存(如,在記事本中儲存時更改編碼方式,在eclipse進行上文中的開發環境編碼設定)
(4) 保證Tomcat在執行時進行正常的轉碼行為。
① 編寫過濾器,並設定當前網站專案的配置檔案web.xml,本質是設定頁面和JSP後臺程式之間專遞過程的轉碼,具體的過程如下:
在工程中新增一個新的類,並編寫如下程式碼。
package com.nista.common.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class SetCharacterEncodingFilter implements Filter { // 相關的引數配置,請在本專案的Server.xml中設定 // 如果未設定是否應用本Filter,則預設開啟轉碼 // 如果未設定使用編碼,則預設採用UTF-8 protected FilterConfig filterConfig = null; protected String strEncodingSet = null; protected boolean enableEncoding = true; @Override public void destroy() { this.strEncodingSet = null; this.filterConfig = null; } @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; this.strEncodingSet = filterConfig.getInitParameter("EncodingSet"); String strEnableEncoding = filterConfig.getInitParameter("EnableEncoding"); if (null == strEnableEncoding || strEnableEncoding.equalsIgnoreCase("true")) { this.enableEncoding = true; } else { this.enableEncoding = false; } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (this.enableEncoding) { if (null == this.strEncodingSet) { this.strEncodingSet = "UTF-8"; } request.setCharacterEncoding(strEncodingSet); } chain.doFilter(request, response); } }
在本工程的web.xml中,<welcome-file-list />標籤之後新增如下程式碼,以呼叫上述的字符集編碼過濾器。注意包名和類名需要與上方程式碼一致。
<!-- request/response自定義的字符集編碼過濾器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.nista.common.filter.SetCharacterEncodingFilter</filter-class> <init-param> <param-name>EncodingSet</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>EnableEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
* 如果希望瞭解web.xml配置的更多說明,可以瀏覽 http://blog.sina.com.cn/s/blog_620782850100gam8.html
http://www.cnblogs.com/chinafine/archive/2010/09/02/1815980.html
② 如果需要利用get方式傳遞UTF-8編碼的資料
將Tomcat配置檔案中,所有的<Connector />標籤的URIEncoding屬性進行設定,例如:<Connector ……URIEncoding="UTF-8" />
這種方法實際上是將URI地址在傳遞過程中進行了轉碼,但是這可能會導致其他的一些問題,例如有時伺服器端發生會發生編碼問題(接受URI中中文資料時會出現問題),這時可以採用如下解決方法(不建議在URI中傳中文):
在tomcat 的server.xml裡設定如下:
<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding=”utf-8” useBodyEncodingForURI=”true” redirectPort="8443" />
然後在服務端解碼:
new String (request.getParameter("id").getByte("ISO-8859-1"),"gbk");
通過這些設定以後,就可以基本保證可能發生轉碼的節點採用統一的UTF-8編碼,防止中文亂碼的產生。