中文亂碼問題整理總結

目錄

1、字符編碼

2、亂碼產生的原因

3、亂碼解決方案

3.1、解決HTML頁面中的中文問題:

3.2、解決JSP頁面中的中文問題

3.3、解決Servlet響應結果的中文問題

3.4解決頁面數據傳輸的中文問題

3.5、解決HTTP(get)請求中的中文問題

3.6、解決MySQL數據庫的中文問題

3.7、實現加解密過程中,報文是亂碼:設置編碼格式可能有誤。

3.8、在本地測試是正常的,但是發佈到測試環境後會亂碼的問題


1、字符編碼

在計算機中任何數據都是以二進制存儲的,要存儲一個字符就要對它進行編碼,用一個二進制數與這對應,這種對應的規則,就是字符的編碼。編碼的規則有很多 種,一種規則所編碼的“字符”的集合就叫做“字符集”。在制定編碼標準的時候,“字符的集合”和“編碼”一般都是同時制定的,因此,平時我們所說的“字符 集”,例如GB2312、GBK和JIS等,除了有“字符的集合”這層含義外,同時也包含了“編碼”的含義。

最早出現的編碼是ASCII碼,因爲早期計算機系統只支持英語。後來每個國家(或區域)規定了計算機信息交換用的字符編碼集,例如中國的GB2312等作 爲自己國家/區域內信息處理的基礎。在程序讀取字符到輸出字符的過程中,就需要在不同的字符集之間進行轉換,這個時候就容易出現亂碼,因此要了解亂碼是如 何產生的,首先要了解各種字符編碼。下面對這些編碼做一個簡單介紹。
1)、ASCII

ASCII碼是《美國標準信息交換碼》,簡稱ASCII,它總共規定了128個字符號所對應的數字代碼,使用了7位二進制的位來表示這些數字。其中包含了英文的大小寫字母、數字和標點符號常用的字符,數字代號從0~127。

2)、ISO8859

ASCII碼解決了英語國家的字符問題,可是歐洲各個國家的字符問題還沒有解決,例如法語中就有許多英語中沒有的字符,爲了解決該問題,國際標準化組織的 ISO8859標準應運而生,在ISO8859的編碼表中,編號0~127與ASCII保持兼容,編號128~159共32個編碼保留給擴充定義的32個 擴充控制碼,160爲空格,161~255的95個數字用於新增加的字符代碼。由於在一張碼錶中只能增加95種字符的代碼,因此ISO8859實際上不是 一張碼錶,而是一系列標準,包括14個字符碼錶。例如,西歐的常用字符就包含在ISO8859-1字符表中,在ISO8859-7中則包含了ASCII和 現代希臘語字符。

3)、GB2312和GBK

GB2312是中國國家標準漢字信息交換用編碼,簡稱國標碼,標準號爲GB2312-80。

中國的文字不是拼音文字,漢字的個數的數萬之多,遠遠超過區區256個字符,ISO8859無能爲力,但是通過借鑑ISO8859的編碼思想,研 究人員解決了中文的編碼問題。GB2312使用兩個字節來表示一箇中文,在每個字符的256種可能中,爲了與ASCII保持兼容,低於128的我們不使 用。借鑑ISO8859的設計方案,只使用從160以後的96個數字,兩個字節分成高位和低位,高位的取值範圍從176~247共72個,低位從 161~254共94個,這樣,兩個字節就有72*94=6768種可能,即可表示6768種漢字。
    BG2312-80僅收錄了6763個漢字,還有許多漢字沒有被收錄進去,爲了對更多的字符進行編碼,全國信息技術化技術委員會於1995年12月1日頒 布了《漢字內碼擴展規範》,簡稱GBK。在GBK1.0中共收錄了21886個漢字和圖形符號,微軟公司的window95系統的簡體中文版開始即支持 GBK編碼。GBK向下與GB2312完全兼容,向上支持ISO10646國際標準。

(4)、UNICODE

每個國家和地區都規定了計算機信息交換編碼,這就造成了不同編碼國家、地區之間交流上的困難,如果全世界都使用統一的編碼表就好了,爲此UNICODE組 織發佈了UNICODE編碼。這種編碼使用雙字節符號數對每一個字符進行編碼,在UNICODE3.0.1中包含了49194個字符,將 來,UNICODE中還會增加更多的字符。UNICODE的全稱是“Universal Multiple-Octet Coded Character Set”,簡稱UCS。

