1. 程式人生 > >中文字元亂碼問題的解決方法

中文字元亂碼問題的解決方法

                         中文字元亂碼問題的解決方法

 

轉載: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                           |

+--------------------------+---------------------------------+