http://qq510219366./blog/1874487 2013 字符:人們使用的記號(hào),抽象意義上的一個(gè)符號(hào)。比如:‘1’,‘中’,‘a(chǎn)’ 字節(jié):計(jì)算機(jī)中存儲(chǔ)數(shù)據(jù)的單元,一個(gè)8位的二進(jìn)制數(shù),是一個(gè)很具體的存儲(chǔ)空間字符集:使用哪些字符。也就是說(shuō)哪些漢字,字母和符號(hào)會(huì)被收入標(biāo)準(zhǔn)中。所包含“字符”的集合就叫做“字符集”。編碼:規(guī)定每個(gè)“字符”分別用一個(gè)字節(jié)還是多個(gè)字節(jié)存儲(chǔ),用哪些字節(jié)來(lái)存儲(chǔ),這個(gè)規(guī)定就叫做“編碼” 平常我們所說(shuō)的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”這層含義外,同時(shí)也包含了“編碼”的含義。 一、編碼基本知識(shí)
1.iso8859-1 屬于單字節(jié)編碼,最多能表示的字符范圍是 0-255,應(yīng)用于英文系列。比如,字母 'a' 的編碼為0x61=97。 很明顯,iso8859-1 編碼表示的字符范圍很窄,無(wú)法表示中文字符。但是,由于是單字節(jié)編碼,和計(jì)算機(jī)最基礎(chǔ)的表示單位一致,所以很多時(shí)候,仍舊使用 iso8859-1 編碼來(lái)表示。而且在很多協(xié)議上,默認(rèn)使用該編碼。比如,雖然"中文"兩個(gè)字不存在 iso8859-1 編碼,以 gb2312 編碼為例,應(yīng)該是"d6d0 cec4" 兩個(gè)字符,使用 iso8859-1 編碼的時(shí)候則將它拆開為 4 個(gè)字節(jié)來(lái)表示:"d6 d0 ce c4"(事實(shí)上,在進(jìn)行存儲(chǔ)的時(shí)候,也是以字節(jié)為單位處理的)。而如果是 UTF 編碼,則是 6 個(gè)字節(jié) "e4 b8 ad e6 96 87"。很明顯,這種表示方法還需要以另一種編碼為基礎(chǔ)。
2.GB2312/GBK 這是漢字的國(guó)標(biāo)碼,專門用來(lái)表示漢字,是雙字節(jié)編碼,而英文字母和 iso8859-1 一致(兼容iso8859-1 編碼)。其中 gbk 編碼能夠用來(lái)同時(shí)表示繁體字和簡(jiǎn)體字,而 gb2312 只能表示簡(jiǎn)體字,gbk是兼容gb2312 編碼的。
3.Unicode 這是最統(tǒng)一的編碼,可以用來(lái)表示所有語(yǔ)言的字符,而且是定長(zhǎng)雙字節(jié)(也有四字節(jié)的)編碼,包括英文字母在內(nèi)。所以可以說(shuō)它是不兼容 iso8859-1 編碼的,也不兼容任何編碼。不過(guò),相對(duì)于iso8859-1 編碼來(lái)說(shuō),unicode 編碼只是在前面增加了一個(gè) 0 字節(jié),比如字母 'a' 為 "00 61"。 需要說(shuō)明的是,定長(zhǎng)編碼便于計(jì)算機(jī)處理(注意 GB2312/GBK 不是定長(zhǎng)編碼),而 unicode 又可以用來(lái)表示所有字符,所以在很多軟件內(nèi)部是使用 unicode 編碼來(lái)處理的,比如 java。
4.UTF 考慮到 unicode 編碼不兼容 iso8859-1 編碼,而且容易占用更多的空間:因?yàn)閷?duì)于英文字母,unicode 也需要兩個(gè)字節(jié)來(lái)表示。所以 unicode 不便于傳輸和存儲(chǔ)。因此而產(chǎn)生了 utf 編碼,utf 編碼兼容 iso8859-1 編碼,同時(shí)也可以用來(lái)表示所有語(yǔ)言的字符,不過(guò),utf 編碼是不定長(zhǎng)編碼,每一個(gè)字符的長(zhǎng)度從1-6個(gè)字節(jié)不等。另外,utf 編碼自帶簡(jiǎn)單的校驗(yàn)功能。一般來(lái)講,英文字母都是用一個(gè)字節(jié)表示,而漢字使用三個(gè)字節(jié)。注意,雖然說(shuō)utf是為了使用更少的空間而使用的,但那只是相對(duì)于 unicode編碼來(lái)說(shuō),如果已經(jīng)知道是漢字,則使用 GB2312/GBK 無(wú)疑是最節(jié)省的。不過(guò)另一方面,值得說(shuō)明的是,雖然 utf 編碼對(duì)漢字使用3個(gè)字節(jié),但即使對(duì)于漢字網(wǎng)頁(yè),utf 編碼也會(huì)比 unicode 編碼節(jié)省,因?yàn)榫W(wǎng)頁(yè)中包含了很多的英文字符。
二、JAVA 對(duì)字符的處理
1. getBytes(charset) 這是 java 字符串處理的一個(gè)標(biāo)準(zhǔn)函數(shù),其作用是將字符串所表示的字符按照 charset 編碼,并以字節(jié)方式表示。注意字符串在 java 內(nèi)存中總是按 unicode 編碼存儲(chǔ)的。當(dāng)Java程序從輸入流、文件或字符文字量等途徑獲得字符串時(shí),均會(huì)做字符編碼的轉(zhuǎn)換,例如InputStreamReader 的構(gòu)造函數(shù)中就需要指定編碼方式,而對(duì)于從文件和字符文字量中獲得字符串時(shí),均采用系統(tǒng)默認(rèn)的編碼方式對(duì)字符數(shù)據(jù)進(jìn)行解碼??紤]下面一段代碼: String str=”中”;
① byte[] bytes = str.getBytes();
② bytes = str.getBytes(“ISO-8859-1”);
③ 語(yǔ)句①:將一個(gè)只含有一個(gè)字符“中”的字符串文字量賦給 String 類的一個(gè)對(duì)象 str,字符文字量“中”是按照操作系統(tǒng)默認(rèn)編碼方式進(jìn)行編碼,在中文 windows 系統(tǒng)中通常是“GBK”,“中”在GBK編碼中是0xD6D0,在將該字符賦給str時(shí),Java會(huì)對(duì)該字符串進(jìn)行編碼轉(zhuǎn)換,即將GBK編碼方式的“中”轉(zhuǎn)換成Unicode編碼方式的“中”,Unicode編碼方式“中”的編碼是0x4E2D,所以str在程序運(yùn)行期間在內(nèi)存中的二進(jìn)制表示成16進(jìn)制就是0x4E2D。語(yǔ)句②:獲得str字符串的二進(jìn)制形式。getBytes(String encoding)方法需要指定編碼方式,表示獲得該字符串在何種編碼方式中的二進(jìn)制形式。此語(yǔ)句中沒(méi)有設(shè)置參數(shù),表示采用操作系統(tǒng)默認(rèn)的編碼方式,即此處獲得的bytes是“中”在GBK編碼中的二進(jìn)制形式,即bytes[0]=0xD6, bytes[1]=0xD0。語(yǔ)句③:該語(yǔ)句與語(yǔ)句②的區(qū)別就是指定了編碼方式,此處指定的是ISO-8859-1,即通常所說(shuō)的Latin-1,該編碼采用8bit對(duì)字符編碼,所以編碼空間中只有256個(gè)字符。該編碼中只包含了基本的ASCII碼和一些擴(kuò)展的其它西歐字符,所以該字符集中不可能包含中文的“中”字,也就是說(shuō)Java虛擬機(jī)無(wú)法在ISO-8859-1編碼集中找到“中”字對(duì)應(yīng)的編碼,針對(duì)這種情況,就只返回一個(gè)問(wèn)號(hào)(?,0x3f)字符,所以此時(shí)bytes.length只有1,且bytes[0]=0x3f。
2.new String(byte[] bytes, String encoding) getBytes()方法從字符串獲得二進(jìn)制的字節(jié)數(shù)組。如果要從二進(jìn)制的字節(jié)數(shù)組獲得字符串,則就需要使用new String(byte[] bytes, String encoding)方法,該方法按照encoding編碼方法對(duì)字節(jié)數(shù)組bytes中的二進(jìn)制數(shù)組進(jìn)行解析,生成一個(gè)新的字符串對(duì)象。
byte[] bytes = {(byte)0xD6, (byte)0xD0, (byte)0x31};
① String str = new String(bytes);
② str = new String(bytes,”ISO-8859-1”);
③ 語(yǔ)句①:定義一個(gè)字節(jié)數(shù)組。語(yǔ)句②:將該字節(jié)數(shù)組中的二進(jìn)制數(shù)據(jù)按照默認(rèn)的編碼方式(GBK)編碼成字符串,我們知道GBK中0xD6 0xD0表示“中”,0x31表示字符“1”(GBK兼容ASCII,但不兼容ISO-8859-1除ASCII之外的部分),所以str得到的值是“中1”。語(yǔ)句③:該句用ISO-8859-1編碼方式對(duì)該字節(jié)數(shù)據(jù)進(jìn)行編碼,由于在ISO-8859-1編碼方式中一個(gè)字節(jié)會(huì)被解析成一個(gè)字符,所以該字節(jié)數(shù)組會(huì)被解釋成包含三個(gè)字符的字符串,但由于在ISO-8859-1編碼方式中沒(méi)有對(duì)應(yīng)0xD6和0xD0的字符,所以前兩個(gè)字符會(huì)產(chǎn)生兩個(gè)問(wèn)號(hào),由于0x31在ISO-8859-1編碼中對(duì)應(yīng)字符“1”(ISO-8859-1也兼容ASCII),所以此語(yǔ)句得到str的值是“??1”。
3.setCharacterEncoding() 該函數(shù)用來(lái)設(shè)置http請(qǐng)求或者相應(yīng)的編碼。對(duì)于request,是指提交內(nèi)容的編碼,指定后可以通過(guò)getParameter()直接獲得正確的字符串,如果不指定,則默認(rèn)使用iso8859-1 編碼,需要進(jìn)一步處理。值得注意的是在執(zhí)行setCharacterEncoding()之前,不能執(zhí)行任何 getParameter()。而且,該指定只對(duì)POST方法有效,對(duì)GET方法無(wú)效。分析原因,應(yīng)該是在執(zhí)行第一個(gè)getParameter()的時(shí)候,java將會(huì)按照編碼分析所有的提交內(nèi)容,而后續(xù)的getParameter()不再進(jìn)行分析,所以setCharacterEncoding()無(wú)效。而對(duì)于GET方法提交表單時(shí),提交的內(nèi)容在URL中,一開始就已經(jīng)按照編碼分析所有的提交內(nèi)容,setCharacterEncoding()自然就無(wú)效。對(duì)于response,則是指定輸出內(nèi)容的編碼,同時(shí),該設(shè)置會(huì)傳遞給瀏覽器,告訴瀏覽器輸出內(nèi)容所采用的編碼。
三、頁(yè)面編碼頁(yè)面編碼主要有兩方面,一是頁(yè)面本身的編碼格式,即以什么編碼方式保存,二是客戶端瀏覽器以什么編碼格式顯示頁(yè)面。
1. 頁(yè)面保存編碼格式
1). HTML 頁(yè)面的編碼要看你保存文件時(shí)的編碼選項(xiàng),多數(shù)的網(wǎng)頁(yè)編輯軟件可以讓你選擇編碼的類型,默認(rèn)為本地編碼,為了使網(wǎng)頁(yè)減少編碼的問(wèn)題,最好保存為 UTF-8 編碼格式。
2). JSP 頁(yè)面使用下列標(biāo)簽指定 JSP 源文件的編碼格式,具體來(lái)說(shuō),我們?cè)贘SP源文件頭上加入下面的一句即可: %@page[/email] pageEncoding="xxx"%>,xxx可以為GB2312,GBK,UTF-8(和MySQL不同,MySQL是 UTF8)等等,其默認(rèn)值為ISO-8859-1。保存文件時(shí)的編碼應(yīng)該與xxx 一致。
2. 頁(yè)面顯示編碼(通知客戶端瀏覽器用什么字符集編碼顯示頁(yè)面)
1). 在 HTML 中設(shè)置頁(yè)面顯示編碼方式 使用標(biāo)簽設(shè)置頁(yè)面顯示編碼
2). 在 Servlet 中設(shè)置頁(yè)面顯示編碼方式 使用 response.setContentType("text/html; charset=xxx");來(lái)指定生成的頁(yè)面編碼。
3).在 JSP 中設(shè)置頁(yè)面顯示編碼方式 使用設(shè)置頁(yè)面顯示編碼。字符集的默認(rèn)值為ISO-8859-1。
3. 頁(yè)面輸入編碼在設(shè)置頁(yè)面顯示編碼的同時(shí),指定了頁(yè)面的輸入方式。如果沒(méi)有指定頁(yè)面編碼,則使用操作系統(tǒng)本身的默認(rèn)編碼。
四、表單傳遞參數(shù)編碼 使用表單輸入數(shù)據(jù)時(shí),處理過(guò)程如下: User input *(gbk:d6d0 cec4) browser *(gbk: d6d0 cec4) web server iso8859-1(00d6 00d 000ce 00c4) class,需要在class中進(jìn)行處理:getbytes("iso8859-1")為d6 d0 ce c4,new String("gbk")為d6d0 cec4,內(nèi)存中以 unicode編碼則為4e2d 6587。 1.用戶輸入的編碼方式和頁(yè)面指定的編碼有關(guān)。
2.從 browser 到 web server,可以在表單中指定提交內(nèi)容時(shí)使用的字符集,否則會(huì)使用頁(yè)面指定的編碼。而如果在url中直接用 ? 的方式輸入?yún)?shù),則其編碼往往是操作系統(tǒng)本身的編碼,因?yàn)檫@時(shí)和頁(yè)面無(wú)關(guān)。
3. Web server接收到的是字節(jié)流,默認(rèn)時(shí)(getParameter)會(huì)以 iso8859-1編碼處理之,結(jié)果是不正確的,所以需要進(jìn)行處理。但如果預(yù)先設(shè)置了編碼(通過(guò) request. setCharacterEncoding ()),則能夠直接獲取到正確的結(jié)果。
五、數(shù)據(jù)庫(kù)編碼
1.MySQL 的字符集 Mysql目前支持多字符集,并且,支持在不同的字符集之間轉(zhuǎn)換(便于移植和支持多語(yǔ)言)。 Mysql可以設(shè)置服務(wù)器級(jí)字符集、數(shù)據(jù)庫(kù)級(jí)字符集、數(shù)據(jù)表級(jí)字符集、表列的字符集,實(shí)際上,最終使用字符集的地方是存儲(chǔ)字符的列,比如,你設(shè)置 table1中col1列是字符類型,col1才用到了字符集,如果table1表的col2列是int類型,col2不使用字符集的概念。服務(wù)器級(jí)字符集、數(shù)據(jù)庫(kù)級(jí)字符集、數(shù)據(jù)表級(jí)字符集都是為列的字符集做默認(rèn)選項(xiàng)的。 Mysql一定有一個(gè)字符集,可以通過(guò)啟動(dòng)時(shí)加參數(shù)指定,也可以編譯時(shí)指定,也可以在配置文件里指定。Mysql服務(wù)器字符集,只是做為數(shù)據(jù)庫(kù)級(jí)的默認(rèn)值。創(chuàng)建數(shù)據(jù)庫(kù)時(shí),你可以指定字符集,如果沒(méi)指定,就使用服務(wù)器的字符集。同理,創(chuàng)建表時(shí),你可以指定表級(jí)的字符集,如果沒(méi)指定,使用數(shù)據(jù)庫(kù)的字符集做為表的字符集。創(chuàng)建列時(shí),你可以指定某列的字符集,如果沒(méi)指定,就使用表的字符集。通常情況下,您只需設(shè)置服務(wù)器級(jí)的字符集,其它的數(shù)據(jù)庫(kù)級(jí),表級(jí),以及列級(jí)的字符集,都繼承自服務(wù)器級(jí)字符集。由于UTF8是最廣的字符集,所以,一般情況下,我們?cè)O(shè)置Mysql服務(wù)器級(jí)的字符集為UTF8!
2. MySQL的存儲(chǔ)機(jī)制 MySQL 要求客戶端(mysql命令行,JDBC, PHP,CGI 等)與MySQL建立連接后,必須指定客戶端發(fā)送的數(shù)據(jù)采用的是什么字符集,也就是character_set_client;MySQL的怪異之處在于,得到的這個(gè)字符集并不立即轉(zhuǎn)換為存儲(chǔ)在數(shù)據(jù)庫(kù)中的那個(gè)字符集,而是先轉(zhuǎn)換為character_set_connection 變量指定的一個(gè)字符集;轉(zhuǎn)換為character_set_connection的這個(gè)字符集之后,再轉(zhuǎn)換為數(shù)據(jù)庫(kù)默認(rèn)的字符集character_set_database 進(jìn)行存儲(chǔ);當(dāng)這個(gè)數(shù)據(jù)被輸出時(shí),又要轉(zhuǎn)換為 character_set_results指定的字符集。 上面3個(gè)變量的作用是這樣的: character_set_client: 設(shè)置客戶端發(fā)送查詢使用的字符集 character_set_connection: 設(shè)置服務(wù)器需要將收到的查詢串轉(zhuǎn)換成的字符集 character_set_results: 設(shè)置服務(wù)器要將結(jié)果數(shù)據(jù)轉(zhuǎn)換到的字符集,轉(zhuǎn)換后才發(fā)送給客戶端 3. JAVA 與數(shù)據(jù)庫(kù) 在 JAVA 程序中使用 JDBC 連接數(shù)據(jù)庫(kù)時(shí),在URL中使用useUnicode=true和characterEncoding=utf-8兩個(gè)屬性設(shè)置Client使用的編碼。如果使用MySQL4.1以上版本、MySQL JDBC Driver3.0.16以上版本,jdbc的url不用再帶上useUnicode=true&EncodingCharacter=GBK,jdbc驅(qū)動(dòng)程序會(huì)在連接的時(shí)候自動(dòng)檢測(cè)mysql服務(wù)器的變量(character_set_server)指定的編碼,然后將該值賦給 character_set_client,character_set_connection。 使用下列語(yǔ)句可以查看 JDBC 客戶端發(fā)送給服務(wù)器的SQL使用的編碼: public void select() throws SQLException { String url = "jdbc:mysql://localhost/database"; Connection conn = DriverManager.getConnection(url); ResultSet rs = conn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_%'"); while(rs.next()){ System.out.println(rs.getString(1)+","+rs.getString(2)); } rs.close(); }
六、JAVA 編碼轉(zhuǎn)換詳細(xì)過(guò)程 我們常見(jiàn)的JAVA程序包括以下類別: *直接在console上運(yùn)行的類(包括可視化界面的類) *JSP代碼類(注:JSP是Servlets類的變型) *Servlets類 *EJB類 *其它不可以直接運(yùn)行的支持類這些類文件中,都有可能含有中文字符串,并且我們常用前三類JAVA程序和用戶直接交互,用于輸出和輸入字符,如:我們?cè)贘SP和Servlet中得到客戶端送來(lái)的字符,這些字符也包括中文字符。無(wú)論這些JAVA類的作用如何,這些JAVA程序的生命周期都是這樣的: *編程人員在一定的操作系統(tǒng)上選擇一個(gè)合適的編輯軟件來(lái)實(shí)現(xiàn)源程序代碼并以.java擴(kuò)展名保存在操作系統(tǒng)中,例如我們?cè)谥形膚in2k中用記事本編輯一個(gè)java源程序; *編程人員用JDK中的javac.exe來(lái)編譯這些源代碼,形成.class類(JSP文件是由容器調(diào)用JDK來(lái)編譯的); *直接運(yùn)行這些類或?qū)⑦@些類布署到WEB容器中去運(yùn)行,并輸出結(jié)果。那么,在這些過(guò)程中,JDK和JVM是如何將這些文件如何編碼和解碼并運(yùn)行的呢?這里,我們以中文windows xp 操作系統(tǒng)為例說(shuō)明JAVA類是如何來(lái)編碼和被解碼的。 第一步,我們?cè)谥形膚in2k中用編輯軟件如記事本編寫一個(gè)Java源程序文件(包括以上五類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編碼格式保存的;要查看系統(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類文件,此時(shí).class文件是UNICODE編碼的,它暫放在內(nèi)存中,緊接著,JDK將此以UNICODE編碼的編譯后的class文件保存到我們的操作系統(tǒng)中形成我們見(jiàn)到的.class文件。對(duì)我們來(lái)說(shuō),我們最終獲得的.class文件是內(nèi)容以UNICODE編碼格式保存的類文件,它內(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類,然后再把它編譯成UNICODE格式的class類,并保存在臨時(shí)文件夾中。如:在中文win2k上,WEB容器就把JSP文件從GBK編碼格式轉(zhuǎn)化為UNICODE格式,然后編譯成臨時(shí)保存的Servlet類,以響應(yīng)用戶的請(qǐng)求。第三步,運(yùn)行第二步編譯出來(lái)的類,分為三種情況: A、 直接在console上運(yùn)行的類 B、 EJB類和不可以直接運(yùn)行的支持類(如JavaBean類) C、 JSP代碼和Servlet類 A、直接在console上運(yùn)行的類這種情況,運(yùn)行該類首先需要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類,然后JVM運(yùn)行它,如果此時(shí)此類需要接收用戶輸入,則類會(huì)默認(rèn)用file.encoding編碼格式對(duì)用戶輸入的串進(jìn)行編碼并轉(zhuǎn)化為unicode保存入內(nèi)存(用戶可以設(shè)置輸入流的編碼格式)。程序運(yùn)行后,產(chǎn)生的字符串(UNICODE編碼的)再回交給JVM,最后JRE把此字符串再轉(zhuǎn)化為file.encoding格式(用戶可以設(shè)置輸出流的編碼格式)傳遞給操作系統(tǒng)顯示接口并輸出到界面上。以上每一步的轉(zhuǎn)化都需要正確的編碼格式轉(zhuǎn)化,才能最終不出現(xiàn)亂碼現(xiàn)象。 B、EJB類和不可以直接運(yùn)行的支持類(如JavaBean類) 由于EJB類和不可以直接運(yùn)行的支持類,它們一般不與用戶直接交互輸入和輸出,它們常常與其它的類進(jìn)行交互輸入和輸出,所以它們?cè)诘诙奖痪幾g后,就形成了內(nèi)容是UNICODE編碼的類保存在操作系統(tǒng)中了,以后只要它與其它的類之間的交互在參數(shù)傳遞過(guò)程中沒(méi)有丟失,則它就會(huì)正確的運(yùn)行。 C、JSP代碼和Servlet類經(jīng)過(guò)第二步后,JSP文件也被轉(zhuǎn)化為Servlets類文件,只不過(guò)它不像標(biāo)準(zhǔn)的Servlets一校存在于classes目錄中,它存在于WEB容器的臨時(shí)目錄中,故這一步中我們也把它做為Servlets來(lái)看。對(duì)于Servlets,客戶端請(qǐng)求它時(shí),WEB容器調(diào)用它的JVM來(lái)運(yùn)行Servlet,首先,JVM把Servlet的class類從系統(tǒng)中讀出并裝入內(nèi)存中,內(nèi)存中是以UNICODE編碼的Servlet類的代碼,然后JVM在內(nèi)存中運(yùn)行該Servlet類,如果Servlet在運(yùn)行的過(guò)程中,需要接受從客戶端傳來(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ǔ)法,用戶輸出的串等)直接發(fā)送到客戶端瀏覽器上并輸出給用戶,如果此時(shí)指定了發(fā)送時(shí)輸出的編碼格式,則按指定的編碼格式輸出到瀏覽器上,如果沒(méi)有指定,則默認(rèn)按ISO-8859-1編碼發(fā)送到客戶的瀏覽器上。
七、jsp 編譯過(guò)程(以tomcat為例)
1.Tomcat 先將整個(gè)JSP頁(yè)面的代碼讀取出來(lái),寫到一個(gè)新的JAVA文件中。在讀取JSP文件時(shí),tomcat會(huì)先去讀取JSP文件的pageEncoding屬性,然后按照pageEncoding指定的編碼來(lái)讀取JSP文件。如果pageEncoding沒(méi)有指定,tomcat會(huì)使用contentType指定的字符集編碼,如果contentType也沒(méi)有指定,就使用默認(rèn)的ISO-8859-1編碼。
2.Tomcat讀取完JSP文件后,會(huì)用UTF-8編碼將這些內(nèi)容寫道一個(gè)新的文件中,然后編譯。
3.當(dāng)JSP文件顯示的時(shí)候,會(huì)使用contentType中指定的MIME類型和charset。如果charset沒(méi)有指定,就使用pageEncoding中指定的編碼,如果pageEncoding也沒(méi)有指定,就使用默認(rèn)的ISO-8859-1編碼 |
|