摘錄地址: http://internet.blog.enorth.com.cn/article/5015.shtml
一、中文問(wèn)題的來(lái)源
計(jì)算機(jī)最初的操作系統(tǒng)支持的編碼是單字節(jié)的字符編碼,于是,在計(jì)算機(jī)中一切處理程序最初都是以單字節(jié)編碼的英文為準(zhǔn)進(jìn)行處理。隨著計(jì)算機(jī)的發(fā)展,為了適應(yīng)世界其它民族的語(yǔ)言(當(dāng)然包括我們的漢字),人們提出了 UNICODE 編碼,它采用雙字節(jié)編碼,兼容英文字符和其它民族的雙字節(jié)字符編碼,所以,目前,大多數(shù)國(guó)際性的軟件內(nèi)部均采用 UNICODE 編碼,在軟件運(yùn)行時(shí),它獲得本地支持系統(tǒng)(多數(shù)時(shí)間是操作系統(tǒng))默認(rèn)支持的編碼格式,然后再將軟件內(nèi)部的 UNICODE 轉(zhuǎn)化為本地系統(tǒng)默認(rèn)支持的格式顯示出來(lái)。 Java 的 JDK 和 JVM 即是如此,我這里說(shuō)的 JDK 是指國(guó)際版的 JDK ,我們大多數(shù)程序員使用的是國(guó)際化的 JDK 版本,以下所有的 JDK 均指國(guó)際化的 JDK 版本。我們的漢字是雙字節(jié)編碼語(yǔ)言,為了能讓計(jì)算機(jī)處理中文,我們自己制定的 gb2312 、 GBK 、 GBK2K 等標(biāo)準(zhǔn)以適應(yīng)計(jì)算機(jī)處理的需求。所以,大部分的操作系統(tǒng)為了適應(yīng)我們處理中文的需求,均定制有中文操作系統(tǒng),它們采用的是 GBK,GB2312 編碼格式以正確顯示我們的漢字。如:中文 Win2K 默認(rèn)采用的是 GBK 編碼顯示,在中文 WIN2k 中保存文件時(shí)默認(rèn)采用的保存文件的編碼格式也是 GBK 的,即,所有在中文 WIN2K 中保存的文件它的內(nèi)部編碼默認(rèn)均采用 GBK 編碼,注意: GBK 是在 GB2312 基礎(chǔ)上擴(kuò)充來(lái)的。
由于 Java 語(yǔ)言?xún)?nèi)部采用 UNICODE 編碼,所以在 JAVA 程序運(yùn)行時(shí),就存在著一個(gè)從 UNICODE 編碼和對(duì)應(yīng)的操作系統(tǒng)及瀏覽器支持的編碼格式轉(zhuǎn)換輸入、輸出的問(wèn)題,這個(gè)轉(zhuǎn)換過(guò)程有著一系列的步驟,如果其中任何一步出錯(cuò),則顯示出來(lái)的漢字就會(huì)出是亂碼,這就是我們常見(jiàn)的 JAVA 中文問(wèn)題。
同時(shí), Java 是一個(gè)跨平臺(tái)的編程語(yǔ)言,也即我們編寫(xiě)的程序不僅能在中文 windows 上運(yùn)行,也能在中文 Linux 等系統(tǒng)上運(yùn)行,同時(shí)也要求能在英文等系統(tǒng)上運(yùn)行(我們經(jīng)常看到有人把在中文 win2k 上編寫(xiě)的 JAVA 程序,移植到英文 Linux 上運(yùn)行)。這種移植操作也會(huì)帶來(lái)中文問(wèn)題。
還有,有人使用英文的操作系統(tǒng)和英文的 IE 等瀏覽器,來(lái)運(yùn)行帶中文字符的程序和瀏覽中文網(wǎng)頁(yè),它們本身就不支持中文,也會(huì)帶來(lái)中文問(wèn)題。
有,幾乎所有的瀏覽器默認(rèn)在傳遞參數(shù)時(shí)都是以 UTF-8 編碼格式來(lái)傳遞,而不是按中文編碼傳遞,所以,傳遞中文參數(shù)時(shí)也會(huì)有問(wèn)題,從而帶來(lái)亂碼現(xiàn)象。
總之,以上幾個(gè)方面是 JAVA 中的中文問(wèn)題的主要來(lái)源,我們把以上原因造成的程序不能正確運(yùn)行而產(chǎn)生的問(wèn)題稱(chēng)作: JAVA 中文問(wèn)題。
2 、 JAVA 編碼轉(zhuǎn)換的詳細(xì)過(guò)程
我們常見(jiàn)的 JAVA 程序包括以下類(lèi)別:
* 直接在 console 上運(yùn)行的類(lèi) ( 包括可視化界面的類(lèi) )
*JSP 代碼類(lèi)(注: JSP 是 Servlets 類(lèi)的變型)
*Servelets 類(lèi)
*EJB 類(lèi)
* 其它不可以直接運(yùn)行的支持類(lèi)
這些類(lèi)文件中,都有可能含有中文字符串,并且我們常用前三類(lèi) JAVA 程序和用戶(hù)直接交互,用于輸出和輸入字符,如:我們?cè)?/span> JSP 和 Servlet 中得到客戶(hù)端送來(lái)的字符,這些字符也包括中文字符。無(wú)論這些 JAVA 類(lèi)的作用如何,這些 JAVA 程序的生命周期都是這樣的:
* 編程人員在一定的操作系統(tǒng)上選擇一個(gè)合適的編輯軟件來(lái)實(shí)現(xiàn)源程序代碼并以 .java 擴(kuò)展名保存在操作系統(tǒng)中,例如我們?cè)谥形?/span> win2k 中用記事本編輯一個(gè) java 源程序;
* 編程人員用 JDK 中的 javac.exe 來(lái)編譯這些源代碼,形成 .class 類(lèi) (JSP 文件是由容器調(diào)用 JDK 來(lái)編譯的 ) ;
* 直接運(yùn)行這些類(lèi)或?qū)⑦@些類(lèi)布署到 WEB 容器中去運(yùn)行,并輸出結(jié)果。
那么,在這些過(guò)程中, JDK 和 JVM 是如何將這些文件如何編碼和解碼并運(yùn)行的呢?
這里,我們以中文 win2k 操作系統(tǒng)為例說(shuō)明 JAVA 類(lèi)是如何來(lái)編碼和被解碼的。
第一步,我們?cè)谥形?/span> win2k 中用編輯軟件如記事本編寫(xiě)一個(gè) Java 源程序文件 ( 包括以上五類(lèi) JAVA 程序 ) ,程序文件在保存時(shí)默認(rèn)采用了操作系統(tǒng)默認(rèn)支持 GBK 編碼格式 ( 操作系統(tǒng)默認(rèn)支持的格式為 file.encoding 格式 ) 形成了一個(gè) .java 文件,也即, java 程序在被編譯前,我們的 JAVA 源程序文件是采用操作系統(tǒng)默認(rèn)支持的 file.encoding 編碼格式保存的, java 源程序中含有中文信息字符和英文程序代碼;要查看系統(tǒng)的 file.encoding 參數(shù),可以用以下代碼:
public class ShowSystemDefaultEncoding {
public static void main(String[] args) {
String encoding = System.getProperty("file.encoding");
System.out.println(encoding);
}}
第二步,我們用 JDK 的 javac.exe 文件編譯我們的 Java 源程序,由于 JDK 是國(guó)際版的,在編譯的時(shí)候,如果我們沒(méi)有用 -encoding 參數(shù)指定我們的 JAVA 源程序的編碼格式,則 javac.exe 首先獲得我們操作系統(tǒng)默認(rèn)采用的編碼格式,也即在編譯 java 程序時(shí),若我們不指定源程序文件的編碼格式, JDK 首先獲得操作系統(tǒng)的 file.encoding 參數(shù) ( 它保存的就是操作系統(tǒng)默認(rèn)的編碼格式,如 WIN2k ,它的值為 GBK) ,然后 JDK 就把我們的 java 源程序從 file.encoding 編碼格式轉(zhuǎn)化為 JAVA 內(nèi)部默認(rèn)的 UNICODE 格式放入內(nèi)存中。然后, javac 把轉(zhuǎn)換后的 unicode 格式的文件進(jìn)行編譯成 .class 類(lèi)文件,此時(shí) .class 文件是 UNICODE 編碼的,它暫放在內(nèi)存中,緊接著, JDK 將此以 UNICODE 編碼的編譯后的 class 文件保存到我們的操作系統(tǒng)中形成我們見(jiàn)到的 .class 文件。對(duì)我們來(lái)說(shuō),我們最終獲得的 .class 文件是內(nèi)容以 UNICODE 編碼格式保存的類(lèi)文件,它內(nèi)部包含我們?cè)闯绦蛑械闹形淖址徊贿^(guò)此時(shí)它己經(jīng)由 file.encoding 格式轉(zhuǎn)化為 UNICODE 格式了。
這一步中,對(duì)于 JSP 源程序文件是不同的,對(duì)于 JSP ,這個(gè)過(guò)程是這樣的:即 WEB 容器調(diào)用 JSP 編譯器, JSP 編譯器先查看 JSP 文件中是否設(shè)置有文件編碼格式,如果 JSP 文件中沒(méi)有設(shè)置 JSP 文件的編碼格式,則 JSP 編譯器調(diào)用 JDK 先把 JSP 文件用 JVM 默認(rèn)的字符編碼格式 ( 也即 WEB 容器所在的操作系統(tǒng)的默認(rèn)的 file.encoding) 轉(zhuǎn)化為臨時(shí)的 Servlet 類(lèi),然后再把它編譯成 UNICODE 格式的 class 類(lèi),并保存在臨時(shí)文件夾中。如:在中文 win2k 上, WEB 容器就把 JSP 文件從 GBK 編碼格式轉(zhuǎn)化為 UNICODE 格式,然后編譯成臨時(shí)保存的 Servlet 類(lèi),以響應(yīng)用戶(hù)的請(qǐng)求。
第三步,運(yùn)行第二步編譯出來(lái)的類(lèi),分為三種情況:
A 、 直接在 console 上運(yùn)行的類(lèi)
B 、 EJB 類(lèi)和不可以直接運(yùn)行的支持類(lèi) ( 如 JavaBean 類(lèi) )
C 、 JSP 代碼和 Servlet 類(lèi)
D 、 JAVA 程序和數(shù)據(jù)庫(kù)之間
下面我們分這四種情況來(lái)看。
A 、直接在 console 上運(yùn)行的類(lèi)
這種情況,運(yùn)行該類(lèi)首先需要 JVM 支持,即操作系統(tǒng)中必須安裝有 JRE 。運(yùn)行過(guò)程是這樣的:首先 java 啟動(dòng) JVM ,此時(shí) JVM 讀出操作系統(tǒng)中保存的 class 文件并把內(nèi)容讀入內(nèi)存中,此時(shí)內(nèi)存中為 UNICODE 格式的 class 類(lèi),然后 JVM 運(yùn)行它,如果此時(shí)此類(lèi)需要接收用戶(hù)輸入,則類(lèi)會(huì)默認(rèn)用 file.encoding 編碼格式對(duì)用戶(hù)輸入的串進(jìn)行編碼并轉(zhuǎn)化為 unicode 保存入內(nèi)存(用戶(hù)可以設(shè)置輸入流的編碼格式)。程序運(yùn)行后,產(chǎn)生的字符串( UNICODE 編碼的)再回交給 JVM ,最后 JRE 把此字符串再轉(zhuǎn)化為 file.encoding 格式 ( 用戶(hù)可以設(shè)置輸出流的編碼格式 ) 傳遞給操作系統(tǒng)顯示接口并輸出到界面上。
以上每一步的轉(zhuǎn)化都需要正確的編碼格式轉(zhuǎn)化,才能最終不出現(xiàn)亂碼現(xiàn)象。
B 、 EJB 類(lèi)和不可以直接運(yùn)行的支持類(lèi) ( 如 JavaBean 類(lèi) )
由于 EJB 類(lèi)和不可以直接運(yùn)行的支持類(lèi),它們一般不與用戶(hù)直接交互輸入和輸出,它們常常與其它的類(lèi)進(jìn)行交互輸入和輸出,所以它們?cè)诘诙奖痪幾g后,就形成了內(nèi)容是 UNICODE 編碼的類(lèi)保存在操作系統(tǒng)中了,以后只要它與其它的類(lèi)之間的交互在參數(shù)傳遞過(guò)程中沒(méi)有丟失,則它就會(huì)正確的運(yùn)行。
C 、 JSP 代碼和 Servlet 類(lèi)
經(jīng)過(guò)第二步后, JSP 文件也被轉(zhuǎn)化為 Servlets 類(lèi)文件,只不過(guò)它不像標(biāo)準(zhǔn)的 Servlets 一校存在于 classes 目錄中,它存在于 WEB 容器的臨時(shí)目錄中,故這一步中我們也把它做為 Servlets 來(lái)看。
對(duì)于 Servlets ,客戶(hù)端請(qǐng)求它時(shí), WEB 容器調(diào)用它的 JVM 來(lái)運(yùn)行 Servlet ,首先, JVM 把 Servlet 的 class 類(lèi)從系統(tǒng)中讀出并裝入內(nèi)存中,內(nèi)存中是以 UNICODE 編碼的 Servlet 類(lèi)的代碼,然后 JVM 在內(nèi)存中運(yùn)行該 Servlet 類(lèi),如果 Servlet 在運(yùn)行的過(guò)程中,需要接受從客戶(hù)端傳來(lái)的字符如:表單輸入的值和 URL 中傳入的值,此時(shí)如果程序中沒(méi)有設(shè)定接受參數(shù)時(shí)采用的編碼格式,則 WEB 容器會(huì)默認(rèn)采用 ISO-8859-1 編碼格式來(lái)接受傳入的值并在 JVM 中轉(zhuǎn)化為 UNICODE 格式的保存在 WEB 容器的內(nèi)存中。 Servlet 運(yùn)行后生成輸出,輸出的字符串是 UNICODE 格式的,緊接著,容器將 Servlet 運(yùn)行產(chǎn)生的 UNICODE 格式的串(如 html 語(yǔ)法,用戶(hù)輸出的串等)直接發(fā)送到客戶(hù)端瀏覽器上并輸出給用戶(hù),如果此時(shí)指定了發(fā)送時(shí)輸出的編碼格式,則按指定的編碼格式輸出到瀏覽器上,如果沒(méi)有指定,則默認(rèn)按 ISO-8859-1 編碼發(fā)送到客戶(hù)的瀏覽器上。
D 、 Java 程序和數(shù)據(jù)庫(kù)之間
對(duì)于幾乎所有數(shù)據(jù)庫(kù)的 JDBC 驅(qū)動(dòng)程序,默認(rèn)的在 JAVA 程序和數(shù)據(jù)庫(kù)之間傳遞數(shù)據(jù)都是以 ISO-8859-1 為默認(rèn)編碼格式的,所以,我們的程序在向數(shù)據(jù)庫(kù)內(nèi)存儲(chǔ)包含中文的數(shù)據(jù)時(shí), JDBC 首先是把程序內(nèi)部的 UNICODE 編碼格式的數(shù)據(jù)轉(zhuǎn)化為 ISO-8859-1 的格式,然后傳遞到數(shù)據(jù)庫(kù)中,在數(shù)據(jù)庫(kù)保存數(shù)據(jù)時(shí),它默認(rèn)即以 ISO-8859-1 保存,所以,這是為什么我們常常在數(shù)據(jù)庫(kù)中讀出的中文數(shù)據(jù)是亂碼。
3 、分析常見(jiàn)的 JAVA 中文問(wèn)題幾個(gè)必須清楚的原則
首先,經(jīng)過(guò)上面的詳細(xì)分析,我們可以清晰地看到,任何 JAVA 程序的生命期中,其編碼轉(zhuǎn)換的關(guān)鍵過(guò)程是在于:最初編譯成 class 文件的轉(zhuǎn)碼和最終向用戶(hù)輸出的轉(zhuǎn)碼過(guò)程。
其次,我們必須了解 JAVA 在編譯時(shí)支持的、常用的編碼格式有以下幾種:
*ISO-8859-1 , 8-bit, 同 8859_1,ISO-8859-1,ISO_8859_1 等編碼
*Cp1252 ,美國(guó)英語(yǔ)編碼,同 ANSI 標(biāo)準(zhǔn)編碼
*UTF-8 ,同 unicode 編碼
*GB2312 ,同 gb2312-80,gb2312-1980 等編碼
*GBK , 同 MS936 ,它是 gb2312 的擴(kuò)充
及其它的編碼,如韓文、日文、繁體中文等。同時(shí),我們要注意這些編碼間的兼容關(guān)體系如下:
unicode 和 UTF-8 編碼是一一對(duì)應(yīng)的關(guān)系。 GB2312 可以認(rèn)為是 GBK 的子集,即 GBK 編碼是在 gb2312 上擴(kuò)展來(lái)的。同時(shí), GBK 編碼包含了 20902 個(gè)漢字,編碼范圍為: 0x8140-0xfefe ,所有的字符可以一一對(duì)應(yīng)到 UNICODE2.0 中來(lái)。
再次,對(duì)于放在操作系統(tǒng)中的 .java 源程序文件,在編譯時(shí),我們可以指定它內(nèi)容的編碼格式,具體來(lái)說(shuō)用 -encoding 來(lái)指定。注意:如果源程序中含有中文字符,而你用 -encoding 指定為其它的編碼字符,顯然是要出錯(cuò)的。用 -encoding 指定源文件的編碼方式為 GBK 或 gb2312 ,無(wú)論我們?cè)谑裁聪到y(tǒng)上編譯含有中文字符的 JAVA 源程序都不會(huì)有問(wèn)題,它都會(huì)正確地將中文轉(zhuǎn)化為 UNICODE 存儲(chǔ)在 class 文件中。
然后,我們必須清楚,幾乎所有的 WEB 容器在其內(nèi)部默認(rèn)的字符編碼格式都是以 ISO-8859-1 為默認(rèn)值的,同時(shí),幾乎所有的瀏覽器在傳遞參數(shù)時(shí)都是默認(rèn)以 UTF-8 的方式來(lái)傳遞參數(shù)的。所以,雖然我們的 Java 源文件在出入口的地方指定了正確的編碼方式,但其在容器內(nèi)部運(yùn)行時(shí)還是以 ISO-8859-1 來(lái)處理的。
4 、中文問(wèn)題的分類(lèi)及其建議最優(yōu)解決辦法
了解以上 JAVA 處理文件的原理之后,我們就可以提出了一套建議最優(yōu)的解決漢字問(wèn)題的辦法。
我們的目標(biāo)是:我們?cè)谥形南到y(tǒng)中編輯的含有中文字符串或進(jìn)行中文處理的 JAVA 源程序經(jīng)編譯后可以移值到任何其它的操作系統(tǒng)中正確運(yùn)行,或拿到其它操作系統(tǒng)中編譯后能正確運(yùn)行,能正確地傳遞中文和英文參數(shù),能正確地和數(shù)據(jù)庫(kù)交流中英文字符串。
我們的具體思路是:在 JAVA 程序轉(zhuǎn)碼的入口和出口及 JAVA 程序同用戶(hù)有輸入輸出轉(zhuǎn)換的地方限制編碼方法使之正確即可。
具體解決辦法如下:
1 、 針對(duì)直接在 console 上運(yùn)行的類(lèi)
對(duì)于這種情況,我們建議在程序編寫(xiě)時(shí),如果需要從用戶(hù)端接收用戶(hù)的可能含有中文的輸入或含有中文的輸出,程序中應(yīng)該采用字符流來(lái)處理輸入和輸出,具體來(lái)說(shuō),應(yīng)用以下面向字符型節(jié)點(diǎn)流類(lèi)型:
對(duì)文件: FileReader , FileWrieter
其字節(jié)型節(jié)點(diǎn)流類(lèi)型為: FileInputStream , FileOutputStream
對(duì)內(nèi)存(數(shù)組): CharArrayReader , CharArrayWriter
其字節(jié)型節(jié)點(diǎn)流類(lèi)型為: ByteArrayInputStream , ByteArrayOutputStream
對(duì)內(nèi)存(字符串): StringReader , StringWriter
對(duì)管道: PipedReader , PipedWriter
其字節(jié)型節(jié)點(diǎn)流類(lèi)型為: PipedInputStream , PipedOutputStream
同時(shí),應(yīng)該用以下面向字符型處理流來(lái)處理輸入和輸出:
BufferedWriter , BufferedReader
其字節(jié)型的處理流為: BufferedInputeStream , BufferedOutputStream
InputStreamReader , OutputStreamWriter
其字節(jié)型的處理流為: DataInputStream , DataOutputStream
其中 InputStreamReader 和 InputStreamWriter 用于將字節(jié)流按照指定的字符編碼集轉(zhuǎn)換到字符流,如:
InputStreamReader in = new InputStreamReader(System.in , "GB2312") ;
OutputStreamWriter out = new OutputStreamWriter (System.out , "GB2312") ;
例如:采用如下的示例 JAVA 編碼就達(dá)到了要求:
//Read.java
import java.io.*;
public class Read {
public static void main(String[] args) throws IOException {
String str = "\n 中文測(cè)試,這是內(nèi)部硬編碼的串 "+"\ntest english character";
String strin= "";
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in,"gb2312")); // 設(shè)置輸入接口按中文編碼
BufferedWriter stdout = new BufferedWriter(new OutputStreamWriter(System.out,"gb2312")); // 設(shè)置輸出接口按中文編碼
stdout.write(" 請(qǐng)輸入 :");
stdout.flush();
strin = stdin.readLine();
stdout.write(" 這是從用戶(hù)輸入的串: "+strin);
stdout.write(str);
stdout.flush();
}}
同時(shí),在編譯程序時(shí),我們用以下方式來(lái)進(jìn)行:
javac -encoding gb2312 Read.java
2 、 針對(duì) EJB 類(lèi)和不可以直接運(yùn)行的支持類(lèi) ( 如 JavaBean 類(lèi) )
由于這種類(lèi)它們本身被其它的類(lèi)調(diào)用,不直接與用戶(hù)交互,故對(duì)這種類(lèi)來(lái)說(shuō),我們的建議的處理方式是內(nèi)部程序中應(yīng)該采用字符流來(lái)處理程序內(nèi)部的中文字符串(具體如上面一節(jié)中一樣),同時(shí),在編譯類(lèi)時(shí)用 -encoding gb2312 參數(shù)指示源文件是中文格式編碼的即可。
3 、 針對(duì) Servlet 類(lèi)
針對(duì) Servlet ,我們建議用以下方法:
在編譯 Servlet 類(lèi)的源程序時(shí),用 -encoding 指定編碼為 GBK 或 GB2312 ,且在向用戶(hù)輸出時(shí)的編碼部分用 response 對(duì)象的 setContentType("text/html;charset=GBK"); 或 gb2312 來(lái)設(shè)置輸出編碼格式,同樣在接收用戶(hù)輸入時(shí),我們用 request.setCharacterEncoding("GB2312") ;這樣無(wú)論我們的 servlet 類(lèi)移植到什么操作系統(tǒng)中,只有客戶(hù)端的瀏覽器支持中文顯示,就可以正確顯示。如下是一個(gè)正確的示例:
//HelloWorld.java
package hello;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld extends HttpServlet
{
public void init() throws ServletException { }
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
request.setCharacterEncoding("GB2312"); // 設(shè)置輸入編碼格式
response.setContentType("text/html;charset=GB2312"); // 設(shè)置輸出編碼格式
PrintWriter out = response.getWriter(); // 建議使用 PrintWriter 輸出
out.println("<hr>");
out.println("Hello World! This is created by Servlet! 測(cè)試中文 !");
out.println("<hr>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
request.setCharacterEncoding("GB2312"); // 設(shè)置輸入編碼格式
response.setContentType("text/html;charset=GB2312"); // 設(shè)置輸出編碼格式
String name = request.getParameter("name");
String id = request.getParameter("id");
if(name==null) name="";
if(id==null) id="";
PrintWriter out = response.getWriter(); // 建議使用 PrintWriter 輸出
out.println("<hr>");
out.println(" 你傳入的中文字串是: " + name);
out.println("<hr> 你輸入的 id 是: " + id);
out.println("<hr>");
}
public void destroy() { }
}
請(qǐng)用 javac -encoding gb2312 HelloWorld.java 來(lái)編譯此程序。
測(cè)試此 Servlet 的程序如下所示:
<%@page contentType="text/html; charset=gb2312"%>
<%request.setCharacterEncoding("GB2312");%>
<html><head><title></title>
<Script language="JavaScript">
function Submit() {
// 通過(guò) URL 傳遞中文字符串值給 Servlet
document.base.action = "./HelloWorld?name= 中文 ";
document.base.method = "POST";
document.base.submit();
}
</Script>
</head>
<body bgcolor="#FFFFFF" text="#000000" topmargin="5">
<form name="base" method = "POST" target="_self">
<input name="id" type="text" value="" size="30">
<a href = "JavaScript:Submit()"> 傳給 Servlet</a>
</form></body></html>
4 、 JAVA 程序和數(shù)據(jù)庫(kù)之間
為避免 JAVA 程序和數(shù)據(jù)庫(kù)之間數(shù)據(jù)傳遞出現(xiàn)亂碼現(xiàn)象,我們建議采用以下最優(yōu)方法來(lái)處理:
1 、 對(duì)于 JAVA 程序的處理方法按我們指定的方法處理。
2 、 把數(shù)據(jù)庫(kù)默認(rèn)支持的編碼格式改為 GBK 或 GB2312 的。
如:在 mysql 中,我們可以在配置文件 my.ini 中加入以下語(yǔ)句實(shí)現(xiàn):
在 [mysqld] 區(qū)增加:
default-character-set=gbk
并增加:
[client]
default-character-set=gbk
在 SQL Server2K 中,我們可以將數(shù)據(jù)庫(kù)默認(rèn)的語(yǔ)言設(shè)置為 Simplified Chinese 來(lái)達(dá)到目的。
5 、 針對(duì) JSP 代碼
由于 JSP 是在運(yùn)行時(shí),由 WEB 容器進(jìn)行動(dòng)態(tài)編譯的,如果我們沒(méi)有指定 JSP 源文件的編碼格式,則 JSP 編譯器會(huì)獲得服務(wù)器操作系統(tǒng)的 file.encoding 值來(lái)對(duì) JSP 文件編譯的,它在移植時(shí)最容易出問(wèn)題,如在中文 win2k 中可以很好運(yùn)行的 jsp 文件拿到英文 linux 中就不行,盡管客戶(hù)端都是一樣的,那是因?yàn)槿萜髟诰幾g JSP 文件時(shí)獲取的操作系統(tǒng)的編碼不同造成的(在中文 wink 中的 file.encoding 和在英文 Linux 中 file.encoding 是不同的,且英文 Linux 的 file.encoding 對(duì)中文不支持,所以編譯出來(lái)的 JSP 類(lèi)就會(huì)有問(wèn)題)。網(wǎng)絡(luò)上討論的大多數(shù)是此類(lèi)問(wèn)題,多是因?yàn)?/span> JSP 文件移植平臺(tái)時(shí)不能正確顯示的問(wèn)題,對(duì)于這類(lèi)問(wèn)題,我們了解了 JAVA 中程序編碼轉(zhuǎn)換的原理,解決起來(lái)就容易多了。我們建議的解決辦法如下:
1 、我們要保證 JSP 向客戶(hù)端輸出時(shí)是采用中文編碼方式輸出的,即無(wú)論如何我們首先在我們的 JSP 源代編中加入以下一行:
<%@page contentType="text/html; charset=gb2312"%>
2 、為了讓 JSP 能正確獲得傳入的參數(shù),我們?cè)?/span> JSP 源文件頭加入下面一句:
<%request.setCharacterEncoding("GB2312");%>
3 、為了讓 JSP 編譯器能正確地解碼我們的含有中文字符的 JSP 文件,我們需要在 JSP 源文件中指定我們的 JSP 源文件的編碼格式,具體來(lái)說(shuō),我們?cè)?/span> JSP 源文件頭上加入下面的一句即可:
<%@page pageEncoding="GB2312"%> 或 <%@page pageEncoding="GBK"%>
這是 JSP 規(guī)范 2.0 新增加的指令。
我們建議使用此方法來(lái)解 JSP 文件中的中文問(wèn)題,下面的代碼是一個(gè)正確做法的 JSP 文件的測(cè)試程序:
//testchinese.jsp
<%@page pageEncoding="GB2312"%>
<%@page contentType="text/html; charset=gb2312"%>
<%request.setCharacterEncoding("GB2312");%>
<%
String action = request.getParameter("ACTION");
String name = "";
String str = "";
if(action!=null && action.equals("SENT"))
{
name = request.getParameter("name");
str = request.getParameter("str");
}
%>
<html>
<head>
<title></title>
<Script language="JavaScript">
function Submit()
{
document.base.action = "?ACTION=SENT&str= 傳入的中文 ";
document.base.method = "POST";
document.base.submit();
}
</Script>
</head>
<body bgcolor="#FFFFFF" text="#000000" topmargin="5">
<form name="base" method = "POST" target="_self">
<input type="text" name="name" value="" size="30">
<a href = "JavaScript:Submit()"> 提交 </a>
</form>
<%
if(action!=null && action.equals("SENT"))
{
out.println("<br> 你輸入的字符為: "+name);
out.println("<br> 你通過(guò) URL 傳入的字符為: "+str);
}
%>
</body>
</html>
由于大多數(shù)本地測(cè)試環(huán)境是 TOMCAT ,現(xiàn)也將其中文問(wèn)題一并附上。
Tomcat 中文問(wèn)題 - -
在 tomcat5 中發(fā)現(xiàn)了以前處理 tomcat4 的方法不能適用于處理直接通過(guò) url 提交的請(qǐng)求,上網(wǎng)找資料終于發(fā)現(xiàn)了最完美的解決辦法,不用每個(gè)地方都轉(zhuǎn)換了,而且無(wú)論 get, 和 post 都正常。寫(xiě)了個(gè)文檔,貼出來(lái)希望跟我有同樣問(wèn)題的人不再像我一樣痛苦一次 :-)
問(wèn)題描述:
1 表單提交的數(shù)據(jù),用 request.getParameter(“xxx”) 返回的字符串為亂碼或者??
2 直接通過(guò) url 如 http://localhost/a.jsp?name= 中國(guó),這樣的 get 請(qǐng)求在服務(wù)端用 request. getParameter(“name”) 時(shí)返回的是亂碼;按 tomcat4 的做法設(shè)置 Filter 也沒(méi)有用或者用 request.setCharacterEncoding("GBK"); 也不管用
原因:
1 tomcat 的 j2ee 實(shí)現(xiàn)對(duì)表單提交即 post 方式提示時(shí)處理參數(shù)采用缺省的 iso-8859-1 來(lái)處理
2 tomcat 對(duì) get 方式提交的請(qǐng)求對(duì) query-string 處理時(shí)采用了和 post 方法不一樣的處理方式。 ( 與 tomcat4 不一樣 , 所以設(shè)置 setCharacterEncoding(“gbk”)) 不起作用。
解決辦法:
首先所有的 jsp 文件都加上 :
1 實(shí)現(xiàn)一個(gè) Filter. 設(shè)置處理字符集為 GBK 。 ( 在 tomcat 的 webapps/servlet-examples 目錄有一個(gè)完整的例子。請(qǐng)參考 web.xml 和 SetCharacterEncodingFilter 的配置。 )
1) 只要把 %TOMCAT 安裝目錄 %/ webapps\servlets-examples\WEB-INF\classes\filters\SetCharacterEncodingFilter.class 文件拷到你的 webapp 目錄 /filters 下,如果沒(méi)有 filters 目錄,就創(chuàng)建一個(gè)。
2) 在你的 web.xml 里加入如下幾行: <filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3) 完成 .
2 get 方式的解決辦法
1) 打開(kāi) tomcat 的 server.xml 文件,找到區(qū)塊,加入如下一行:
URIEncoding=”GBK”
完整的應(yīng)如下:
<Connector
port="80" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true"
URIEncoding="GBK"
/>
2) 重啟 tomcat, 一切 OK 。
執(zhí)行如下 jsp 頁(yè)頁(yè)測(cè)試是否成功
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.*"%>
<%
String q=request.getParameter("q");
q = q == null? " 沒(méi)有值 " : q;
%>
<HTML>
<HEAD><TITLE> 新聞列表顯示 </TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META http-equiv=pragma content=no-cache>
<body>
你提交了:
<%=q%>
<br>
<form action="tcnchar.jsp" method="post">
輸入中文 :<input type="text" name="q"><input type="submit" value=" 確定 ">
<br>
<a href="tcnchar.jsp?q= 中國(guó) "> 通過(guò) get 方式提交 </a>
</form>
</BODY></HTML>
測(cè)試結(jié)果如果你輸入文本框或者點(diǎn)超鏈都會(huì)顯示 : 你提交了 ” 中國(guó) ”, 說(shuō)明成功 !!!!!

歡迎大家訪問(wèn)我的個(gè)人網(wǎng)站
萌萌的IT人