和Java一樣,JSP是目前比較熱門的一個(gè)話題。它是一種在服務(wù)器端編譯執(zhí)行的Web設(shè)計(jì)語言,因?yàn)槟_本語言采用了Java,所以JSP繼承了Java的所有優(yōu)點(diǎn)??墒窃谑褂肑SP程序的過程中,常遇到中文亂碼問題,很多人為此頭疼不已,初學(xué)的時(shí)候我就深受其害,而且使用平臺(tái)不同,中文亂碼問題的解決方法也不同,無形中增加了學(xué)習(xí)JSP的難度。其實(shí),在徹底了解相關(guān)原因后,問題還是比較容易解決的。,以下是我總結(jié)的解決方法,相信對(duì)讀者會(huì)有一定的借鑒意義。 (因?yàn)槲沂褂玫米疃嗟氖荰omcat環(huán)境,所以主要是以Tomcat為例,其它的環(huán)境只會(huì)提及一下,但解決辦法也是差不多的! 每個(gè)國(guó)家(或區(qū)域)都規(guī)定了計(jì)算機(jī)信息交換用的字符編碼集,如美國(guó)的擴(kuò)展ASCII碼、中國(guó)的GB2312-80、日本的 JIS 等,作為該國(guó)家(區(qū)域)信息處理的基礎(chǔ),有著統(tǒng)一編碼的重要作用。由于各本地字符集代碼范圍重疊,相互間信息交換困難,軟件本地化版本獨(dú)立維護(hù)成本較高。因此有必要將本地化工作中的共性抽取出來,做一致性處理,將特殊的本地化處理內(nèi)容降低到最少,這就是所謂的國(guó)際化(I18N)。各種語言信息被規(guī)范為本地信息,而底層字符集采用包含了所有字符的Unicode。
相信了解JSP代碼的讀者對(duì)ISO8859-1一定不陌生,ISO8859-1是我們平時(shí)使用比較多的一個(gè)CodePage,它屬于西歐語系。GB2312-80 是在國(guó)內(nèi)計(jì)算機(jī)漢字信息技術(shù)發(fā)展初始階段制訂的,其中包含了大部分常用的一、二級(jí)漢字和9區(qū)的符號(hào)。該字符集是幾乎所有的中文系統(tǒng)和國(guó)際化的軟件都支持的中文字符集,這也是最基本的中文字符集。
GBK 是 GB2312-80 的擴(kuò)展,是向上兼容的。它包含了20902個(gè)漢字,其編碼范圍是 0x8140~0xFEFE,剔除高位 0x80 的字位,其所有字符都可以一對(duì)一映射到 Unicode 2.0,也就是說 Java 實(shí)際上提供了對(duì) GBK 字符集的支持。
>GB18030-2000(GBK2K) 在 GBK 的基礎(chǔ)上進(jìn)一步擴(kuò)展了漢字,增加了藏、蒙等少數(shù)民族的文字。GBK2K 從根本上解決了字位不夠、字形不足的問題。 1.Tomcat 4開發(fā)平臺(tái) 這個(gè)版本應(yīng)該是我們經(jīng)常用到的版本,所以討論得會(huì)比較詳細(xì)。 Windows 98/2000下的Tomcat 4以上版本都會(huì)出現(xiàn)中文問題(而在Linux下和Tomcat 3.x中則沒有問題),主要表現(xiàn)是頁面顯示亂碼。 為解決這個(gè)問題,最簡(jiǎn)單的方法就是在每個(gè)JSP的頁面開始處加上<%@ page language=“Java” contentType=“text/html; charset=gb2312”%>。不過,這還不夠,雖然這時(shí)顯示了中文,但是發(fā)現(xiàn)從數(shù)據(jù)庫讀出的字段變成了亂碼。經(jīng)過分析發(fā)現(xiàn): 在數(shù)據(jù)庫中保存的中文字符是正常的,數(shù)據(jù)庫用ISO8859-1字符集存取數(shù)據(jù),而Java程序在處理字符時(shí)默認(rèn)采用統(tǒng)一的ISO8859-1字符集(這也體現(xiàn)了Java國(guó)際化思想),所以在數(shù)據(jù)添加的時(shí)候Java和數(shù)據(jù)庫都是以ISO8859-1方式處理,這樣不會(huì)出錯(cuò)。但是在讀取數(shù)據(jù)的時(shí)候就出現(xiàn)問題了,因?yàn)閿?shù)據(jù)讀出也采用ISO8859-1字符集,而 JSP的文件頭中有語句<%@ page language=“Java” contentType=“text/html; charset=gb2312”%>,這說明頁面采用GB2312的字符集顯示,這樣就和讀出的數(shù)據(jù)不一樣。這時(shí)頁面顯示從數(shù)據(jù)庫中讀出的字符是亂碼,解決的方法是對(duì)這些字符轉(zhuǎn)碼,從ISO8859-1轉(zhuǎn)成GB2312,就可以正常顯示了。這個(gè)解決辦法對(duì)很多平臺(tái)具有通用性,讀者可以靈活運(yùn)用。具體的方法會(huì)在以下詳細(xì)講解。另外,對(duì)于不同的數(shù)據(jù)庫如SQL Server,Oracle,Mysql,Sybase等,字符集的選擇很重要。如果考慮多語言版本,數(shù)據(jù)庫的字符集就應(yīng)該統(tǒng)一采用ISO8859-1,需要輸出的時(shí)候在不同的字符集之間做轉(zhuǎn)換就可以了。 以下是針對(duì)不同平臺(tái)的總結(jié): (1) JSWDK只適合于普通開發(fā),穩(wěn)定性和其他問題可能不如商業(yè)軟件。 由于JDK 1.3版性能要好于JDK 1.2.2很多,并且對(duì)中文的支持也較好,所以應(yīng)該盡量采用。 現(xiàn)在jdk已經(jīng)出到1.4版本了,所以如果允許最好升級(jí)到最新的版本,這樣對(duì)中文的也會(huì)較好,而且還可以得到更多的支持。 (2) Tomcat僅僅是一個(gè)對(duì)JSP 1.1、Servlet 2.2標(biāo)準(zhǔn)的實(shí)現(xiàn), 我們不應(yīng)該要求這個(gè)免費(fèi)軟件在細(xì)節(jié)和性能上都面面俱到, 它主要考慮英文用戶, 這也是為什么不做特殊轉(zhuǎn)換,漢字用URL方法傳遞就有問題的原因。大部分IE瀏覽器缺省始終以UTF-8發(fā)送, 這似乎是Tomcat的一個(gè)不足, 另外Tomcat不管當(dāng)前的操作系統(tǒng)是什么語言, 都按ISO8859去編譯JSP, 似乎也欠妥。 2.JSP代碼的中文處理 (1)如果與數(shù)據(jù)無關(guān)的操作,可以在頁面首行加入<%@ page language=“Java” contentType=“text/html; charset=gb2312”%> (2)將Form中的值傳送到數(shù)據(jù)庫中再取出來后全變成了“?”。Form用POST提交數(shù)據(jù),代碼中使用了語句: String st=new(request.getParameter(“name”).getBytes(“ISO8859_1”)), 而且也聲明了charset=gb2312。
要處理Form中傳遞的中文參數(shù),應(yīng)該在JSP中加入下面的代碼,另外定義一個(gè)專門解決這個(gè)問題的getStr類,然后對(duì)接收到的參數(shù)進(jìn)行轉(zhuǎn)換: String keyword1=request.getParameter(“keyword1”); keyword1=getStr(keyword1); 這樣就可以解決問題了,代碼如下: <%@ page contentType=“text/html;charset=gb2312”%> <%! public String getStr(String str){ try{String temp_p=str; byte[] temp_t=temp_p.getBytes(“ISO8859-1”); String temp=new String(temp_t); return temp; } catch(Exception e){ } return “NULL”; } %> <%--http://www.測(cè)試--%> <% String keyword=“創(chuàng)聯(lián)網(wǎng)絡(luò)技術(shù)中心歡迎您的到來”; String keyword1=request.getParameter(“keyword1”); keyword1=getStr(keyword1); out.print(keyword); out.print(keyword1); %> 另外,流行的關(guān)系數(shù)據(jù)庫系統(tǒng)都支持?jǐn)?shù)據(jù)庫Encoding,也就是說在創(chuàng)建數(shù)據(jù)庫時(shí)可以指定它自己的字符集設(shè)置,數(shù)據(jù)庫的數(shù)據(jù)以指定的編碼形式存儲(chǔ)。當(dāng)應(yīng)用程序訪問數(shù)據(jù)時(shí),在入口和出口處都會(huì)有 Encoding 轉(zhuǎn)換。對(duì)于中文數(shù)據(jù),數(shù)據(jù)庫字符編碼的設(shè)置應(yīng)當(dāng)保證數(shù)據(jù)的完整性。 GB2312、GBK、UTF-8 等都是可選的數(shù)據(jù)庫 Encoding,也可以選擇 ISO8859-1 (8-bit), 但會(huì)增加了編程的復(fù)雜度,ISO8859-1不是推薦的數(shù)據(jù)庫 Encoding。在JSP/Servlet編程時(shí),可以先用數(shù)據(jù)庫管理系統(tǒng)提供的管理功能檢查其中的中文數(shù)據(jù)是否正確。
(3)JDBC Driver的字符轉(zhuǎn)換 目前大多數(shù)JDBC Driver采用本地編碼格式來傳輸中文字符,例如中文字符“0x4175”會(huì)被轉(zhuǎn)成“0x41”和“0x75”進(jìn)行傳輸。因此需要對(duì)JDBC Driver返回的字符以及要發(fā)給JDBC Driver的字符進(jìn)行轉(zhuǎn)換。當(dāng)用JDBC Driver向數(shù)據(jù)庫中插入數(shù)據(jù)時(shí),需要先將Unicode轉(zhuǎn)成Native code; 當(dāng) JDBC Driver從數(shù)據(jù)庫中查詢數(shù)據(jù)時(shí),則需要將Native code轉(zhuǎn)換成Unicode。下面給出了這兩種轉(zhuǎn)換的實(shí)現(xiàn): String native2Unicode(String s) { if (s == null || s.length() == 0) { return null; } byte[] buffer = new byte[s.length()]; for (int i = 0; i s.length(); i++) { if (s.charAt(i)>= 0x100) { c = s.charAt(i); byte []buf = (“”+c).getBytes(); buffer[j++] = (char)buf[0]; buffer[j++] = (char)buf[1]; } else {buffer[j++] = s.charAt(i);} } return new String(buffer, 0, j); } 要注意的是,有些JDBC Driver如果通過JDBC Driver Manager設(shè)置了正確的字符集屬性,以上方法就不需要了。具體情況可參考相關(guān)JDBC的資料。 其實(shí)理解了,中文亂碼就這么一回事!反復(fù)使用就會(huì)摸出一定的門道了!我覺得以上的三種方法,只要你真的能弄懂,在遇到中文問題時(shí),在這三種方法多試嘗,我保證你不再會(huì)使這種中文問題所煩! 以上只是自己的一些經(jīng)驗(yàn)所談,如果有什么不對(duì),希望能提出,共同學(xué)習(xí)!
|