中文字元亂碼問題的解決方法
轉載:http://blog.chinaunix.net/uid-26284395-id-3303341.html
Jsp+servlet+tomcat6.0+ibatis+mysql5.0架構,中文字元亂碼問題的解決總結
首先總結我的項目字元集設定:
1、jsp、servlet字元集要統一,如果要用gbk就都用gbk。或者都用utf-8。我都統一用得是utf-8;(我在servlet中分别對request和response進行了字元集設定,并且還應用
new String(S.getBypes(ISO-8859-1),"UTF-8" ) 由于他和request的設定的作用是相同的,
是以我得到還是亂碼,由此可以看出不是吧所有的字元集設定都加上就是正确的)
2、在未插入資料庫之前一定要确認servlet在jsp頁面獲得的是否為中文。
3、Ibatis 在連接配接mysql的時候 url 裡面加的characterEncoding 的值要和mysql的字元集一制。
4、為解決中文問題,mysql我用的gbk。
5、Mysql5.0 的驅動也很重要,驅動要和mysql的版本一緻,要不然也會出問題,這個是出現中文字元亂碼的原因之一。
6、Tomcat 字元集的設定,修改 D:\Tomcat 6.0\conf\server.xml
connectionTimeout="20000"
redirectPort="9443" URIEncoding='GBK' />
增加對GET方法擷取資料時的編碼設定參數 URIEncoding='GBK',(設定tomcat對我項目影響不大,我剛才測試了一下,如果不設定也正常運作,設定這項對于用get方法擷取參數是有作用)
7、我在網上查了好多的資料好多人都說mysql和jsp、servlet 最好統一字元,确實統一字元會少很多麻煩,由于我的mysql設定成utf-8就有問題,是以我就設定成gbk的了!按照網上說的更改my.ini 檔案結合設定語句,都統一成下面這樣了
8、其實遇到中文亂碼問題的人很多,主要原因就是沒有弄清jsp、servlet、mysql之間字元集是怎麼轉換的,個人認為應該先從理論上了解,自己在做一些測試,如果還是有問題,就要一步一步的測試,中文問題也就容易解決了!
針對字元集的問題我查閱了很多資料,下面整體進行總結一下:
下面對于字元集的設定在jsp、servlet、mysql、tomcat中的作用
首先要清楚幾個名詞解釋及其作用
1. contentType: <%@ page contentType=”text/html; charset=UTF-8″%>
2. pageEncoding:<%@ page pageEncoding=”UTF-8″%>
3. html頁面charset:
4. setCharacterEncoding:request.setCharacterEncoding(),response.setCharacterEncoding()
5. setContentType:response.setContentType()
6. jsp頁面編碼: jsp檔案本身的編碼
7. web頁面顯示編碼:jsp的輸出流在浏覽器中顯示的編碼
8. web頁面輸入編碼: 輸入框輸入的字型編碼
9. web伺服器輸入的請求流: web Server相應浏覽器的請求資料
10. web伺服器輸出的響應流: web Server相應浏覽器的輸出資料
1、JSP/Servlet中的幾個字元編碼的作用
在JSP/Servlet中主要有以下幾個地方可以設定編碼,pageEncoding="UTF-8"、contentType="text/html;charset=UTF-8"、request.setCharacterEncoding("UTF-8")和response.setCharacterEncoding("UTF-8"),其中前兩個隻能用于JSP中,而後兩個可以用于JSP和Servlet中。
(1)pageEncoding="UTF-8"的作用是設定JSP編譯成Servlet時使用的編碼。
衆所周知,JSP在伺服器上是要先被編譯成Servlet的。pageEncoding="UTF-8"的作用就是告訴JSP編譯器在将JSP檔案編譯成Servlet時使用的編碼。通常,在JSP内部定義的字元串(直接在JSP中定義,而不是從浏覽器送出的資料)出現亂碼時,很多都是由于該參數設定錯誤引起的。例如,你的JSP檔案是以GBK為編碼儲存的,而在JSP中卻指定pageEncoding="UTF-8",就會引起JSP内部定義的字元串為亂碼。
另外,該參數還有一個功能,就是在JSP中不指定contentType參數,也不使用response.setCharacterEncoding方法時,指定對伺服器響應進行重新編碼的編碼。
補充: pageEncoding, 隻是指明了 JSP 頁面本身的編碼格式,跟頁面顯示的編碼沒有關系; 容器在讀取(檔案)或者(資料庫)或者(字元串常量)時将起轉化為内部使用的 Unicode,而 頁面顯示的時候将内部的Unicode轉換為contentType指定的編碼後顯示頁面内容;如果pageEncoding屬性存在,那麼JSP頁面的字元編碼方式就由pageEncoding決定,否則就由contentType屬性中的charset決定,如果charset也不存在,JSP頁面的字元編 碼方式就采用預設的ISO-8859-1。
(2)contentType="text/html;charset=UTF-8"的作用是指定對伺服器響應進行重新編碼的編碼。
在不使用response.setCharacterEncoding方法時,用該參數指定對伺服器響應進行重新編碼的編碼。伺服器在将資料發送到浏覽器前,對資料進行重新編碼時,使用的就是該編碼。
(3)request.setCharacterEncoding("UTF-8")的作用是設定對用戶端請求進行重新編碼的編碼。
該方法用來指定對浏覽器發送來的資料進行重新編碼(或者稱為解碼)時,使用的編碼
(4)response.setCharacterEncoding("UTF-8")的作用是指定對伺服器響應進行重新編碼的編碼。伺服器在将資料發送到浏覽器前,對資料進行重新編碼時,使用的就是該編碼。
其次,要說一說浏覽器是怎麼樣對接收和發送 的資料進行編碼的
response.setCharacterEncoding("UTF-8")的作用是指定對伺服器響應進行重新編碼的編碼。同時,浏覽器也是根據這個參數來對其接收到的資料進行重新編碼(或者稱為解碼)。是以在無論你在JSP中設定response.setCharacterEncoding("UTF-8")或者response.setCharacterEncoding("GBK"),浏覽器均能正确顯示中文(前提是你發送到浏覽器的資料編碼是正确的,比如正确設定了pageEncoding參數等)。讀者可以做個實驗,在JSP中設定response.setCharacterEncoding("UTF-8"),在IE中顯示該頁面時,在IE的菜單中選擇"檢視(V)"à"編碼(D)"中可以檢視到是" Unicode(UTF-8)",而在在JSP中設定response.setCharacterEncoding("GBK"),在IE中顯示該頁面時,在IE的菜單中選擇"檢視(V)"à"編碼(D)"中可以檢視到是"簡體中文(GB2312)"。
浏覽器在發送資料時,對URL和參數會進行URL編碼,對參數中的中文,浏覽器也是使用response.setCharacterEncoding參數來進行URL編碼的。以百度和GOOGLE為例,如果你在百度中搜尋"漢字",百度會将其編碼為"%BA%BA%D7%D6"。而在GOOGLE中搜尋"漢字",GOOGLE會将其編碼為"%E6%B1%89%E5%AD%97",這是因為百度的response.setCharacterEncoding參數為GBK,而GOOGLE的的response.setCharacterEncoding參數為UTF-8。
浏覽器在接收伺服器資料和發送資料到伺服器時所使用的編碼是相同的,預設情況下均為JSP頁面的response.setCharacterEncoding參數(或者contentType和pageEncoding參數),我們稱其為浏覽器編碼。當然,在IE中可以修改浏覽器編碼(在IE的菜單中選擇"檢視(V)"à"編碼(D)"中修改),但通常情況下,修改該參數會使原本正确的頁面中出現亂碼。一個有趣的例子是,在IE中浏覽GOOGLE的首頁時,将浏覽器編碼修改為"簡體中文(GB2312)",此時,頁面上的中文會變成亂碼,不理它,在文本框中輸入"漢字",送出,GOOGLE會将其編碼為"%BA%BA%D7%D6",可見,浏覽器在對中文進行URL編碼時,使用的就是浏覽器編碼。
弄清了浏覽器是在接收和發送資料時,是如何對資料進行編碼的了,我們再來看看伺服器是在接收和發送資料時,是如何對資料進行編碼的。
對于發送資料,伺服器按照response.setCharacterEncoding—contentType—pageEncoding的優先順序,對要發送的資料進行編碼。
對于接收資料,要分三種情況。一種是浏覽器直接用URL送出的資料,另外兩種是用表單的GET和POST方式送出的資料。
因為各種WEB伺服器對這三種方式的處理也不相同,是以我們以Tomcat5.0為例。
無論使用那種方式送出,如果參數中包含中文,浏覽器都會使用目前浏覽器編碼對其進行URL編碼。
對于表單中POST方式送出的資料,隻要在接收資料的JSP中正确request.setCharacterEncoding參數,即将對用戶端請求進行重新編碼的編碼設定成浏覽器編碼,就可以保證得到的參數編碼正确。有些讀者可能會問,那如何得到浏覽器編碼呢?上面我們提過了,在預設請情況下,浏覽器編碼就是你在響應該請求的JSP頁面中response.setCharacterEncoding設定的值。是以對于POST表單送出的資料,在獲得資料的JSP頁面中request.setCharacterEncoding要和生成送出該表單的JSP頁面的response.setCharacterEncoding設定成相同的值。
對于URL送出的資料和表單中GET方式送出的資料,在接收資料的JSP中設定request.setCharacterEncoding參數是不行的,因為在Tomcat5.0中,預設情況下使用ISO-8859-1對URL送出的資料和表單中GET方式送出的資料進行重新編碼(解碼),而不使用該參數對URL送出的資料和表單中GET方式送出的資料進行重新編碼(解碼)。要解決該問題,應該在Tomcat的配置檔案的Connector标簽中設定useBodyEncodingForURI或者URIEncoding屬性,其中useBodyEncodingForURI參數表示是否用request.setCharacterEncoding參數對URL送出的資料和表單中GET方式送出的資料進行重新編碼,在預設情況下,該參數為false(Tomcat4.0中該參數預設為true);URIEncoding參數指定對所有GET方式請求(包括URL送出的資料和表單中GET方式送出的資料)進行統一的重新編碼(解碼)的編碼。URIEncoding和useBodyEncodingForURI差別是,URIEncoding是對所有GET方式的請求的資料進行統一的重新編碼(解碼),而useBodyEncodingForURI則是根據響應該請求的頁面的request.setCharacterEncoding參數對資料進行的重新編碼(解碼),不同的頁面可以有不同的重新編碼(解碼)的編碼。是以對于URL送出的資料和表單中GET方式送出的資料,可以修改URIEncoding參數為浏覽器編碼或者修改useBodyEncodingForURI為true,并且在獲得資料的JSP頁面中request.setCharacterEncoding參數設定成浏覽器編碼。
2、下面總結下,以Tomcat5.0為WEB伺服器時,如何防止中文亂碼。
(1) 對于同一個應用,最好統一編碼,推薦為UTF-8,當然GBK也可以。
(2) 正确設定JSP的pageEncoding參數
(3)在所有的JSP/Servlet中設定contentType="text/html;charset=UTF-8"或response.setCharacterEncoding("UTF-8"),進而間接實作對浏覽器編碼的設定。
(4)對于請求,可以使用過濾器或者在每個JSP/Servlet中設定request.setCharacterEncoding("UTF-8")。同時,要修改Tomcat的預設配置,推薦将useBodyEncodingForURI參數設定為true,也可以将URIEncoding參數設定為UTF-8(有可能影響其他應用,是以不推薦)。
3、Mysql字元集設定
基本概念
• 字元(Character)是指人類語言中最小的表義符号。例如’A'、’B'等;
• 給定一系列字元,對每個字元賦予一個數值,用數值來代表對應的字元,這一數值就是字元的編碼(Encoding)。例如,我們給字元’A'賦予數值0,給字元’B'賦予數值1,則0就是字元’A'的編碼;
• 給定一系列字元并賦予對應的編碼後,所有這些字元和編碼對組成的集合就是字元集(Character Set)。例如,給定字元清單為{’A',’B'}時,{’A'=>0, ‘B’=>1}就是一個字元集;
• 字元序(Collation)是指在同一字元集内字元之間的比較規則;
• 确定字元序後,才能在一個字元集上定義什麼是等價的字元,以及字元之間的大小關系;
• 每個字元序唯一對應一種字元集,但一個字元集可以對應多種字元序,其中有一個是預設字元序(Default Collation);
• MySQL中的字元序名稱遵從命名慣例:以字元序對應的字元集名稱開頭;以_ci(表示大小寫不敏感)、_cs(表示大小寫敏感)或_bin(表示按編碼值比較)結尾。例如:在字元序“utf8_general_ci”下,字元“a”和“A”是等價的;
MySQL字元集設定
• 系統變量:
– character_set_server:預設的内部操作字元集
– character_set_client:用戶端來源資料使用的字元集
– character_set_connection:連接配接層字元集
– character_set_results:查詢結果字元集
– character_set_database:目前選中資料庫的預設字元集
– character_set_system:系統中繼資料(字段名等)字元集
– 還有以collation_開頭的同上面對應的變量,用來描述字元序。
1.MySQL預設字元集
MySQL對于字元集的指定可以細化到一個資料庫,一張表,一列,應該用什麼字元集。
但是,傳統的程式在建立資料庫和資料表時并沒有使用那麼複雜的配置,它們用的是預設的配置,那麼,預設的配置從何而來呢? (1)編譯MySQL 時,指定了一個預設的字元集,這個字元集是 latin1;
(2)安裝MySQL 時,可以在配置檔案 (my.ini) 中指定一個預設的的字元集,如果沒指定,這個值繼承自編譯時指定的;
(3)啟動mysqld 時,可以在指令行參數中指定一個預設的的字元集,如果沒指定,這個值繼承自配置檔案中的配置,此時 character_set_server 被設定為這個預設的字元集;
(4)當建立一個新的資料庫時,除非明确指定,這個資料庫的字元集被預設設定為character_set_server;
(5)當選定了一個資料庫時,character_set_database 被設定為這個資料庫預設的字元集;
(6)在這個資料庫裡建立一張表時,表預設的字元集被設定為 character_set_database,也就是這個資料庫預設的字元集;
(7)當在表内設定一欄時,除非明确指定,否則此欄預設的字元集就是表預設的字元集;
簡單的總結一下,如果什麼地方都不修改,那麼所有的資料庫的所有表的所有欄位的都用 latin1 存儲,不過我們如果安裝 MySQL,一般都會選擇多語言支援,也就是說,安裝程式會自動在配置檔案中把 default_character_set 設定為 UTF-8,這保證了預設情況下,所有的資料庫的所有表的所有欄位的都用 UTF-8 存儲。
2.檢視預設字元集(預設情況下,mysql的字元集是latin1(ISO_8859_1)
通常,檢視系統的字元集和排序方式的設定可以通過下面的兩條指令:
mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+---------------------------------+
| Variable_name | Value |
+--------------------------+---------------------------------+