(5)、UTF-8

使用UNICODE編碼,一個英文字符也要佔據兩個字節,對於英文信息而言就增加了一倍數據量,爲了減少存儲和傳輸英文數據的數據量,美國人又制定了一系 列用於傳輸和保存UNICODE的編碼標準UTF,這些編碼稱爲UCS傳輸格式碼,也就是將UCS的編碼通過一定的轉換來達到使用的目的。常見的有 UTF-7、UTF-8、UTF-16等。其中UTF-8編碼得到了廣泛的應用,UTF-8的全名是UCS Transformation Format 8,即UCS編碼的8位傳輸格式,就是使用單字節的方式對UCS進行編碼,使UNICODE編碼能夠在單字節的設備上正常進行處理。

UTF-8編碼是變長的編碼,對不同的UNICODE可能編成不同的長度。

從理論上來說,這些根據字符集設置而進行的字符轉換不應該產生太多的問題,而事實上由於應用程序的實際運行環境不同,UNICODE和各個本地字符集的補充、完善以及系統或應用程序實現的不規範,轉碼時還是會經常出現問題而導致亂碼。

2、亂碼產生的原因

Java語言內部是用UNICODE表示字符的,遵守UNICODE V2.0。Java程序無論是以字符流讀/寫磁盤文件,還是向URL轉接寫HTML信息,或從URL連接讀取參數值,都會由UNICODE作爲中介和本地字符編碼進行轉換。

在WEB應用中,瀏覽器、WEB服務器、WEB應用程序和數據庫等各個部分都有可能使用不用的字符集,字符在不同的字符集之間進行轉換時,就有可能出現亂碼問題。例如一箇中文字符“中”要轉換爲ISO-8859-1編碼,在Java中先讀取到的是中文字符的GBK編碼“0xD6D0”,轉換爲 UNICODE碼爲“0x4E2D”,再從UNICODE編碼轉換ISO-8859-1編碼,如果ISO-8859-1編碼中沒有對應的 “0xD6D0”,於是就得到“0x3F”,也就是我們經常在頁面上看到一堆“?”的原因。

在WEB應用中,亂碼可能在多個環節產生,下面針對可能出現亂碼的幾個環節,給出解決的方案。

3、亂碼解決方案

1)、JSP頁面最基本的亂碼問題
運行下面的代碼,會發現頁面上出現的是亂碼。

<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page contentType="text/html; charset=ISO8859-1"%>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>中文問題</title>
</head>
<body>

亂碼問題
</body>
</html>
這段代碼產生亂碼的原因在於它有三處設置了編碼格式,但是格式設置的不一致,因此導致了亂碼,下面來分析這三處設置編碼格式的作用。
<%@ page language="java" pageEncoding="UTF-8"%>
此處的pageEncoding="UTF-8"爲JSP文件的存儲格式。

<%@ page contentType="text/html; charset=ISO8859-1"%>
此處charset=ISO8859-1爲JSP的解碼格式。ISO8859-1是沒有爲漢字編碼的,因此按UTF-8編碼存儲的文件如果用 ISO8859-1編碼格式編碼,其中的中文字符就會因爲找不到對應的編碼而顯示爲亂碼。所以JSP文件的存儲格式和它的解碼格式應該是一致的。

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
此處編碼控制的是瀏覽器的解碼方式,瀏覽器收到的只是一個字節流,它並不知道
頁面是如何編碼的,因此,需要一個機制來告訴瀏覽器頁面的編碼類型,標準的機制是使用<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">來指定頁面的編碼,當瀏覽器讀取頁面遇到這樣的指示時,將使用這裏制定的編碼方式重新加載頁面。

因此只要把三處的都設置爲UTF-8或GBK即可解決亂碼問題。
2)、表單使用POST提交方式提交後接收到的是亂碼

WEB容器在內部編碼格式是ISO8859-1,在POST方式提交時,默認的提交編碼格式是ISO8859-1,這樣接收到的中文信息就會是亂碼,解決方式如下:
   在請求頁面上開始處,執行請求和編碼代碼:
   request.setCharacterEncoding(“GBK”);

   把提交內容的字符集設爲GBK,這樣接受此參數的頁面就不必再轉碼了,直接使用即可得到漢字參數。
   在每一個接受提交的JSP頁面及Servlet中都加這樣的代碼是比較煩人的,可以用過濾器設置request和response的setCharacterEncoding方法來解決這個問題。
例:過濾器解決問題

