- 相關(guān)推薦
JSP和servlet對中文的處理過(guò)程
Java具有簡(jiǎn)單性、面向對象、分布式、健壯性、安全性、平臺可移植性、多線(xiàn)程、動(dòng)態(tài)性等特點(diǎn)。Java可以編寫(xiě)桌面應用程序、Web應用程序、分布式系統和嵌入式系統應用程序等。下面,小編為大家搜索整理了JSP和servlet對中文的處理過(guò)程,希望能給大家帶來(lái)幫助!更多精彩內容請及時(shí)關(guān)注我們應屆畢業(yè)生考試網(wǎng)!
漢字是雙字節的。所謂雙字節是指一個(gè)雙字要占用兩個(gè)BYTE的位置(即16位),分別稱(chēng)為高位和低位。中國規定的漢字編碼為GB2312,這是強制性的,目前幾乎所有的能處理中文的應用程序都支持GB2312。GB2312包括了一二級漢字和9區符號,高位從0xa1到0xfe,低位也是從0xa1到0xfe,其中,漢字的編碼范圍為0xb0a1到0xf7fe。
另外有一種編碼,叫做GBK,但這是一份規范,不是強制的。GBK提供了20902個(gè)漢字,它兼容GB2312,編碼范圍為0x8140到0xfefe。GBK中的所有字符都可以一一映射到Unicode 2.0。
在不久的將來(lái),中國會(huì )頒布另一種標準:GB18030-2000(GBK2K)。它收錄了藏、蒙等少數民族的字型,從根本上解決了字位不足的問(wèn)題。注意:它不再是定長(cháng)的。其二字節部份與GBK兼容,四字節部分是擴充的字符、字形。它的首字節和第三字節從0x81到0xfe,二字節和第四字節從0x30到0x39。
本文不打算介紹Unicode,有興趣的可以瀏覽“http://www.unicode.org/”查看更多的信息。Unicode有一個(gè)特性:它包括了世界上所有的字符字形。所以,各個(gè)地區的語(yǔ)言都可以建立與Unicode的映射關(guān)系,而Java正是利用了這一點(diǎn)以達到異種語(yǔ)言之間的轉換。
在JDK中,與中文相關(guān)的編碼有:
表1 JDK中與中文相關(guān)的編碼列表
編碼名稱(chēng)
說(shuō) 明
ASCII
7位,與ascii7相同
ISO8859-1
8-位,與 8859_1,ISO-8859-1,ISO_8859-1,latin1...等相同
GB2312-80
16位,與gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383, Cp1383, ISO2022CN,ISO2022CN_GB...等相同
GBK
與MS936相同,注意:區分大小寫(xiě)
UTF8
與UTF-8相同
GB18030
與cp1392、1392相同,目前支持的JDK很少
在實(shí)際編程時(shí),接觸得比較多的是GB2312(GBK)和ISO8859-1。
為什么會(huì )有“?”號
上文說(shuō)過(guò),異種語(yǔ)言之間的轉換是通過(guò)Unicode來(lái)完成的。假設有兩種不同的語(yǔ)言A和B,轉換的步驟為:先把A轉化為Unicode,再把Unicode轉化為B。
舉例說(shuō)明。有GB2312中有一個(gè)漢字“李”,其編碼為“C0EE”,欲轉化為ISO8859-1編碼。步驟為:先把“李”字轉化為Unicode,得到“674E”,再把“674E”轉化為ISO8859-1字符。當然,這個(gè)映射不會(huì )成功,因為ISO8859-1中根本就沒(méi)有與“674E”對應的字符。
當映射不成功時(shí),問(wèn)題就發(fā)生了!當從某語(yǔ)言向Unicode轉化時(shí),如果在某語(yǔ)言中沒(méi)有該字符,得到的將是Unicode的代碼“uffffd”(“u”表示是Unicode編碼,)。而從Unicode向某語(yǔ)言轉化時(shí),如果某語(yǔ)言沒(méi)有對應的字符,則得到的是“0x3f”(“?”)。這就是“?”的由來(lái)。
例如:把字符流buf =“0x80 0x40 0xb0 0xa1”進(jìn)行new String(buf, "gb2312")操作,得到的結果是“ufffdu554a”,再println出來(lái),得到的結果將是“?啊”,因為“0x80 0x40”是GBK中的字符,在GB2312中沒(méi)有。
再如,把字符串String="u00d6u00ecu00e9u0046u00bbu00f9"進(jìn)行new String (buf.getBytes("GBK"))操作,得到的結果是“3fa8aca8a6463fa8b4”,其中,“u00d6”在“GBK”中沒(méi)有對應的字符,得到“3f”,“u00ec”對應著(zhù)“a8ac”,“u00e9”對應著(zhù)“a8a6”,“0046”對應著(zhù)“46”(因為這是ASCII字符),“u00bb”沒(méi)找到,得到“3f”,最后,“u00f9”對應著(zhù)“a8b4”。把這個(gè)字符串println一下,得到的結果是“?ìéF?ù”?吹?jīng)]?這里并不全是問(wèn)號,因為GBK與Unicode映射的內容中除了漢字外還有字符,本例就是最好的明證。
所以,在漢字轉碼時(shí),如果發(fā)生錯亂,得到的不一定都是問(wèn)號噢!不過(guò),錯了終究是錯了,50步和100步并沒(méi)有質(zhì)的差別。
或者會(huì )問(wèn):如果源字符集中有,而Unicode中沒(méi)有,結果會(huì )如何?回答是不知道。因為我手頭沒(méi)有能做這個(gè)測試的源字符集。但有一點(diǎn)是肯定的,那就是源字符集不夠規范。在Java中,如果發(fā)生這種情況,是會(huì )拋出異常的。
什么是UTF
UTF,是Unicode Text Format的縮寫(xiě),意為Unicode文本格式。對于UTF,是這樣定義的:
(1)如果Unicode的16位字符的頭9位是0,則用一個(gè)字節表示,這個(gè)字節的首位是“0”,剩下的7位與原字符中的后7位相同,如“u0034”(0000 0000 0011 0100),用“34” (0011 0100)表示;(與源Unicode字符是相同的);
(2)如果Unicode的16位字符的頭5位是0,則用2個(gè)字節表示,首字節是“110”開(kāi)頭,后面的5位與源字符中除去頭5個(gè)零后的最高5位相同;第二個(gè)字節以“10”開(kāi)頭,后面的6位與源字符中的低6位相同。如“u025d”(0000 0010 0101 1101),轉化后為“c99d”(1100 1001 1001 1101);
(3)如果不符合上述兩個(gè)規則,則用三個(gè)字節表示。第一個(gè)字節以“1110”開(kāi)頭,后四位為源字符的高四位;第二個(gè)字節以“10”開(kāi)頭,后六位為源字符中間的六位;第三個(gè)字節以“10”開(kāi)頭,后六位為源字符的低六位;如“u9da7”(1001 1101 1010 0111),轉化為“e9b6a7”(1110 1001 1011 0110 1010 0111);
可以這么描述JAVA程序中Unicode與UTF的關(guān)系,雖然不絕對:字符串在內存中運行時(shí),表現為Unicode代碼,而當要保存到文件或其它介質(zhì)中去時(shí),用的是UTF。這個(gè)轉化過(guò)程是由writeUTF和readUTF來(lái)完成的。
好了,基礎性的論述差不多了,下面進(jìn)入正題。
先把這個(gè)問(wèn)題想成是一個(gè)黑匣子。先看黑匣子的一級表示:
input(charsetA)->process(Unicode)->output(charsetB)
簡(jiǎn)單,這就是一個(gè)IPO模型,即輸入、處理和輸出。同樣的內容要經(jīng)過(guò)“從charsetA到unicode再到charsetB”的轉化。
再看二級表示:
SourceFile(jsp,java)->class->output
在這個(gè)圖中,可以看出,輸入的是jsp和java源文件,在處理過(guò)程中,以Class文件為載體,然后輸出。再細化到三級表示:
jsp->temp file->class->browser,os console,db
app,servlet->class->browser,os console,db
這個(gè)圖就更明白了。Jsp文件先生成中間的Java文件,再生成Class。而Servlet和普通App則直接編譯生成Class。然后,從Class再輸出到瀏覽器、控制臺或數據庫等。
JSP:從源文件到Class的過(guò)程
Jsp的源文件是以“.jsp”結尾的文本文件。在本節中,將闡述JSP文件的解釋和編譯過(guò)程,并跟蹤其中的中文變化。
1、JSP/Servlet引擎提供的JSP轉換工具(jspc)搜索JSP文件中用中指定的charset。如果在JSP文件中未指定,則取JVM中的默認設置file.encoding,一般情況下,這個(gè)值是ISO8859-1;
2、jspc用相當于“javac –encoding ”的命令解釋JSP文件中出現的所有字符,包括中文字符和ASCII字符,然后把這些字符轉換成Unicode字符,再轉化成UTF格式,存為JAVA文件。ASCII碼字符轉化為Unicode字符時(shí)只是簡(jiǎn)單地在前面加“00”,如“A”,轉化為“u0041”(不需要理由,Unicode的碼表就是這么編的)。然后,經(jīng)過(guò)到UTF的轉換,又變回“41”了!這也就是可以使用普通文本編輯器查看由JSP生成的JAVA文件的原因;
3、引擎用相當于“javac –encoding UNICODE”的命令,把JAVA文件編譯成CLASS文件;
先看一下這些過(guò)程中中文字符的轉換情況。有如下源代碼:
這段代碼是在UltraEdit for Windows上編寫(xiě)的。保存后,“中文”兩個(gè)字的16進(jìn)制編碼為“D6 D0 CE C4”(GB2312編碼)。經(jīng)查表,“中文”兩字的Unicode編碼為“u4E2Du6587”,用 UTF表示就是“E4 B8 AD E6 96 87”。打開(kāi)引擎生成的由JSP文件轉變而成的JAVA文件,發(fā)現其中的“中文”兩個(gè)字確實(shí)被“E4 B8 AD E6 96 87”替代了,再查看由JAVA文件編譯生成的CLASS文件,發(fā)現結果與JAVA文件中的完全一樣。
再看JSP中指定的CharSet為ISO-8859-1的情況。
同樣,該文件是用UltraEdit編寫(xiě)的,“中文”這兩個(gè)字也是存為GB2312編碼“D6 D0 CE C4”。先模擬一下生成的JAVA文件和CLASS文件的過(guò)程:jspc用ISO-8859-1來(lái)解釋“中文”,并把它映射到Unicode。由于ISO-8859-1是8位的,且是拉丁語(yǔ)系,其映射規則就是在每個(gè)字節前加“00”,所以,映射后的Unicode編碼應為“u00D6u00D0u00CEu00C4”,轉化成UTF后應該是“C3 96 C3 90 C3 8E C3 84”。好,打開(kāi)文件看一下,JAVA文件和CLASS文件中,“中文”果然都表示為“C3 96 C3 90 C3 8E C3 84”。
如果上述代碼中不指定,即把第一行寫(xiě)成“”,JSPC會(huì )使用file.encoding的設置來(lái)解釋JSP文件。在RedHat 6.2上,其處理結果與指定為ISO-8859-1是完全相同的。
到現在為止,已經(jīng)解釋了從JSP文件到CLASS文件的轉變過(guò)程中中文字符的映射過(guò)程。一句話(huà):從“JspCharSet到Unicode再到UTF”。下表總結了這個(gè)過(guò)程:
表2 “中文”從JSP到CLASS的轉化過(guò)程
Jsp-CharSet
JSP文件中
JAVA文件中
CLASS文件中
GB2312
D6 D0 CE C4
(GB2312)
從u4E2Du6587(Unicode)到
E4 B8 AD E6 96 87 (UTF)
E4 B8 AD E6 96 87 (UTF)
ISO-8859-1
D6 D0 CE C4
(GB2312)
從u00D6u00D0u00CEu00C4 (Unicode)到C3 96 C3 90 C3 8E C3 84 (UTF)
C3 96 C3 90 C3 8E C3 84 (UTF)
無(wú)(默認=file.encoding)
同ISO-8859-1
同ISO-8859-1
同ISO-8859-1
下節先討論Servlet從JAVA文件到CLASS文件的轉化過(guò)程,然后再解釋從CLASS文件如何輸出到客戶(hù)端。之所以這樣安排,是因為JSP和Servlet在輸出時(shí)處理方法是一樣的。
Servlet:從源文件到Class的過(guò)程
Servlet源文件是以“.java”結尾的文本文件。本節將討論Servlet的編譯過(guò)程并跟蹤其中的中文變化。
用“javac”編譯Servlet源文件。javac可以帶“-encoding ”參數,意思是“用< Compile-charset >中指定的編碼來(lái)解釋Serlvet源文件”。
源文件在編譯時(shí),用來(lái)解釋所有字符,包括中文字符和ASCII字符。然后把字符常量轉變成Unicode字符,最后,把Unicode轉變成UTF。
在Servlet中,還有一個(gè)地方設置輸出流的CharSet。通常在輸出結果前,調用HttpServletResponse的setContentType方法來(lái)達到與在JSP中設置一樣的效果,稱(chēng)之為。
注意,文中一共提到了三個(gè)變量:、和。其中,JSP文件只與有關(guān),而和只與Servlet有關(guān)。
看下例:
import javax.servlet.*;
import javax.servlet.http.*;
class testServlet extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse resp)
throws ServletException,java.io.IOException
{
resp.setContentType("text/html; charset=GB2312");
java.io.PrintWriter out=resp.getWriter();
out.println("");
out.println("#中文#");
out.println("");
}
}
該文件也是用UltraEdit for Windows編寫(xiě)的,其中的“中文”兩個(gè)字保存為“D6 D0 CE C4”(GB2312編碼)。
開(kāi)始編譯。下表是不同時(shí),CLASS文件中“中文”兩字的十六進(jìn)制碼。在編譯過(guò)程中,不起任何作用。只對CLASS文件的輸出產(chǎn)生影響,實(shí)際上是和一起,達到與JSP文件中的相同的效果,因為對編譯和CLASS文件的輸出都會(huì )產(chǎn)生影響。
表3 “中文”從Servlet源文件到Class的轉變過(guò)程
Compile-charset
Servlet源文件中
Class文件中
等效的Unicode碼
GB2312
D6 D0 CE C4
(GB2312)
E4 B8 AD E6 96 87 (UTF)
u4E2Du6587 (在Unicode中=“中文”)
ISO-8859-1
D6 D0 CE C4
(GB2312)
C3 96 C3 90 C3 8E C3 84 (UTF)
u00D6 u00D0 u00CE u00C4 (在D6 D0 CE C4前面各加了一個(gè)00)
無(wú)(默認)
D6 D0 CE C4
(GB2312)
同ISO-8859-1
同ISO-8859-1
普通Java程序的編譯過(guò)程與Servlet完全一樣。
CLASS文件中的中文表示法是不是昭然若揭了?OK,接下來(lái)看看CLASS又是怎樣輸出中文的呢?
Class:輸出字符串
上文說(shuō)過(guò),字符串在內存中表現為Unicode編碼。至于這種Unicode編碼表示了什么,那要看它是從哪種字符集映射過(guò)來(lái)的,也就是說(shuō)要看它的祖先。這好比在托運行李時(shí),外觀(guān)都是紙箱子,里面裝了什么就要看寄郵件的人實(shí)際郵了什么東西。
看看上面的例子,如果給一串Unicode編碼“00D6 00D0 00CE 00C4”,如果不作轉換,直接用Unicode碼表來(lái)對照它時(shí),是四個(gè)字符(而且是特殊字符);假如把它與“ISO8859-1”進(jìn)行映射,則直接去掉前面的“00”即可得到“D6 D0 CE C4”,這是ASCII碼表中的四個(gè)字符;而假如把它當作GB2312來(lái)進(jìn)行映射,得到的結果很可能是一大堆亂碼,因為在GB2312中有可能沒(méi)有(也有可能有)字符與00D6等字符對應(如果對應不上,將得到0x3f,也就是問(wèn)號,如果對應上了,由于00D6等字符太靠前,估計也是一些特殊符號,真正的漢字在Unicode中的編碼從4E00開(kāi)始)。
各位看到了,同樣的Unicode字符,可以解釋成不同的樣子。當然,這其中有一種是我們期望的結果。以上例而論,“D6 D0 CE C4”應該是我們所想要的,當把“D6 D0 CE C4”輸出到IE中時(shí),用“簡(jiǎn)體中文”方式查看,就能看到清楚的“中文”兩個(gè)字了。(當然了,如果你一定要用“西歐字符”來(lái)看,那也沒(méi)辦法,你將得不到任何有何時(shí)何地的東西)為什么呢?因為“00D6 00D0 00CE 00C4”本來(lái)就是由ISO8859-1轉化過(guò)去的。
給出如下結論:
在Class輸出字符串前,會(huì )將Unicode的字符串按照某一種內碼重新生成字節流,然后把字節流輸入,相當于進(jìn)行了一步“String.getBytes(???)”操作。???代表某一種字符集。
如果是Servlet,那么,這種內碼就是在HttpServletResponse.setContentType()方法中指定的內碼,也就是上文定義的。
如果是JSP,那么,這種內碼就是在中指定的內碼,也就是上文定義的。
如果是Java程序,那么,這種內碼就是file.encoding中指定的內碼,默認為ISO8859-1。
當輸出對象是瀏覽器時(shí)
以流行的瀏覽器IE為例。IE支持多種內碼。假如IE接收到了一個(gè)字節流“D6 D0 CE C4”,你可以嘗試用各種內碼去查看。你會(huì )發(fā)現用“簡(jiǎn)體中文”時(shí)能得到正確的結果。因為“D6 D0 CE C4”本來(lái)就是簡(jiǎn)體中文中“中文”兩個(gè)字的編碼。
OK,完整地看一遍。
JSP:源文件為GB2312格式的文本文件,且JSP源文件中有“中文”這兩個(gè)漢字
如果指定了為GB2312,轉化過(guò)程如下表。
表4 Jsp-charset = GB2312時(shí)的變化過(guò)程
序號
步驟說(shuō)明
結果
1
編寫(xiě)JSP源文件,且存為GB2312格式
D6 D0 CE C4
(D6D0=中 CEC4=文)
2
jspc把JSP源文件轉化為臨時(shí)JAVA文件,并把字符串按照GB2312映射到Unicode,并用UTF格式寫(xiě)入JAVA文件中
E4 B8 AD E6 96 87
3
把臨時(shí)JAVA文件編譯成CLASS文件
E4 B8 AD E6 96 87
4
運行時(shí),先從CLASS文件中用readUTF讀出字符串,在內存中的是Unicode編碼
4E 2D 65 87(在Unicode中4E2D=中 6587=文)
5
根據Jsp-charset=GB2312把Unicode轉化為字節流
D6 D0 CE C4
6
把字節流輸出到IE中,并設置IE的編碼為GB2312(作者按:這個(gè)信息隱藏在HTTP頭中)
D6 D0 CE C4
7
IE用“簡(jiǎn)體中文”查看結果
“中文”(正確顯示)
如果指定了為ISO8859-1,轉化過(guò)程如下表。
表5 Jsp-charset = ISO8859-1時(shí)的變化過(guò)程
序號
步驟說(shuō)明
結果
1
編寫(xiě)JSP源文件,且存為GB2312格式
D6 D0 CE C4
(D6D0=中 CEC4=文)
2
jspc把JSP源文件轉化為臨時(shí)JAVA文件,并把字符串按照ISO8859-1映射到Unicode,并用UTF格式寫(xiě)入JAVA文件中
C3 96 C3 90 C3 8E C3 84
3
把臨時(shí)JAVA文件編譯成CLASS文件
C3 96 C3 90 C3 8E C3 84
4
運行時(shí),先從CLASS文件中用readUTF讀出字符串,在內存中的是Unicode編碼
00 D6 00 D0 00 CE 00 C4
(啥都不是!!!)
5
根據Jsp-charset=ISO8859-1把Unicode轉化為字節流
D6 D0 CE C4
6
把字節流輸出到IE中,并設置IE的編碼為ISO8859-1(作者按:這個(gè)信息隱藏在HTTP頭中)
D6 D0 CE C4
7
IE用“西歐字符”查看結果
亂碼,其實(shí)是四個(gè)ASCII字符,但由于大于128,所以顯示出來(lái)的怪模怪樣
8
改變IE的頁(yè)面編碼為“簡(jiǎn)體中文”
“中文”(正確顯示)
奇怪了!為什么把設成GB2312和ISO8859-1是一個(gè)樣的,都能正確顯示?因為表4表5中的第2步和第5步互逆,是相互“抵消”的。只不過(guò)當指定為ISO8859-1時(shí),要增加第8步操作,殊為不便。
再看看不指定 時(shí)的情況。
表6 未指定Jsp-charset 時(shí)的變化過(guò)程
序號
步驟說(shuō)明
結果
1
編寫(xiě)JSP源文件,且存為GB2312格式
D6 D0 CE C4
(D6D0=中 CEC4=文)
2
jspc把JSP源文件轉化為臨時(shí)JAVA文件,并把字符串按照ISO8859-1映射到Unicode,并用UTF格式寫(xiě)入JAVA文件中
C3 96 C3 90 C3 8E C3 84
3
把臨時(shí)JAVA文件編譯成CLASS文件
C3 96 C3 90 C3 8E C3 84
4
運行時(shí),先從CLASS文件中用readUTF讀出字符串,在內存中的是Unicode編碼
00 D6 00 D0 00 CE 00 C4
(啥都不是!!!)
5
根據Jsp-charset=ISO8859-1把Unicode轉化為字節流
D6 D0 CE C4
6
把字節流輸出到IE中
D6 D0 CE C4
7
IE用發(fā)出請求時(shí)的頁(yè)面的編碼查看結果
視情況而定。如果是簡(jiǎn)體中文,則能正確顯示,否則,需執行表5中的第8步
Servlet:源文件為JAVA文件,格式是GB2312,源文件中含有“中文”這兩個(gè)漢字
如果=GB2312,=GB2312
表7 Compile-charset=Servlet-charset=GB2312 時(shí)的變化過(guò)程
序號
步驟說(shuō)明
結果
1
編寫(xiě)Servlet源文件,且存為GB2312格式
D6 D0 CE C4
(D6D0=中 CEC4=文)
2
用javac –encoding GB2312把JAVA源文件編譯成CLASS文件
E4 B8 AD E6 96 87 (UTF)
3
運行時(shí),先從CLASS文件中用readUTF讀出字符串,在內存中的是Unicode編碼
4E 2D 65 87 (Unicode)
4
根據Servlet-charset=GB2312把Unicode轉化為字節流
D6 D0 CE C4 (GB2312)
5
把字節流輸出到IE中并設置IE的編碼屬性為Servlet-charset=GB2312
D6 D0 CE C4 (GB2312)
6
IE用“簡(jiǎn)體中文”查看結果
“中文”(正確顯示)
如果=ISO8859-1,=ISO8859-1
表8 Compile-charset=Servlet-charset=ISO8859-1時(shí)的變化過(guò)程
序號
步驟說(shuō)明
結果
1
編寫(xiě)Servlet源文件,且存為GB2312格式
D6 D0 CE C4
(D6D0=中 CEC4=文)
2
用javac –encoding ISO8859-1把JAVA源文件編譯成CLASS文件
C3 96 C3 90 C3 8E C3 84 (UTF)
3
運行時(shí),先從CLASS文件中用readUTF讀出字符串,在內存中的是Unicode編碼
00 D6 00 D0 00 CE 00 C4
(啥都不是!!!)
4
根據Servlet-charset=ISO8859-1把Unicode轉化為字節流
D6 D0 CE C4
5
把字節流輸出到IE中并設置IE的編碼屬性為Servlet-charset=ISO8859-1
D6 D0 CE C4 (GB2312)
6
IE用“西歐字符”查看結果
亂碼(原因同表5)
7
改變IE的頁(yè)面編碼為“簡(jiǎn)體中文”
“中文”(正確顯示)
如果不指定Compile-charset或Servlet-charset,其默認值均為ISO8859-1。
當Compile-charset=Servlet-charset時(shí),第2步和第4步能互逆,“抵消”,顯示結果均能正確。讀者可試著(zhù)寫(xiě)一下Compile-charset<>Servlet-charset時(shí)的情況,肯定是不正確的。
當輸出對象是數據庫時(shí)
輸出到數據庫時(shí),原理與輸出到瀏覽器也是一樣的。本節只是Servlet為例,JSP的情況請讀者自行推導。
假設有一個(gè)Servlet,它能接收來(lái)自客戶(hù)端(IE,簡(jiǎn)體中文)的漢字字符串,然后把它寫(xiě)入到內碼為ISO8859-1的數據庫中,然后再從數據庫中取出這個(gè)字符串,顯示到客戶(hù)端。
表9
輸出對象是數據庫時(shí)的變化過(guò)程(1)
序號
步驟說(shuō)明
結果
域
1
在IE中輸入“中文”
D6 D0 CE C4
IE
2
IE把字符串轉變成UTF,并送入傳輸流中
E4 B8 AD E6 96 87
3
Servlet接收到輸入流,用readUTF讀取
4E 2D 65 87(unicode)
Servlet
4
編程者在Servlet中必須把字符串根據GB2312還原為字節流
D6 D0 CE C4
5
編程者根據數據庫內碼ISO8859-1生成新的字符串
00 D6 00 D0 00 CE 00 C4
6
把新生成的字符串提交給JDBC
00 D6 00 D0 00 CE 00 C4
7
JDBC檢測到數據庫內碼為ISO8859-1
00 D6 00 D0 00 CE 00 C4
JDBC
8
JDBC把接收到的字符串按照ISO8859-1生成字節流
D6 D0 CE C4
9
JDBC把字節流寫(xiě)入數據庫中
D6 D0 CE C4
10
完成數據存儲工作
D6 D0 CE C4 數據庫
以下是從數據庫中取出數的過(guò)程
11
JDBC從數據庫中取出字節流
D6 D0 CE C4
JDBC
12
JDBC按照數據庫的字符集ISO8859-1生成字符串,并提交給Servlet
00 D6 00 D0 00 CE 00 C4 (Unicode)
13
Servlet獲得字符串
00 D6 00 D0 00 CE 00 C4 (Unicode)
Servlet
15
編程者必須根據數據庫的內碼ISO8859-1還原成原始字節流
D6 D0 CE C4
16
編程者必須根據客戶(hù)端字符集GB2312生成新的字符串
4E 2D 65 87
(Unicode)
Servlet準備把字符串輸出到客戶(hù)端
17
Servlet根據生成字節流
D6 D0 CE C4
Servlet
18
Servlet把字節流輸出到IE中,如果已指定,還會(huì )設置IE的編碼為
D6 D0 CE C4
19
IE根據指定的編碼或默認編碼查看結果
“中文”(正確顯示)
IE
解釋一下,表中第4第5步和第15第16步是用紅色標記的,表示要由編碼者來(lái)作轉換。第4、5兩步其實(shí)就是一句話(huà):“new String(source.getBytes("GB2312"), "ISO8859-1")”。第15、16兩步也是一句話(huà):“new String(source.getBytes("ISO8859-1"), "GB2312")”。親愛(ài)的讀者,你在這樣編寫(xiě)代碼時(shí)是否意識到了其中的每一個(gè)細節呢?
至于客戶(hù)端內碼和數據庫內碼為其它值時(shí)的流程,和輸出對象是系統控制臺時(shí)的流程,請讀者自己想吧。明白了上述流程的原理,相信你可以輕松地寫(xiě)出來(lái)。
行文至此,已可告一段落了。終點(diǎn)又回到了起點(diǎn),對于編程者而言,幾乎是什么影響都沒(méi)有。
因為我們早就被告之要這么做了。
以下給出一個(gè)結論,作為結尾。
1、 在Jsp文件中,要指定contentType,其中,charset的值要與客戶(hù)端瀏覽器所用的字符集一樣;對于其中的字符串常量,不需做任何內碼轉換;對于字符串變量,要求能根據ContentType中指定的字符集還原成客戶(hù)端能識別的字節流,簡(jiǎn)單地說(shuō),就是“字符串變量是基于字符集的”;
2、 在Servlet中,必須用HttpServletResponse.setContentType()設置charset,且設置成與客戶(hù)端內碼一致;對于其中的字符串常量,需要在Javac編譯時(shí)指定encoding,這個(gè)encoding必須與編寫(xiě)源文件的平臺的字符集一樣,一般說(shuō)來(lái)都是GB2312或GBK;對于字符串變量,與JSP一樣,必須“是基于字符集的”。
【JSP和servlet對中文的處理過(guò)程】相關(guān)文章:
jsp向cookie寫(xiě)入中文亂碼的解決辦法07-08
jsp試題及答案05-07
JSP的基礎原理05-30
Java Servlet編程所需的軟件及環(huán)境配置10-04
倉儲轉型過(guò)程中需要處理哪些問(wèn)題11-02
JSP與XML的交互有哪些08-06
PHP中文文字處理技巧08-14