J2EE(J2EE培訓 )發源於Java,由於Java與平台的無關性、開發環境的多樣性,使得J2EE在開發的過程中經常會遇到不同文字編碼相互轉化的問題。J2EE的中文亂碼,就是Java在字符編碼轉化過程中沒有正確匹配對應字符串的字符集,錯誤地使用字符集進行轉化所致。在Java國際版的JDK中,程序運行時,總是把字符串轉化為UTF-8編碼來進行運算。通常情況下,字符串被Java應用程序轉化之前,是根據操作系統默認的編碼方式編碼。因此,在Java程序運行時,就有1個從UNICODE編碼到對應的操作系統及浏覽器支持的編碼格式轉換問題,在整個過程中,每個步驟都必須轉換正確,其中只要有1個步驟轉換出現問題,都會出現漢字亂碼現象,這就是常見的Java中文亂碼問題,也是J2EE開發中產生亂碼的根本原因。因此,在Java系統的輸入、輸出和操作系統之間,采用統一的編碼,就能夠使Java系統正確處理和顯示漢字。這是Java系統處理漢字的通用方法,也是J2EE開發中文系統的一個原則。
1 字符集與字符編碼
人類的記號五花八門,包括國家文字、標點符號、圖形符號、數字等。這些在計算機領域會被統稱為“字符”,而所有字符的集合就被稱為“字符集”。在計算機中要表示這些“字符”,就涉及一個字符編碼的問題。那麼什麼是字符編碼呢?可以說字符編碼就是一種規范,它規定一個字符集中的字符用多少字節來表示,同時制訂該字符編碼集的字符表,即該字符集中每個字符對應的位模式因此,字符編碼就是字符與代碼值之間的映射在文字編碼中涉及與中文編碼相關的字符編碼常用的有:ISO-8859-1,GB2312,GBK,UTF-8,只有ISO-8859-1編碼字符少,不能很好地支持中文,其他3種字符集都兼容ISO-8859-1的編碼(也就是說無論編碼怎麼改變,只要是在ISO-8859-1中的字符,永遠不會出現亂碼)。ISO-8859-1,又稱Latin-1或“西歐語言”,是國際標准化組織內ISO/
IEC8859的第一個8位字符集,它以ASCII為基礎,在空置的0xA0-0xFF的范圍內,加入192個字母及符號,供使用變音符號的拉丁字母語言使用。ISO-8859-1編碼表示的字符范圍很窄,無法表示中文字符。但是,由於是單字節編碼,和計算機最基礎的表示單位一致,所以很多時候,仍舊使用ISO-8859-1編碼來表示。而且在很多協議上,默認使用ISO-8859-1。GB2312是中國規定的漢字編碼,也可以說是簡體中文的字符集編碼,全稱為GB2312(80)字符集,共包括國標簡體漢字6763個。GBK是GB2312的擴展,除了兼容GB2312外,它還能顯示繁體中文,還有日文的假名,共包括21003個字符。
UTF是Unicode的實現方式,稱為Unicode轉換格式(UnicodeTranslationFormat,簡稱為UTF)。UTF-8使用的是可變長的UNICODE編碼,編碼可能是1位16進制(即ISO-8859-1中的字符,其編碼也是相
同的)也有可能是2位或3位的16進制。UTF-8的優點是:與CPU字節順序無關,可以在不同平台之間交流;容錯能力高,任何一個字節損壞後,最多只會導致1個編碼碼位損失,不會鏈鎖錯誤(如GB碼錯1個字節就會整行亂碼),所以在國際化處理中基本都是建議使用UTF-8作為編碼。UTF-8編碼的好處是,即使使用WindowsXP英文版的用戶,浏覽UTF-8編碼的任何網頁,無論是中文還是日文、韓文、阿拉伯文,都可以正常顯示,UTF-8是世界通用的語言編碼。
2 文件的存儲格式
文件的存儲格式是用於在文件中編碼字符數據的標准。文件的存儲格式最常使用的有兩種:ANSI和UTF-8。ANSI是保存文件時使用的默認編碼,也是操作系統的默認編碼,如:中文Windows2000,WindowsXP默認采用的是GBK編碼,英文系統上ISO-8859-1,日文系統上是MS932。如果文件的存儲格式使用了UTF-8,那麼字符編碼就必須使用UTF-8,因為如果文件存儲格式所遵循的標准與字符編碼所遵循的標准不同就會造成亂碼。3J2EE應用程序運行的一般過程J2EE應用程序一般由三部分組成,前端的JSP頁面,中間件應用服務器中的各種JAVABean,後端的數據庫平台。涉及數據編碼轉換的有4個過程:JSP頁面打包成請求(request)發往中間件應用服務器;中間件應用服務器生成JSP頁面,發往客戶端浏覽器;通過數據庫讀入到中間件應用服務器;中間件應用服務器生成數據發往數據庫。利用JSP頁面輸入、輸出信息時,如果不進行特別指定頁面編碼,JAVA將根據默認的操作系統編碼作為初始編碼,這就使得頁面編碼所遵循的編碼標准與操作系統的默認編碼所遵循的編碼標准不一致,從而導致使用J2EE所開發的應用程序產生亂碼。中間件應用服務器對數據庫的讀寫操作,涉及與特定數據庫的編碼交互問題,由於Java內部字符串以UTF-8格式編碼,讀寫數據庫時,必須根據數據庫的字符編碼進行轉換,這也是J2EE程序中容易出現亂碼的地方。由於Java的跨平台性,在實際編譯和運行中,都可能涉及不同的操作系統,如果都由Java自己根據操作系統來決定輸入輸出的編碼字符
集,將不可避免地出現亂碼。同時,由於J2EE的多層松耦合性,也使得字符集問題必須由具體系統的特定層來解決。
4 不同情況下中文亂碼的解決方案
(1)JSP頁面內中文亂碼的解決方案。對於JSP文件的執行,也就是用Web容器調用JSP的編譯器的過程,JSP編譯器第一步檢查JSP文件中有沒有設置文件編碼格式,假如JSP文件中沒有設置JSP文件的編碼格式,那麼JSP編譯器會調用JDK的JVM(Java虛擬機)默認的字符編碼格式(也就是Web容器所在的操作系統的默認的文件編碼)把JSP頁面轉化為臨時的Java文件,然後再把它編譯成UNICODE格式的class類,並保存在臨時文件夾中。通過設置JSP文件頭中頁面編碼,讓JSP編譯器,選用正確的字符編碼格式轉化為臨時的Java文件。如:<%@pageContentType=“text/html;charset=gb2312”%>或<%@pageContentType=“text/Html;charset=gbk”%>或<%@pagelanguage=“Java”contentType=“text/
Html;charset=utf-8”%>,使其生成的中間Java文件的字符串,不再采用系統默認的編碼格式,這樣就避免了亂碼的產生。
(2)頁面參數與JSp之間中文亂碼的解決方案。JSP獲取頁面參數時,實際上是轉化成Servlet來進行。而在Servlet中不指定獲取的編碼格式,則它會自動使用系統默認的編碼方式,如果頁面參數的編碼類型與系統默認的編碼類型不一致,就要產生亂碼。如:使用POST方法傳遞參數,系統提交數據,默認的字符編碼是utf-8。解決這種亂碼問題的基本方法是在頁面獲取參數之前,專門指定request獲取參數的編碼方式。如request.setCharacterEncoding(“UTF-8”),也就是做到傳遞編碼格式與獲得數據的解碼格式一致。對於get方法傳遞中文參數時,必須在接受參數頁面中使用Stringtestname=newString(request.getParameter(“testname”).getBytes(“ISO-8859-1”),“GBK”)進行編碼轉化,這是由於使用get方法傳遞參數時,系統默認使用ISO-8859-1格式。因此,在接受頁面中必須
進行編碼轉化,避免亂碼的出現。使用JSP將變量輸出到頁面時出現了亂碼。在這種情況下,需要把
輸出生成的JSP頁面中重新設定字符編碼,使之可以正確解釋中文。如response.setContentType (“text/html;charset =GBK”) 或 response.setContentType(“text/Html;charset=gb2312”)或response.setContentType(“text/XML;charset=UTF-8”)。最通用的方法是采用過濾器。它只是Servlet接收請求前的預處理器。下面的例子是使用過濾器,將所有來自浏覽器的請求(request)轉換為UTF-8。因為浏覽器發過來請求包的編碼,是根據浏覽器所在的操作系統編碼,不同的操作系統請求包的編碼不同。通過Filter把不同編碼的請求包,轉換為特定編碼的請求包,從而解決漢字亂碼問題。
Filter與Servlet的關聯由Web應用的配置描述文件來明確。在Web.
XML中配置如下:
<filter>
<filter-name>SetCharsetEncodingFilter</filter-name> <filter-
class>com.Network.util.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter><filter-mapping>
<filter-name>SetCharsetEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在<param-name>encoding</param-name>的參數中,可以使用GBK或gb2312將所有來自浏覽器的請求轉化為GBK或gb2312編碼。SetCharacterEncodingFilter可以在TOMCAT的目錄下的\webaPPS\JSP-examples\WEB-INF\classes\filters\ 找到SetCharacterEncodingFilter.Java這個類,放到程序中並配置好映射路徑。
(3)Struts資源文件的亂碼解決方案。資源文件是J2EE程序國際化支持不可或缺的一部分,它的編碼方式和編輯平台相關。如在Windows平台下編寫的資源文件以GBK方式編碼。資源文件亂碼,是資源文件未能正確轉化為Struts可以正確識別的格式。對於所有的非西歐文字必須使用native2ascii-本地碼-至-ASCII碼轉換器轉化,該命令是負責將非西歐文字轉換成系統可以識別的文字。當然,中文也要使用native2ascii命令進行正確的轉換。如:native2ascii-encodinggbkA_zh.propertiesb.propertiesA_zh.properties是要含有本地編碼需轉換的資源文件,b.propertIEs是轉換後可以被Struts使用的文件。
(4)Ajax向後台提交數據亂碼,後台返回數據為亂碼的解決方案。Ajax提交與返回數據亂碼的原因為,AJax技術發送與接受數據實際上是采用異步請求與接受JSp頁面,因此前面提到的JSP頁面中的亂碼問題,在Ajax中也存在。下面是AJax通用的發送數據、接受數據的代碼。
XMLhttp.open(“pos”,url,async);
XMLhttp.setRequestHeader(“Content-Type”,“text/Html;charset=
UTF-8”);
XMLhttp.send(params);
在數據庫端返回數據時也需設置:
response.setContentType(“text/XML”);
response.setCharacterEncoding(“UTF-8”);
可以看出AJax發送時,實際上構造了以1個臨時的Jsp頁面,它由浏覽器動態生成,向後台請求數據。因此,對與普通JSp頁面設置的字符集編碼,對於請求JSP頁面的編碼也要設置。而在返回數據的頁面上,實際上也需要設置頁面編碼,使得浏覽器可以正確解釋返回的中文信息。