public class setEncodeingFilter extends HttpServlet implements Filter {
    private FilterConfig config;
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("GBK");
        response.setCharacterEncoding("GBK");
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.config = config;
    }
}

這個過濾器中已經在doFilter方法中直接設置了統一使用GBK編碼,然後在web.xml國配置過濾器:

<filter>
    <filter-name>setEncodeingFilter </filter-name>
    <filter-class>setEncodeingFilter(過濾器的全路徑)</filter-class>
    </filter>
        <filter-mapping>
        <filter-name>setEncodeingFilter </filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <url-pattern>/*</url-pattern>表示所有的頁面都要經過此過濾器過濾,這樣就不用在JSP和Servlet中設置encoding了。 

3)、表單使用GET方式導致的亂碼的處理方式

如果使用GET方式提交中文,接受參數的頁面也會出現亂碼,原因是web容器會以GET方式的默認編碼方式ISO8859-1對漢字進行編碼,編 碼後追加到URL,導致接受頁面得到的參數爲亂碼。 因爲在進入URL之前已經進行了ISO8859-1的編碼處理,所以需要在得到參數值後進行編碼轉換:
     String name = request.getParameter("name");
     name = new String(name.getBytes("ISO8859-1"),"GBK");

4)、數據庫中讀取和存儲中文時的亂碼問題

大多數的JDBC驅動都是默認IS-O8859-1爲數據的傳輸編碼格式,而數據庫本身又有自己的字符集,因此在數據庫讀寫中文數據庫時也經常會出現籌碼人。

流行的關係數據庫系統都支持數據庫Encoding,即在創建數據庫時可以指定其自己的字符集設置。數據庫的數據以指定的編碼形式存儲。當應用程序訪問數據時,在入口和出口處都會有Encoding轉換。對於中文數據,數據庫字符編碼的設置應當保證數據的完整性。

GB23212、GBK和UTF-8等都是可選的數據庫Encoding,在JSP/Servlet編程時,可以先用數據庫管理系統提供的管理功能檢查其中的中文數據是否正確。

3.1、解決HTML頁面中的中文問題:

爲了使HTML頁面很好地支持中文,就必須在每個HTML頁面的頭部增加如下代碼:

<HEAD>
...
<META http-equiv=Content-Type content="text/html;charset=GBK">
...
<HEAD>

3.2、解決JSP頁面中的中文問題

爲了使JSP頁面很好地支持中文,就必須在每個JSP頁面的頭部增加如下代碼:

<%@ page contentType="text/html;charset=GBK" language="java"%>

3.3、解決Servlet響應結果的中文問題

爲了使Servlet頁面很好地支持中文,就必須在每個Servlet頁面的頭部增加如下代碼:

response.setCharacterEncoding("GBK");

3.4解決頁面數據傳輸的中文問題

爲了使中文數據在各頁面(組件)之間正常傳遞,最佳的方法就是採用編碼過濾器來解決。在WEB.XML中配置一個編碼過濾器,內容如下:

<!--定義編碼過濾器-->

<filter>
      <filter-name>encodingFilter</filter-name>
      <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
                <param-name>encoding</param-name>
                <param-value>GBK</param-value>
        </init-param> 
</filter>
    <filter-mapping>
       <filter-name>encodingFilter</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>

3.5、解決HTTP(get)請求中的中文問題

在默認情況下,IE瀏覽器發“ISO-8859-1”的編碼格式發送請求,如果接收到HTTP的get請求中文參數時出現亂碼,就可以對其進行編碼轉換,例如:

String param = request.getParameter("param");

param = new String(param.getBytes("ISO-8859-1", "GBK"));

也可以通過修改Tomcat的server.xml文件來解決:

<Connector port = "8080"

.....

URIEncoding="GBK"/> -->增加這項

3.6、解決MySQL數據庫的中文問題

解決MySQL數據庫中文問題主要在JDBC驅動的URL上,例如:

jdbc:mysql://localhost/test?user=root&password=123456&useUnicode=true&characterEncoding=GBK

3.7、實現加解密過程中,報文是亂碼:設置編碼格式可能有誤。

3.8、在本地測試是正常的,但是發佈到測試環境後會亂碼的問題

1)可能是編譯不一致,比如,測試環境要求編譯成1.4版本,而本地編譯的是1.6;  

2)可能請求報文的編碼和服務器編碼不同,服務器是UTF-8的編碼,而請求報文是GBK。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章