本篇的主題是中文亂碼問題.我們將分析中文亂碼產生的原因,並通過多種方式解決中文亂碼問題。
在電腦中,只有位元據。不管資料儲存在記憶體或者外存,對於我們看到的字元,也是以二進位形式儲存的。不同字元對應位元的規則,就是字元的編碼。字元編碼的集合就稱之為字元集。
常用字元集
常用的字元集有ASCII碼,ISO8859-1,GB2312,GBK,Unicode,UTF-8。每一個ASCII碼用8位位元表示,比如字元“0”表示為48。ASCII最多能表示256種字元,最初只用於表示英文字母和其他字元,但是隨著電腦發展與普及,其他國家都需要引入本地語言,所以明顯不夠用。ISO8859-1則擴充了ASCII碼,增加了一些其他的西文字元。GB2312是中國國家標準漢字資訊交換用編碼,GBK對GB2312提供擴充支援,除了完全相容GB2312外,還支援繁體字,不常用漢字和許多符號。不過GBK並不是國家標準,它只是規範。
每個國家都定義了自己的字元集。如果你發送一封郵件給一個德國朋友,郵件發送時按照漢字編碼轉換為位元據,等到他接收到以後再將位元據轉換為德文,那就會出現亂碼。因為,在不同的字元集之間,同一個數字可能對應了不同的符號,也可能在另一種字元集中,沒有對應的符號。為瞭解決這些問題,Unicode協會制定了Unicode編碼。unicode使用雙位元組無符號數對每一個字元進行編碼。範圍為0-65535,目前已定義了40000多個不同的unicode字元。UTF-8是為了減少儲存和傳輸英文字元的資料量。因為unicode編碼一個字元要佔兩個位元組,而在網路上,大多數資訊是用英文表示的。
對亂碼產生原因的分析
為了讓使用java編寫的程式能在各種語言平台下運行,java在內部使用unicode字元集來表示字元,這樣就存在unicode字元集和本地字元集進行轉換的過程。在java中讀取本地字元資料時,需要將其轉換為unicode編碼,而在輸出時,需要將unicode編碼轉換為本地字元編碼。例如在中文系統中從控制台讀取一個字元“中”,實際上讀取的是它的GBK編碼0xD6D0,在java語言中藥將GBK轉換為unicode編碼0x4E2D,此時,記憶體中儲存的字元“中”對應的數值為0x4E2D,在向控制台輸出時,則將其轉換為GBK。
根據上述過程,轉換過程是可逆的,不應該存在亂碼問題才對。但實際上,web應用中,瀏覽器,web伺服器,web應用程式,資料庫中都可能使用不同的字元集,從而導致字元在各種不同字元之間轉換時,出現亂碼問題。
當從unicode字元集向某個字元集轉換時,如果該字元集沒有對應的編碼,則得到0x3f(即問號?)。從其他字元集向unicode編碼轉換時,如果這個位元在該字元集中沒有標識任何字元,則得到的結果是0xfffd。
中文亂碼問題解決方案
以post方法提交的表單資料中有中文字元
由於web容器預設採用ISO-8859-1編碼,在servlet/jsp中,通過請求對象的getParameter()方法得到的字串是以ISO-8859-1轉換而來,這是導致亂碼的原因之一,為了避免容器以ISO-8859-1的編碼格式返回字串,對於以POST方法提交的表單資料,可以在擷取請求參數前,調用request.setCharacterEncoding("GBK") ,明確指出請求本文使用的編碼格式是GBK,在向瀏覽器發送資料前,調用指定輸出內容的編碼方式是GBK。
對於JSP頁面,在擷取請求參數值前,寫上下面的代碼:
<%request.setCharacterEncoding("gb2312");%>
為了指定輸出內容的編碼格式,設定page指令的contentType屬性。
<%reponse.setContentType("text/html;charset=GBK");%>
在web容器轉換jsp頁面後的servlet類中,會自動添加下面的代碼:
reponse.setContentType("text/html;charset=GBK");
以get方式提交的表單資料有中文字元
當提交表單採用get方式時,提交的資料作為查詢字串被附加到URL的末端,發送到伺服器,此時在伺服器端調用setCharacterEncoding就沒用了,我們需要在得到請求參數的值後,自己做正確的編碼轉換。
String name = request.getParameter("name");name = new String(name.getBytes("ISO-8859-1","GBK"));
在資料庫中儲存的讀取中文資料
要解決讀取資料庫中中文資料出現亂碼的問題,只需要將資料庫預設的編碼格式改為GBK或GB2312即可。
使用過濾器解決中文亂碼問題
過濾器代碼如下:
package com.shan.filter;import java.io.IOException;import javax.servlet.*;public class EncodingFilter implements Filter {private String encoding = null;private FilterConfig filterConfig = null;public void init(FilterConfig filterConfig) throws ServletException {this.filterConfig = filterConfig;this.encoding = filterConfig.getInitParameter("encoding");}public void destroy() {this.encoding = null;this.filterConfig = null;}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {if(null != encoding){request.setCharacterEncoding(encoding);}chain.doFilter(request, response);}}
web.xml設定檔內容如下:
<?xml version="1.0" encoding="ISO-8859-1"?><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <filter> <filter-name>EncodingFilter</filter-name> <filter-class>com.shan.filter.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>gb2312</param-value> </init-param> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping></web-app>
讓Tomcat支援中文檔案名稱
在web應用程式中我們可能會使用具有中文檔案名稱的檔案,然而Tomcat在預設情況下不能訪問中文檔案名稱的檔案。為了讓Tomcat可以正常訪問,需要配置在Tomcat安裝目錄下的conf檔案夾下的server.xml檔案。找到<Connector>元素,在該元素中添加URIEncoding屬性,將其值設定為UTF-8,如下所示:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
絕大多數瀏覽器在傳輸URI時都以UTF-8編碼。在web應用程式中,如果調用response.sendRedirect()方法重新導向到中文檔案名稱的頁面,需要用如下方式調用:
response.sendRedirect(java.net.URLEncoder.encode("中文檔案.html","UTF-8"));
除此之外,對於其他訪問方式,可直接寫中文檔案名稱,不需要進行編碼。
轉載請註明出處:http://blog.csdn.net/iAm333