思想比知識更重要 成長比成功更重要
回歸blogjava |
URI(Uniform Resoure Identifier:統(tǒng)一資源標(biāo)識符),URL(Uniform Resoure Location:統(tǒng)一資源定位器),URN(Uniform Resource Name統(tǒng)一資源
名),URC(Uniform Resource Citation統(tǒng)一資源引用符)
URI、URL和URN是識別、定位和命名互聯(lián)網(wǎng)上的資源的標(biāo)準(zhǔn)途徑; URL,URN是URI的子集.
???? URI不能定位或讀取/寫入資源。這是統(tǒng)一的資源定位器(URL)的任務(wù)。URL是一種URI,但是它的大綱組件是已知的網(wǎng)絡(luò)協(xié)議(簡稱協(xié)議
),并且它把URI組件與某種協(xié)議處理程序(一種資源定位器和根據(jù)協(xié)議建立的約束規(guī)則與資源通訊的讀/寫機制)。
URI一般不能為資源提供持久不便的名稱。這是統(tǒng)一的資源命名(URN)的任務(wù)。URN也是一種URI,但是全球唯一的、持久不便的,即使資
源不在存在或不再使用。
????? web上地址的基本形式是URI,它代表統(tǒng)一資源標(biāo)識符。有兩種形式:
????? URL:目前URI的最普遍形式就是無處不在的URL或統(tǒng)一資源定位器。
????? URN:URL的一種更新形式,統(tǒng)一資源名稱(URN, Uniform Resource Name)不依賴于位置,并且有可能減少失效連接的個數(shù)。但是其流行
還需假以時日,因為它需要更精密軟件的支持。
體系中的URI、URL和URN是彼此關(guān)聯(lián)的。URI的范疇位于體系的頂層,URL和URN的范疇位于體系的底層。這種排列顯示URL和URN都是URI的子范疇
, URI表示的是統(tǒng)一的資源標(biāo)識,它是以某種統(tǒng)一的(標(biāo)準(zhǔn)化的)方式標(biāo)識資源的簡單字符串。典型情況下,這種字符串以scheme(命名URI
的名字空間的標(biāo)識符--一組相關(guān)的名稱)開頭,語法如下:
[scheme:] scheme-specific-part
URI以scheme和冒號開頭。Scheme用大寫/小寫字母開頭,后面為空或者跟著更多的大寫/小寫字母、數(shù)字、加號、減號和點號。冒號把scheme與
scheme-specific-part分開了,并且scheme-specific-part的語法和語義(意思)由URI的名字空間決定。
其中一個例子是http://www.cnn.com,其中http是scheme,//www.cnn.com是 scheme-specific-part,并且它的scheme與scheme-specific-
part被冒號分開了。
我們可以把URI按照絕對的或相對的分類。絕對的URI指以scheme(后面跟著冒號)開頭的URI。前面提到的http://www.cnn.com就是絕對的URI
的一個例子,其它的例子還有mailto:jeff@javajeff.com、news:comp.lang.java.help和xyz://whatever。你可以把絕對的URI看作是以某種方
式引用某種資源,而這種方式對標(biāo)識符出現(xiàn)的環(huán)境沒有依賴。
如果使用文件系統(tǒng)作類比,絕對的URI類似于從根目錄開始的某個文件的路徑。與絕對的URI不同的,相對的URI不是以scheme(后面跟著冒號)
開始的URI。
它的一個例子是articles/articles.html。你可以把相對的URI看作是以某種方式引用某種資源,而這種方式依賴于標(biāo)識符出現(xiàn)的環(huán)境。如果用
文件系統(tǒng)作類比,相對的URI類似于從當(dāng)前目錄開始的文件路徑。
URI:
Web上可用的每種資源 - HTML文檔、圖像、視頻片段、程序等 - 由一個通過通用資源標(biāo)志符(Universal Resource Identifier, 簡稱"URI")
進行定位。
URI一般由三部分組成:
1. 訪問資源的命名機制。
2. 存放資源的主機名。
3. 資源自身的名稱,由路徑表示。
注:大多數(shù)人可能熟悉"URL",而不是URI。URL是URI命名機制的一個子集。
URL:
URL是Uniform Resource Location的縮寫,譯為"統(tǒng)一資源定位符"。通俗地說,URL是Internet上用來描述信息資源的字符串,主要用在各種
WWW客戶程序和服務(wù)器程序上,特別是著名的Mosaic。采用URL可以用一種統(tǒng)一的格式來描述各種信息資源,包括文件、服務(wù)器的地址和目錄等
。
URL的格式
URL的格式由下列三部分組成:
第一部分是協(xié)議(或稱為服務(wù)方式);
第二部分是存有該資源的主機IP地址(有時也包括端口號);
第三部分是主機資源的具體地址。,如目錄和文件名等。
第一部分和第二部分之間用"://"符號隔開,第二部分和第三部分用"/"符號隔開。第一部分和第二部分是不可缺少的,第三部分有時可以省略
。
URL的缺點:
當(dāng)信息資源的存放地點發(fā)生變化時,必須對URL作相應(yīng)的改變。因此人們正在研究新的信息資源表示方法,例如:URI(Universal Resource
Identifier)即"通用資源標(biāo)識"(參見RFC 1630)、URN(Uniform Resource Name)即"統(tǒng)一資源名"和URC(Uniform Resource Citation)即"
統(tǒng)一資源引用符"等。
?
?1、中文問題的來源
??? 計算機最初的操作系統(tǒng)支持的編碼是單字節(jié)的字符編碼,于是,在計算機中一切處理程序最初都是以單字節(jié)編碼的英文為準(zhǔn)進行處理。隨著計算機的發(fā)展,為了適應(yīng)世界其它民族的語言(當(dāng)然包括我們的漢字),人們提出了UNICODE編碼,它采用雙字節(jié)編碼,兼容英文字符和其它民族的雙字節(jié)字符編碼,所以,目前,大多數(shù)國際***的軟件內(nèi)部均采用UNICODE編碼,在軟件運行時,它獲得本地支持系統(tǒng)(多數(shù)時間是操作系統(tǒng))默認支持的編碼格式,然后再將軟件內(nèi)部的 UNICODE轉(zhuǎn)化為本地系統(tǒng)默認支持的格式顯示出來。Java的JDK和JVM即是如此,我這里說的JDK是指國際版的JDK,我們大多數(shù)程序員使用的是國際化的JDK版本,以下所有的JDK均指國際化的JDK版本。我們的漢字是雙字節(jié)編碼語言,為了能讓計算機處理中文,我們自己制定的gb2312、 GBK、GBK2K等標(biāo)準(zhǔn)以適應(yīng)計算機處理的需求。所以,大部分的操作系統(tǒng)為了適應(yīng)我們處理中文的需求,均定制有中文操作系統(tǒng),它們采用的是GBK, GB2312編碼格式以正確顯示我們的漢字。如:中文Win2K默認采用的是GBK編碼顯示,在中文WIN2k中保存文件時默認采用的保存文件的編碼格式也是GBK的,即,所有在中文WIN2K中保存的文件它的內(nèi)部編碼默認均采用GBK編碼,注意:GBK是在GB2312基礎(chǔ)上擴充來的。
??? 由于Java語言內(nèi)部采用UNICODE編碼,所以在JAVA程序運行時,就存在著一個從UNICODE編碼和對應(yīng)的操作系統(tǒng)及瀏覽器支持的編碼格式轉(zhuǎn)換輸入、輸出的問題,這個轉(zhuǎn)換過程有著一系列的步驟,如果其中任何一步出錯,則顯示出來的漢字就會出是亂碼,這就是我們常見的JAVA中文問題。
??? 同時,Java是一個跨平臺的編程語言,也即我們編寫的程序不僅能在中文windows上運行,也能在中文Linux等系統(tǒng)上運行,同時也要求能在英文等系統(tǒng)上運行(我們經(jīng)常看到有人把在中文win2k上編寫的JAVA程序,移植到英文Linux上運行)。這種移植操作也會帶來中文問題。
??? 還有,有人使用英文的操作系統(tǒng)和英文的IE等瀏覽器,來運行帶中文字符的程序和瀏覽中文網(wǎng)頁,它們本身就不支持中文,也會帶來中文問題。
??? 幾乎所有的瀏覽器默認在傳遞參數(shù)時都是以UTF-8編碼格式來傳遞,而不是按中文編碼傳遞,所以,傳遞中文參數(shù)時也會有問題,從而帶來亂碼現(xiàn)象。
??? 總之,以上幾個方面是JAVA中的中文問題的主要來源,我們把以上原因造成的程序不能正確運行而產(chǎn)生的問題稱作:JAVA中文問題。
2、JAVA編碼轉(zhuǎn)換的詳細過程
??? 我們常見的JAVA程序包括以下類別:
???? *直接在console上運行的類(包括可視化界面的類)
???? *JSP代碼類(注:JSP是Servlets類的變型)
???? *Servelets類
???? *EJB類
???? *其它不可以直接運行的支持類
??? 這些類文件中,都有可能含有中文字符串,并且我們常用前三類JAVA程序和用戶直接交互,用于輸出和輸入字符,如:我們在JSP和Servlet中得到客戶端送來的字符,這些字符也包括中文字符。無論這些JAVA類的作用如何,這些JAVA程序的生命周期都是這樣的:
??? *編程人員在一定的操作系統(tǒng)上選擇一個合適的編輯軟件來實現(xiàn)源程序代碼并以.java擴展名保存在操作系統(tǒng)中,例如我們在中文win2k中用記事本編輯一個java源程序;
???? *編程人員用JDK中的javac.exe來編譯這些源代碼,形成.class類(JSP文件是由容器調(diào)用JDK來編譯的);
???? *直接運行這些類或?qū)⑦@些類布署到WEB容器中去運行,并輸出結(jié)果。
??? 那么,在這些過程中,JDK和JVM是如何將這些文件如何編碼和解碼并運行的呢?
這里,我們以中文win2k操作系統(tǒng)為例說明JAVA類是如何來編碼和被解碼的。
??? 第一步,我們在中文win2k中用編輯軟件如記事本編寫一個Java源程序文件(包括以上五類JAVA 程序),程序文件在保存時默認采用了操作系統(tǒng)默認支持GBK編碼格式(操作系統(tǒng)默認支持的格式為file.encoding格式)形成了一個.java文件,也即,java程序在被編譯前,我們的JAVA源程序文件是采用操作系統(tǒng)默認支持的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是國際版的,在編譯的時候,如果我們沒有用-encoding參數(shù)指定我們的 JAVA源程序的編碼格式,則javac.exe首先獲得我們操作系統(tǒng)默認采用的編碼格式,也即在編譯java程序時,若我們不指定源程序文件的編碼格式,JDK首先獲得操作系統(tǒng)的file.encoding參數(shù)(它保存的就是操作系統(tǒng)默認的編碼格式,如WIN2k,它的值為GBK),然后JDK就把我們的java源程序從file.encoding編碼格式轉(zhuǎn)化為JAVA內(nèi)部默認的 UNICODE格式放入內(nèi)存中。然后,javac把轉(zhuǎn)換后的unicode格式的文件進行編譯成.class類文件,此時.class文件是 UNICODE編碼的,它暫放在內(nèi)存中,緊接著,JDK將此以UNICODE編碼的編譯后的class文件保存到我們的操作系統(tǒng)中形成我們見到的. class文件。對我們來說,我們最終獲得的.class文件是內(nèi)容以UNICODE編碼格式保存的類文件,它內(nèi)部包含我們源程序中的中文字符串,只不過此時它己經(jīng)由file.encoding格式轉(zhuǎn)化為UNICODE格式了。
??? 這一步中,對于JSP源程序文件是不同的,對于JSP,這個過程是這樣的:即WEB容器調(diào)用JSP編譯器,JSP編譯器先查看JSP文件中是否設(shè)置有文件編碼格式,如果JSP文件中沒有設(shè)置JSP文件的編碼格式,則JSP編譯器調(diào)用JDK先把JSP文件用JVM默認的字符編碼格式(也即WEB容器所在的操作系統(tǒng)的默認的file.encoding)轉(zhuǎn)化為臨時的Servlet類,然后再把它編譯成UNICODE格式的class類,并保存在臨時文件夾中。如:在中文win2k上,WEB容器就把JSP文件從GBK編碼格式轉(zhuǎn)化為UNICODE格式,然后編譯成臨時保存的Servlet類,以響應(yīng)用戶的請求。
??? 第三步,運行第二步編譯出來的類,分為三種情況:
??? A、 直接在console上運行的類
??? B、 EJB類和不可以直接運行的支持類(如JavaBean類)
??? C、 JSP代碼和Servlet類
??? D、 JAVA程序和數(shù)據(jù)庫之間
??? 下面我們分這四種情況來看。
??? A、直接在console上運行的類
??? 這種情況,運行該類首先需要JVM支持,即操作系統(tǒng)中必須安裝有JRE。運行過程是這樣的:首先java啟動JVM,此時JVM讀出操作系統(tǒng)中保存的 class文件并把內(nèi)容讀入內(nèi)存中,此時內(nèi)存中為UNICODE格式的class類,然后JVM運行它,如果此時此類需要接收用戶輸入,則類會默認用 file.encoding編碼格式對用戶輸入的串進行編碼并轉(zhuǎn)化為unicode保存入內(nèi)存(用戶可以設(shè)置輸入流的編碼格式)。程序運行后,產(chǎn)生的字符串(UNICODE編碼的)再回交給JVM,最后JRE把此字符串再轉(zhuǎn)化為file.encoding格式(用戶可以設(shè)置輸出流的編碼格式)傳遞給操作系統(tǒng)顯示接口并輸出到界面上。
??? 對于這種直接在console上運行的類,它的轉(zhuǎn)化過程可用圖1更加明確的表示出來:
圖1
以上每一步的轉(zhuǎn)化都需要正確的編碼格式轉(zhuǎn)化,才能最終不出現(xiàn)亂碼現(xiàn)象。
??? B、EJB類和不可以直接運行的支持類(如JavaBean類)
??? 由于EJB類和不可以直接運行的支持類,它們一般不與用戶直接交互輸入和輸出,它們常常與其它的類進行交互輸入和輸出,所以它們在第二步被編譯后,就形成了內(nèi)容是UNICODE編碼的類保存在操作系統(tǒng)中了,以后只要它與其它的類之間的交互在參數(shù)傳遞過程中沒有丟失,則它就會正確的運行。
這種EJB類和不可以直接運行的支持類, 它的轉(zhuǎn)化過程可用圖2更加明確的表示出來:
圖2
??? C、JSP代碼和Servlet類
??? 經(jīng)過第二步后,JSP文件也被轉(zhuǎn)化為Servlets類文件,只不過它不像標(biāo)準(zhǔn)的Servlets一校存在于classes目錄中,它存在于WEB容器的臨時目錄中,故這一步中我們也把它做為Servlets來看。
??? 對于Servlets,客戶端請求它時,WEB容器調(diào)用它的JVM來運行Servlet,首先,JVM把Servlet的class類從系統(tǒng)中讀出并裝入內(nèi)存中,內(nèi)存中是以UNICODE編碼的Servlet類的代碼,然后JVM在內(nèi)存中運行該Servlet類,如果Servlet在運行的過程中,需要接受從客戶端傳來的字符如:表單輸入的值和URL中傳入的值,此時如果程序中沒有設(shè)定接受參數(shù)時采用的編碼格式,則WEB容器會默認采用ISO-8859- 1編碼格式來接受傳入的值并在JVM中轉(zhuǎn)化為UNICODE格式的保存在WEB容器的內(nèi)存中。Servlet運行后生成輸出,輸出的字符串是 UNICODE格式的,緊接著,容器將Servlet運行產(chǎn)生的UNICODE格式的串(如html語法,用戶輸出的串等)直接發(fā)送到客戶端瀏覽器上并輸出給用戶,如果此時指定了發(fā)送時輸出的編碼格式,則按指定的編碼格式輸出到瀏覽器上,如果沒有指定,則默認按ISO-8859-1編碼發(fā)送到客戶的瀏覽器上。這種JSP代碼和Servlet類,它的轉(zhuǎn)化過程可用圖3更加明確地表示出來:
圖3
D、Java程序和數(shù)據(jù)庫之間
??? 對于幾乎所有數(shù)據(jù)庫的JDBC驅(qū)動程序,默認的在JAVA程序和數(shù)據(jù)庫之間傳遞數(shù)據(jù)都是以ISO-8859-1為默認編碼格式的,所以,我們的程序在向數(shù)據(jù)庫內(nèi)存儲包含中文的數(shù)據(jù)時,JDBC首先是把程序內(nèi)部的UNICODE編碼格式的數(shù)據(jù)轉(zhuǎn)化為ISO-8859-1的格式,然后傳遞到數(shù)據(jù)庫中,在數(shù)據(jù)庫保存數(shù)據(jù)時,它默認即以ISO-8859-1保存,所以,這是為什么我們常常在數(shù)據(jù)庫中讀出的中文數(shù)據(jù)是亂碼。
??? 對于JAVA程序和數(shù)據(jù)庫之間的數(shù)據(jù)傳遞,我們可以用圖4清晰地表示出來
圖4
??? 3、分析常見的JAVA中文問題幾個必須清楚的原則
??? 首先,經(jīng)過上面的詳細分析,我們可以清晰地看到,任何JAVA程序的生命期中,其編碼轉(zhuǎn)換的關(guān)鍵過程是在于:最初編譯成class文件的轉(zhuǎn)碼和最終向用戶輸出的轉(zhuǎn)碼過程。
??? 其次,我們必須了解JAVA在編譯時支持的、常用的編碼格式有以下幾種:
??? *ISO-8859-1,8-bit, 同8859_1,ISO-8859-1,ISO_8859_1等編碼
??? *Cp1252,美國英語編碼,同ANSI標(biāo)準(zhǔn)編碼
??? *UTF-8,同unicode編碼
??? *GB2312,同gb2312-80,gb2312-1980等編碼
??? *GBK , 同MS936,它是gb2312的擴充
??? 及其它的編碼,如韓文、日文、繁體中文等。同時,我們要注意這些編碼間的兼容關(guān)體系如下:
??? unicode和UTF-8編碼是一一對應(yīng)的關(guān)系。GB2312可以認為是GBK的子集,即GBK編碼是在gb2312上擴展來的。同時,GBK編碼包含了20902個漢字,編碼范圍為:0x8140-0xfefe,所有的字符可以一一對應(yīng)到UNICODE2.0中來。
??? 再次,對于放在操作系統(tǒng)中的.java源程序文件,在編譯時,我們可以指定它內(nèi)容的編碼格式,具體來說用-encoding來指定。注意:如果源程序中含有中文字符,而你用-encoding指定為其它的編碼字符,顯然是要出錯的。用-encoding指定源文件的編碼方式為GBK或gb2312,無論我們在什么系統(tǒng)上編譯含有中文字符的JAVA源程序都不會有問題,它都會正確地將中文轉(zhuǎn)化為UNICODE存儲在class文件中。
????
??? 然后,我們必須清楚,幾乎所有的WEB容器在其內(nèi)部默認的字符編碼格式都是以ISO-8859-1為默認值的,同時,幾乎所有的瀏覽器在傳遞參數(shù)時都是默認以UTF-8的方式來傳遞參數(shù)的。所以,雖然我們的Java源文件在出入口的地方指定了正確的編碼方式,但其在容器內(nèi)部運行時還是以ISO-8859- 1來處理的。
??? 了解以上JAVA處理文件的原理之后,我們就可以提出了一套建議最優(yōu)的解決漢字問題的辦法。
??? 我們的目標(biāo)是:我們在中文系統(tǒng)中編輯的含有中文字符串或進行中文處理的JAVA源程序經(jīng)編譯后可以移值到任何其它的操作系統(tǒng)中正確運行,或拿到其它操作系統(tǒng)中編譯后能正確運行,能正確地傳遞中文和英文參數(shù),能正確地和數(shù)據(jù)庫交流中英文字符串。
??? 我們的具體思路是:在JAVA程序轉(zhuǎn)碼的入口和出口及JAVA程序同用戶有輸入輸出轉(zhuǎn)換的地方限制編碼方法使之正確即可。
??? 具體解決辦法如下:
??? 1、 針對直接在console上運行的類
??? 對于這種情況,我們建議在程序編寫時,如果需要從用戶端接收用戶的可能含有中文的輸入或含有中文的輸出,程序中應(yīng)該采用字符流來處理輸入和輸出,具體來說,應(yīng)用以下面向字符型節(jié)點流類型:
??? 對文件:FileReader,F(xiàn)ileWrieter
??????? 其字節(jié)型節(jié)點流類型為:FileInputStream,F(xiàn)ileOutputStream
??? 對內(nèi)存(數(shù)組):CharArrayReader,CharArrayWriter
??????? 其字節(jié)型節(jié)點流類型為:ByteArrayInputStream,ByteArrayOutputStream
??? 對內(nèi)存(字符串):StringReader,StringWriter
??? 對管道:PipedReader,PipedWriter
??????? 其字節(jié)型節(jié)點流類型為:PipedInputStream,PipedOutputStream
??? 同時,應(yīng)該用以下面向字符型處理流來處理輸入和輸出:
??? 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編碼就達到了要求:
??? //Read.java
??? import java.io.*;
??? public class Read {
??? public static void main(String[] args) throws IOException {
??? String str = "\n中文測試,這是內(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("請輸入:");
??? stdout.flush();
??? strin = stdin.readLine();
??? stdout.write("這是從用戶輸入的串:"+strin);
??? stdout.write(str);
??? stdout.flush();
??? }}
??? 同時,在編譯程序時,我們用以下方式來進行:
??? javac -encoding gb2312 Read.java
??? 其運行結(jié)果如圖5所示:
??? 圖5
2、 針對EJB類和不可以直接運行的支持類(如JavaBean類)
??? 由于這種類它們本身被其它的類調(diào)用,不直接與用戶交互,故對這種類來說,我們的建議的處理方式是內(nèi)部程序中應(yīng)該采用字符流來處理程序內(nèi)部的中文字符串(具體如上面一節(jié)中一樣),同時,在編譯類時用-encoding gb2312參數(shù)指示源文件是中文格式編碼的即可。
??? 3、 針對Servlet類
??? 針對Servlet,我們建議用以下方法:(我建議將.java文件設(shè)置為UTF8編碼的。當(dāng)然如果是用Eclipse的話,只要設(shè)置下就是了。對于數(shù)據(jù)庫,我以為編碼最好設(shè)置為UTF8,便于國際化?。盡可能的使用UTF8碼,? 千里草)
??? 在編譯Servlet類的源程序時,用-encoding指定編碼為GBK或GB2312,且在向用戶輸出時的編碼部分用response對象的 setContentType("text/html;charset=GBK");或gb2312來設(shè)置輸出編碼格式,同樣在接收用戶輸入時,我們用 request.setCharacterEncoding("GB2312");這樣無論我們的servlet類移植到什么操作系統(tǒng)中,只有客戶端的瀏覽器支持中文顯示,就可以正確顯示。如下是一個正確的示例:
??? //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!測試中文!");
??? 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() { }
??? }
??????? 請用javac -encoding gb2312 HelloWorld.java來編譯此程序。
??????? 測試此Servlet的程序如下所示:
??? <%@page contentType="text/html; charset=gb2312"%>
??? <%request.setCharacterEncoding("GB2312");%>
??? <html><head><title></title>
??? <Script language="JavaScript">
??? function Submit() {
??? //通過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>
??? 其運行結(jié)果如圖6所示:
??? 圖6
??? 4、 JAVA程序和數(shù)據(jù)庫之間
??? 為避免JAVA程序和數(shù)據(jù)庫之間數(shù)據(jù)傳遞出現(xiàn)亂碼現(xiàn)象,我們建議采用以下最優(yōu)方法來處理:
??? 1、 對于JAVA程序的處理方法按我們指定的方法處理。
??? 2、 把數(shù)據(jù)庫默認支持的編碼格式改為GBK或GB2312的。
??? 如:在mysql中,我們可以在配置文件my.ini中加入以下語句實現(xiàn):
??? 在[mysqld]區(qū)增加:
??? default-character-set=gbk
??? 并增加:
??? [client]
??? default-character-set=gbk
??? 在SQL Server2K中,我們可以將數(shù)據(jù)庫默認的語言設(shè)置為Simplified Chinese來達到目的。
??? 5、 針對JSP代碼
??? 由于JSP是在運行時,由WEB容器進行動態(tài)編譯的,如果我們沒有指定JSP源文件的編碼格式,則JSP編譯器會獲得服務(wù)器操作系統(tǒng)的 file.encoding值來對JSP文件編譯的,它在移植時最容易出問題,如在中文win2k中可以很好運行的jsp文件拿到英文linux中就不行,盡管客戶端都是一樣的,那是因為容器在編譯JSP文件時獲取的操作系統(tǒng)的編碼不同造成的(在中文wink中的file.encoding和在英文 Linux中file.encoding是不同的,且英文Linux的file.encoding對中文不支持,所以編譯出來的JSP類就會有問題)。網(wǎng)絡(luò)上討論的大多數(shù)是此類問題,多是因為JSP文件移植平臺時不能正確顯示的問題,對于這類問題,我們了解了JAVA中程序編碼轉(zhuǎn)換的原理,解決起來就容易多了。我們建議的解決辦法如下:
??? 1、我們要保證JSP向客戶端輸出時是采用中文編碼方式輸出的,即無論如何我們首先在我們的JSP源代編中加入以下一行:
??? <%@page contentType="text/html; charset=gb2312"%>
??? 2、為了讓JSP能正確獲得傳入的參數(shù),我們在JSP源文件頭加入下面一句:
??? <%request.setCharacterEncoding("GB2312");%>
??? 3、為了讓JSP編譯器能正確地解碼我們的含有中文字符的JSP文件,我們需要在JSP源文件中指定我們的JSP源文件的編碼格式,具體來說,我們在JSP源文件頭上加入下面的一句即可:
??? <%@page pageEncoding="GB2312"%>或<%@page pageEncoding="GBK"%>
??? 這是JSP規(guī)范2.0新增加的指令。
??? 我們建議使用此方法來解JSP文件中的中文問題,下面的代碼是一個正確做法的JSP文件的測試程序:
//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>你通過URL傳入的字符為:"+str);
??? }
??? %>
??? </body>
??? </html>
??? 如圖7是此程序運行的結(jié)果示意圖:
??? 圖7
??? 5、總結(jié)
??? 在上面的詳細分析中,我們清晰地給出了JAVA在處理源程序過程中的詳細轉(zhuǎn)換過程,為我們正確解決JAVA編程中的中文問題提供了基礎(chǔ)。同時,我們給出了認為是最優(yōu)的解決JAVA中文問題的辦法。
我的補充(需要特別注意): 在表單(form )提交時,如果提交的方法為get,那么request.setCharacterEncoding() 是不起作用的。此時在服務(wù)器端得到的字符編碼仍然是ISO8859-1,而不是你設(shè)置的編碼。所以一般我們在提交數(shù)據(jù)時,盡量使用post方法,此時 request.setCharacterEncoding()方法起效。作者:郎云鵬(dev2dev ID: hippiewolf)
摘要:雖然session機制在web應(yīng)用程序中被采用已經(jīng)很長時間了,但是仍然有很多人不清楚session機制的本質(zhì),以至不能正確的應(yīng)用這一技術(shù)。本文將詳細討論session的工作機制并且對在Java web application中應(yīng)用session機制時常見的問題作出解答。
目錄:
一、術(shù)語session
二、HTTP協(xié)議與狀態(tài)保持
三、理解cookie機制
四、理解session機制
五、理解javax.servlet.http.HttpSession
六、HttpSession常見問題
七、跨應(yīng)用程序的session共享
八、總結(jié)
參考文檔
一、術(shù)語session
在我的經(jīng)驗里,session這個詞被濫用的程度大概僅次于transaction,更加有趣的是transaction與session在某些語境下的含義是相同的。
session,中文經(jīng)常翻譯為會話,其本來的含義是指有始有終的一系列動作/消息,比如打電話時從拿起電話撥號到掛斷電話這中間的一系列過程可以稱之為一個 session。有時候我們可以看到這樣的話“在一個瀏覽器會話期間,...”,這里的會話一詞用的就是其本義,是指從一個瀏覽器窗口打開到關(guān)閉這個期間 ①。最混亂的是“用戶(客戶端)在一次會話期間”這樣一句話,它可能指用戶的一系列動作(一般情況下是同某個具體目的相關(guān)的一系列動作,比如從登錄到選購商品到結(jié)賬登出這樣一個網(wǎng)上購物的過程,有時候也被稱為一個transaction),然而有時候也可能僅僅是指一次連接,也有可能是指含義①,其中的差別只能靠上下文來推斷②。
然而當(dāng)session一詞與網(wǎng)絡(luò)協(xié)議相關(guān)聯(lián)時,它又往往隱含了“面向連接”和/或“保持狀態(tài)”這樣兩個含義,“面向連接”指的是在通信雙方在通信之前要先建立一個通信的渠道,比如打電話,直到對方接了電話通信才能開始,與此相對的是寫信,在你把信發(fā)出去的時候你并不能確認對方的地址是否正確,通信渠道不一定能建立,但對發(fā)信人來說,通信已經(jīng)開始了。“保持狀態(tài)”則是指通信的一方能夠把一系列的消息關(guān)聯(lián)起來,使得消息之間可以互相依賴,比如一個服務(wù)員能夠認出再次光臨的老顧客并且記得上次這個顧客還欠店里一塊錢。這一類的例子有“一個TCP session”或者“一個POP3 session”③。
而到了web服務(wù)器蓬勃發(fā)展的時代,session在web開發(fā)語境下的語義又有了新的擴展,它的含義是指一類用來在客戶端與服務(wù)器之間保持狀態(tài)的解決方案 ④。有時候session也用來指這種解決方案的存儲結(jié)構(gòu),如“把xxx保存在session里”⑤。由于各種用于web開發(fā)的語言在一定程度上都提供了對這種解決方案的支持,所以在某種特定語言的語境下,session也被用來指代該語言的解決方案,比如經(jīng)常把Java里提供的 javax.servlet.http.HttpSession簡稱為session⑥。
鑒于這種混亂已不可改變,本文中session一詞的運用也會根據(jù)上下文有不同的含義,請大家注意分辨。
在本文中,使用中文“瀏覽器會話期間”來表達含義①,使用“session機制”來表達含義④,使用“session”表達含義⑤,使用具體的“HttpSession”來表達含義⑥
二、HTTP協(xié)議與狀態(tài)保持
HTTP協(xié)議本身是無狀態(tài)的,這與HTTP協(xié)議本來的目的是相符的,客戶端只需要簡單的向服務(wù)器請求下載某些文件,無論是客戶端還是服務(wù)器都沒有必要紀錄彼此過去的行為,每一次請求之間都是獨立的,好比一個顧客和一個自動售貨機或者一個普通的(非會員制)大賣場之間的關(guān)系一樣。
然而聰明(或者貪心?)的人們很快發(fā)現(xiàn)如果能夠提供一些按需生成的動態(tài)信息會使web變得更加有用,就像給有線電視加上點播功能一樣。這種需求一方面迫使 HTML逐步添加了表單、腳本、DOM等客戶端行為,另一方面在服務(wù)器端則出現(xiàn)了CGI規(guī)范以響應(yīng)客戶端的動態(tài)請求,作為傳輸載體的HTTP協(xié)議也添加了文件上載、cookie這些特性。其中cookie的作用就是為了解決HTTP協(xié)議無狀態(tài)的缺陷所作出的努力。至于后來出現(xiàn)的session機制則是又一種在客戶端與服務(wù)器之間保持狀態(tài)的解決方案。
讓我們用幾個例子來描述一下cookie和session機制之間的區(qū)別與聯(lián)系。筆者曾經(jīng)常去的一家咖啡店有喝5杯咖啡免費贈一杯咖啡的優(yōu)惠,然而一次性消費5杯咖啡的機會微乎其微,這時就需要某種方式來紀錄某位顧客的消費數(shù)量。想象一下其實也無外乎下面的幾種方案:
1、該店的店員很厲害,能記住每位顧客的消費數(shù)量,只要顧客一走進咖啡店,店員就知道該怎么對待了。這種做法就是協(xié)議本身支持狀態(tài)。
2、發(fā)給顧客一張卡片,上面記錄著消費的數(shù)量,一般還有個有效期限。每次消費時,如果顧客出示這張卡片,則此次消費就會與以前或以后的消費相聯(lián)系起來。這種做法就是在客戶端保持狀態(tài)。
3、發(fā)給顧客一張會員卡,除了卡號之外什么信息也不紀錄,每次消費時,如果顧客出示該卡片,則店員在店里的紀錄本上找到這個卡號對應(yīng)的紀錄添加一些消費信息。這種做法就是在服務(wù)器端保持狀態(tài)。
由于HTTP協(xié)議是無狀態(tài)的,而出于種種考慮也不希望使之成為有狀態(tài)的,因此,后面兩種方案就成為現(xiàn)實的選擇。具體來說cookie機制采用的是在客戶端保持狀態(tài)的方案,而session機制采用的是在服務(wù)器端保持狀態(tài)的方案。同時我們也看到,由于采用服務(wù)器端保持狀態(tài)的方案在客戶端也需要保存一個標(biāo)識,所以session機制可能需要借助于cookie機制來達到保存標(biāo)識的目的,但實際上它還有其他選擇。
三、理解cookie機制
cookie機制的基本原理就如上面的例子一樣簡單,但是還有幾個問題需要解決:“會員卡”如何分發(fā);“會員卡”的內(nèi)容;以及客戶如何使用“會員卡”。
正統(tǒng)的cookie分發(fā)是通過擴展HTTP協(xié)議來實現(xiàn)的,服務(wù)器通過在HTTP的響應(yīng)頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應(yīng)的cookie。然而純粹的客戶端腳本如Javascript或者VBscript也可以生成cookie。
而cookie 的使用是由瀏覽器按照一定的原則在后臺自動發(fā)送給服務(wù)器的。瀏覽器檢查所有存儲的cookie,如果某個cookie所聲明的作用范圍大于等于將要請求的資源所在的位置,則把該cookie附在請求資源的HTTP請求頭上發(fā)送給服務(wù)器。意思是麥當(dāng)勞的會員卡只能在麥當(dāng)勞的店里出示,如果某家分店還發(fā)行了自己的會員卡,那么進這家店的時候除了要出示麥當(dāng)勞的會員卡,還要出示這家店的會員卡。
cookie的內(nèi)容主要包括:名字,值,過期時間,路徑和域。
其中域可以指定某一個域比如.google.com,相當(dāng)于總店招牌,比如寶潔公司,也可以指定一個域下的具體某臺機器比如www.google.com或者froogle.google.com,可以用飄柔來做比。
路徑就是跟在域名后面的URL路徑,比如/或者/foo等等,可以用某飄柔專柜做比。
路徑與域合在一起就構(gòu)成了cookie的作用范圍。
如果不設(shè)置過期時間,則表示這個cookie的生命期為瀏覽器會話期間,只要關(guān)閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽器會話期的 cookie被稱為會話cookie。會話cookie一般不存儲在硬盤上而是保存在內(nèi)存里,當(dāng)然這種行為并不是規(guī)范規(guī)定的。如果設(shè)置了過期時間,瀏覽器就會把cookie保存到硬盤上,關(guān)閉后再次打開瀏覽器,這些cookie仍然有效直到超過設(shè)定的過期時間。
存儲在硬盤上的cookie可以在不同的瀏覽器進程間共享,比如兩個IE窗口。而對于保存在內(nèi)存里的cookie,不同的瀏覽器有不同的處理方式。對于 IE,在一個打開的窗口上按Ctrl-N(或者從文件菜單)打開的窗口可以與原窗口共享,而使用其他方式新開的IE進程則不能共享已經(jīng)打開的窗口的內(nèi)存 cookie;對于Mozilla Firefox0.8,所有的進程和標(biāo)簽頁都可以共享同樣的cookie。一般來說是用javascript的window.open打開的窗口會與原窗口共享內(nèi)存cookie。瀏覽器對于會話cookie的這種只認cookie不認人的處理方式經(jīng)常給采用session機制的web應(yīng)用程序開發(fā)者造成很大的困擾。
下面就是一個goolge設(shè)置cookie的響應(yīng)頭的例子
HTTP/1.1 302 Found
Location: http://www.google.com/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html
這是使用HTTPLook這個HTTP Sniffer軟件來俘獲的HTTP通訊紀錄的一部分
瀏覽器在再次訪問goolge的資源時自動向外發(fā)送cookie
使用Firefox可以很容易的觀察現(xiàn)有的cookie的值
使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。
IE也可以設(shè)置在接受cookie前詢問
這是一個詢問接受cookie的對話框。
四、理解session機制
session機制是一種服務(wù)器端的機制,服務(wù)器使用一種類似于散列表的結(jié)構(gòu)(也可能就是使用散列表)來保存信息。
當(dāng)程序需要為某個客戶端的請求創(chuàng)建一個session的時候,服務(wù)器首先檢查這個客戶端的請求里是否已包含了一個session標(biāo)識 - 稱為session id,如果已包含一個session id則說明以前已經(jīng)為此客戶端創(chuàng)建過session,服務(wù)器就按照session id把這個session檢索出來使用(如果檢索不到,可能會新建一個),如果客戶端請求不包含session id,則為此客戶端創(chuàng)建一個session并且生成一個與此session相關(guān)聯(lián)的session id,session id的值應(yīng)該是一個既不會重復(fù),又不容易被找到規(guī)律以仿造的字符串,這個session id將被在本次響應(yīng)中返回給客戶端保存。
保存這個session id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動的按照規(guī)則把這個標(biāo)識發(fā)揮給服務(wù)器。一般這個cookie的名字都是類似于 SEEESIONID,而。比如weblogic對于web應(yīng)用程序生成的cookie,JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是 JSESSIONID。
由于 cookie可以被人為的禁止,必須有其他機制以便在cookie被禁止時仍然能夠把session id傳遞回服務(wù)器。經(jīng)常被使用的一種技術(shù)叫做URL重寫,就是把session id直接附加在URL路徑的后面,附加方式也有兩種,一種是作為URL路徑的附加信息,表現(xiàn)形式為http://...../xxx; jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
另一種是作為查詢字符串附加在URL后面,表現(xiàn)形式為http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
這兩種方式對于用戶來說是沒有區(qū)別的,只是服務(wù)器在解析的時候處理的方式不同,采用第一種方式也有利于把session id的信息和正常程序參數(shù)區(qū)分開來。
為了在整個交互過程中始終保持狀態(tài),就必須在每個客戶端可能請求的路徑后面都包含這個session id。
另一種技術(shù)叫做表單隱藏字段。就是服務(wù)器會自動修改表單,添加一個隱藏字段,以便在表單提交時能夠把session id傳遞回服務(wù)器。比如下面的表單
<form name="testform" action="/xxx">
<input type="text">
</form>
在被傳遞給客戶端之前將被改寫成
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
這種技術(shù)現(xiàn)在已較少應(yīng)用,筆者接觸過的很古老的iPlanet6(SunONE應(yīng)用服務(wù)器的前身)就使用了這種技術(shù)。
實際上這種技術(shù)可以簡單的用對action應(yīng)用URL重寫來代替。
在談?wù)搒ession機制的時候,常常聽到這樣一種誤解“只要關(guān)閉瀏覽器,session就消失了”。其實可以想象一下會員卡的例子,除非顧客主動對店家提出銷卡,否則店家絕對不會輕易刪除顧客的資料。對session來說也是一樣的,除非程序通知服務(wù)器刪除一個session,否則服務(wù)器會一直保留,程序一般都是在用戶做log off的時候發(fā)個指令去刪除session。然而瀏覽器從來不會主動在關(guān)閉之前通知服務(wù)器它將要關(guān)閉,因此服務(wù)器根本不會有機會知道瀏覽器已經(jīng)關(guān)閉,之所以會有這種錯覺,是大部分session機制都使用會話cookie來保存session id,而關(guān)閉瀏覽器后這個session id就消失了,再次連接服務(wù)器時也就無法找到原來的session。如果服務(wù)器設(shè)置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發(fā)出的 HTTP請求頭,把原來的session id發(fā)送給服務(wù)器,則再次打開瀏覽器仍然能夠找到原來的session。
恰恰是由于關(guān)閉瀏覽器不會導(dǎo)致session被刪除,迫使服務(wù)器為seesion設(shè)置了一個失效時間,當(dāng)距離客戶端上一次使用session的時間超過這個失效時間時,服務(wù)器就可以認為客戶端已經(jīng)停止了活動,才會把session刪除以節(jié)省存儲空間。
五、理解javax.servlet.http.HttpSession
HttpSession是Java平臺對session機制的實現(xiàn)規(guī)范,因為它僅僅是個接口,具體到每個web應(yīng)用服務(wù)器的提供商,除了對規(guī)范支持之外,仍然會有一些規(guī)范里沒有規(guī)定的細微差異。這里我們以BEA的Weblogic Server8.1作為例子來演示。
首先,Weblogic Server提供了一系列的參數(shù)來控制它的HttpSession的實現(xiàn),包括使用cookie的開關(guān)選項,使用URL重寫的開關(guān)選項,session持久化的設(shè)置,session失效時間的設(shè)置,以及針對cookie的各種設(shè)置,比如設(shè)置cookie的名字、路徑、域,cookie的生存時間等。
一般情況下,session都是存儲在內(nèi)存里,當(dāng)服務(wù)器進程被停止或者重啟的時候,內(nèi)存里的session也會被清空,如果設(shè)置了session的持久化特性,服務(wù)器就會把session保存到硬盤上,當(dāng)服務(wù)器進程重新啟動或這些信息將能夠被再次使用,Weblogic Server支持的持久性方式包括文件、數(shù)據(jù)庫、客戶端cookie保存和復(fù)制。
復(fù)制嚴格說來不算持久化保存,因為session實際上還是保存在內(nèi)存里,不過同樣的信息被復(fù)制到各個cluster內(nèi)的服務(wù)器進程中,這樣即使某個服務(wù)器進程停止工作也仍然可以從其他進程中取得session。
cookie生存時間的設(shè)置則會影響瀏覽器生成的cookie是否是一個會話cookie。默認是使用會話cookie。有興趣的可以用它來試驗我們在第四節(jié)里提到的那個誤解。
cookie的路徑對于web應(yīng)用程序來說是一個非常重要的選項,Weblogic Server對這個選項的默認處理方式使得它與其他服務(wù)器有明顯的區(qū)別。后面我們會專題討論。
關(guān)于session的設(shè)置參考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869
六、HttpSession常見問題
(在本小節(jié)中session的含義為⑤和⑥的混合)
1、session在何時被創(chuàng)建
一個常見的誤解是以為session在有客戶端訪問時就被創(chuàng)建,然而事實是直到某server端程序調(diào)用 HttpServletRequest.getSession(true)這樣的語句時才被創(chuàng)建,注意如果JSP沒有顯示的使用 <%@page session="false"%> 關(guān)閉session,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。
由于session會消耗內(nèi)存資源,因此,如果不打算使用session,應(yīng)該在所有的JSP中關(guān)閉它。
2、session何時被刪除
綜合前面的討論,session在下列情況下被刪除a.程序調(diào)用HttpSession.invalidate();或b.距離上一次收到客戶端發(fā)送的session id時間間隔超過了session的超時設(shè)置;或c.服務(wù)器進程被停止(非持久session)
3、如何做到在瀏覽器關(guān)閉時刪除session
嚴格的講,做不到這一點。可以做一點努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監(jiān)視瀏覽器的關(guān)閉動作,然后向服務(wù)器發(fā)送一個請求來刪除session。但是對于瀏覽器崩潰或者強行殺死進程這些非常規(guī)手段仍然無能為力。
4、有個HttpSessionListener是怎么回事
你可以創(chuàng)建這樣的listener去監(jiān)控session的創(chuàng)建和銷毀事件,使得在發(fā)生這樣的事件時你可以做一些相應(yīng)的工作。注意是session的創(chuàng)建和銷毀動作觸發(fā)listener,而不是相反。類似的與HttpSession有關(guān)的listener還有 HttpSessionBindingListener,HttpSessionActivationListener和 HttpSessionAttributeListener。
5、存放在session中的對象必須是可序列化的嗎
不是必需的。要求對象可序列化只是為了session能夠在集群中被復(fù)制或者能夠持久保存或者在必要時server能夠暫時把session交換出內(nèi)存。在 Weblogic Server的session中放置一個不可序列化的對象在控制臺上會收到一個警告。我所用過的某個iPlanet版本如果session中有不可序列化的對象,在session銷毀時會有一個Exception,很奇怪。
6、如何才能正確的應(yīng)付客戶端禁止cookie的可能性
對所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770
7、開兩個瀏覽器窗口訪問應(yīng)用程序會使用同一個session還是不同的session
參見第三小節(jié)對cookie的討論,對session來說是只認id不認人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲方式都會對這個問題的答案有影響。
8、如何防止用戶打開兩個瀏覽器窗口操作導(dǎo)致的session混亂
這個問題與防止表單多次提交是類似的,可以通過設(shè)置客戶端的令牌來解決。就是在服務(wù)器每次生成一個不同的id返回給客戶端,同時保存在session里,客戶端提交表單時必須把這個id也返回服務(wù)器,程序首先比較返回的id與保存在session里的值是否一致,如果不一致則說明本次操作已經(jīng)被提交過了。可以參看《J2EE核心模式》關(guān)于表示層模式的部分。需要注意的是對于使用javascript window.open打開的窗口,一般不設(shè)置這個id,或者使用單獨的id,以防主窗口無法操作,建議不要再window.open打開的窗口里做修改操作,這樣就可以不用設(shè)置。
9、為什么在Weblogic Server中改變session的值后要重新調(diào)用一次session.setValue
做這個動作主要是為了在集群環(huán)境中提示W(wǎng)eblogic Server session中的值發(fā)生了改變,需要向其他服務(wù)器進程復(fù)制新的session值。
10、為什么session不見了
排除session正常失效的因素之外,服務(wù)器本身的可能性應(yīng)該是微乎其微的,雖然筆者在iPlanet6SP1加若干補丁的Solaris版本上倒也遇到過;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題;理論上防火墻或者代理服務(wù)器在cookie處理上也有可能會出現(xiàn)問題。
出現(xiàn)這一問題的大部分原因都是程序的錯誤,最常見的就是在一個應(yīng)用程序中去訪問另外一個應(yīng)用程序。我們在下一節(jié)討論這個問題。
七、跨應(yīng)用程序的session共享
常常有這樣的情況,一個大項目被分割成若干小項目開發(fā),為了能夠互不干擾,要求每個小項目作為一個單獨的web應(yīng)用程序開發(fā),可是到了最后突然發(fā)現(xiàn)某幾個小項目之間需要共享一些信息,或者想使用session來實現(xiàn)SSO(single sign on),在session中保存login的用戶信息,最自然的要求是應(yīng)用程序間能夠訪問彼此的session。
然而按照Servlet規(guī)范,session的作用范圍應(yīng)該僅僅限于當(dāng)前應(yīng)用程序下,不同的應(yīng)用程序之間是不能夠互相訪問對方的session的。各個應(yīng)用服務(wù)器從實際效果上都遵守了這一規(guī)范,但是實現(xiàn)的細節(jié)卻可能各有不同,因此解決跨應(yīng)用程序session共享的方法也各不相同。
首先來看一下Tomcat是如何實現(xiàn)web應(yīng)用程序之間session的隔離的,從Tomcat設(shè)置的cookie路徑來看,它對不同的應(yīng)用程序設(shè)置的 cookie路徑是不同的,這樣不同的應(yīng)用程序所用的session id是不同的,因此即使在同一個瀏覽器窗口里訪問不同的應(yīng)用程序,發(fā)送給服務(wù)器的session id也可以是不同的。
根據(jù)這個特性,我們可以推測Tomcat中session的內(nèi)存結(jié)構(gòu)大致如下。
筆者以前用過的iPlanet也采用的是同樣的方式,估計SunONE與iPlanet之間不會有太大的差別。對于這種方式的服務(wù)器,解決的思路很簡單,實際實行起來也不難。要么讓所有的應(yīng)用程序共享一個session id,要么讓應(yīng)用程序能夠獲得其他應(yīng)用程序的session id。
iPlanet中有一種很簡單的方法來實現(xiàn)共享一個session id,那就是把各個應(yīng)用程序的cookie路徑都設(shè)為/(實際上應(yīng)該是/NASApp,對于應(yīng)用程序來講它的作用相當(dāng)于根)。
<session-info>
<path>/NASApp</path>
</session-info>
需要注意的是,操作共享的session應(yīng)該遵循一些編程約定,比如在session attribute名字的前面加上應(yīng)用程序的前綴,使得setAttribute("name", "neo")變成setAttribute("app1.name", "neo"),以防止命名空間沖突,導(dǎo)致互相覆蓋。
在Tomcat 中則沒有這么方便的選擇。在Tomcat版本3上,我們還可以有一些手段來共享session。對于版本4以上的Tomcat,目前筆者尚未發(fā)現(xiàn)簡單的辦法。只能借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端cookie,URL參數(shù)或者隱藏字段等手段。
我們再看一下Weblogic Server是如何處理session的。
從截屏畫面上可以看到Weblogic Server對所有的應(yīng)用程序設(shè)置的cookie的路徑都是/,這是不是意味著在Weblogic Server中默認的就可以共享session了呢?然而一個小實驗即可證明即使不同的應(yīng)用程序使用的是同一個session,各個應(yīng)用程序仍然只能訪問自己所設(shè)置的那些屬性。這說明Weblogic Server中的session的內(nèi)存結(jié)構(gòu)可能如下
對于這樣一種結(jié)構(gòu),在session機制本身上來解決session共享的問題應(yīng)該是不可能的了。除了借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端cookie,URL參數(shù)或者隱藏字段等手段,還有一種較為方便的做法,就是把一個應(yīng)用程序的session放到ServletContext 中,這樣另外一個應(yīng)用程序就可以從ServletContext中取得前一個應(yīng)用程序的引用。示例代碼如下,
應(yīng)用程序A
context.setAttribute("appA", session);
應(yīng)用程序B
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");
值得注意的是這種用法不可移植,因為根據(jù)ServletContext的JavaDoc,應(yīng)用服務(wù)器可以處于安全的原因?qū)τ赾ontext.getContext("/appA");返回空值,以上做法在Weblogic Server 8.1中通過。
那么Weblogic Server為什么要把所有的應(yīng)用程序的cookie路徑都設(shè)為/呢?原來是為了SSO,凡是共享這個session的應(yīng)用程序都可以共享認證的信息。一個簡單的實驗就可以證明這一點,修改首先登錄的那個應(yīng)用程序的描述符weblogic.xml,把cookie路徑修改為/appA訪問另外一個應(yīng)用程序會重新要求登錄,即使是反過來,先訪問cookie路徑為/的應(yīng)用程序,再訪問修改過路徑的這個,雖然不再提示登錄,但是登錄的用戶信息也會丟失。注意做這個實驗時認證方式應(yīng)該使用FORM,因為瀏覽器和web服務(wù)器對basic認證方式有其他的處理方式,第二次請求的認證不是通過session來實現(xiàn)的。具體請參看[7] secion 14.8 Authorization,你可以修改所附的示例程序來做這些試驗。
八、總結(jié)
session機制本身并不復(fù)雜,然而其實現(xiàn)和配置上的靈活性卻使得具體情況復(fù)雜多變。這也要求我們不能把僅僅某一次的經(jīng)驗或者某一個瀏覽器,服務(wù)器的經(jīng)驗當(dāng)作普遍適用的經(jīng)驗,而是始終需要具體情況具體分析。
關(guān)于作者:
郎云鵬(dev2dev ID: hippiewolf),軟件工程師,從事J2EE開發(fā)
電子郵件:langyunpeng@yahoo.com.cn
地址:大連軟件園路31號科技大廈A座大連博涵咨詢服務(wù)有限公司
參考文檔:
[1] Preliminary Specification http://wp.netscape.com/newsref/std/cookie_spec.html
[2] RFC2109 http://www.rfc-editor.org/rfc/rfc2109.txt
[3] RFC2965 http://www.rfc-editor.org/rfc/rfc2965.txt
[4] The Unofficial Cookie FAQ http://www.cookiecentral.com/faq/
[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869
[6] http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770
[7] RFC2616 http://www.rfc-editor.org/rfc/rfc2616.txt
早在Java 1.2推出之時,Java平臺中就引入了一個新的支持:java.lang.ThreadLocal,給我們在編寫多線程程序時提供了一種新的選擇。使用這個工具類可以很簡潔地編寫出優(yōu)美的多線程程序,雖然ThreadLocal非常有用,但是似乎現(xiàn)在了解它、使用它的朋友還不多。
ThreadLocal是什么
ThreadLocal并非是一個線程的本地實現(xiàn)版本,它并不是一個Thread,而是thread local variable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)其實的功用非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本沖突。從線程的角度看,就好像每一個線程都完全擁有該變量。線程局部變量并不是Java的新發(fā)明,在其它的一些語言編譯器實現(xiàn)(如IBM XL FORTRAN)中,它在語言的層次提供了直接的支持。因為Java中沒有提供在語言層次的直接支持,而是提供了一個ThreadLocal的類來提供支持,所以,在Java中編寫線程局部變量的代碼相對比較笨拙,這也許是線程局部變量沒有在Java中得到很好的普及的一個原因吧。
ThreadLocal的設(shè)計
首先看看ThreadLocal的接口:
Object get() ;
// 返回當(dāng)前線程的線程局部變量副本 protected Object initialValue(); // 返回該線程局部變量的當(dāng)前線程的初始值
void set(Object value);
// 設(shè)置當(dāng)前線程的線程局部變量副本的值
ThreadLocal有3個方法,其中值得注意的是initialValue(),該方法是一個protected的方法,顯然是為了子類重寫而特意實現(xiàn)的。該方法返回當(dāng)前線程在該線程局部變量的初始值,這個方法是一個延遲調(diào)用方法,在一個線程第1次調(diào)用get()或者set(Object)時才執(zhí)行,并且僅執(zhí)行1次。ThreadLocal中的確實實現(xiàn)直接返回一個null:
protected Object initialValue() { return null; }
ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現(xiàn)的思路很簡單,在ThreadLocal類中有一個Map,用于存儲每一個線程的變量的副本。比如下面的示例實現(xiàn):
public class ThreadLocal
{
private Map values = Collections.synchronizedMap(new HashMap());
public Object get()
{
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread))
{
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue)
{
values.put(Thread.currentThread(), newValue);
}
public Object initialValue()
{
return null;
}
}
?
當(dāng)然,這并不是一個工業(yè)強度的實現(xiàn),但JDK中的ThreadLocal的實現(xiàn)總體思路也類似于此。
ThreadLocal的使用
如果希望線程局部變量初始化其它值,那么需要自己實現(xiàn)ThreadLocal的子類并重寫該方法,通常使用一個內(nèi)部匿名類對ThreadLocal進行子類化,比如下面的例子,SerialNum類為每一個類分配一個序號
public class SerialNum
{
// The next serial number to be assigned
private static int nextSerialNum = 0;
private static ThreadLocal serialNum = new ThreadLocal()
{
protected synchronized Object initialValue()
{
return new Integer(nextSerialNum++);
}
};
public static int get()
{
return ((Integer) (serialNum.get())).intValue();
}
}
?
SerialNum類的使用將非常地簡單,因為get()方法是static的,所以在需要獲取當(dāng)前線程的序號時,簡單地調(diào)用:
int serial = SerialNum.get();
即可。
在線程是活動的并且ThreadLocal對象是可訪問的時,該線程就持有一個到該線程局部變量副本的隱含引用,當(dāng)該線程運行結(jié)束后,該線程擁有的所以線程局部變量的副本都將失效,并等待垃圾收集器收集。
ThreadLocal與其它同步機制的比較
ThreadLocal和其它同步機制相比有什么優(yōu)勢呢?ThreadLocal和其它所有的同步機制都是為了解決多線程中的對同一變量的訪問沖突,在普通的同步機制中,是通過對象加鎖來實現(xiàn)多個線程對同一變量的安全訪問的。這時該變量是多個線程共享的,使用這種同步機制需要很細致地分析在什么時候?qū)ψ兞窟M行讀寫,什么時候需要鎖定某個對象,什么時候釋放該對象的鎖等等很多。所有這些都是因為多個線程共享了資源造成的。ThreadLocal就從另一個角度來解決多線程的并發(fā)訪問,ThreadLocal會為每一個線程維護一個和該線程綁定的變量的副本,從而隔離了多個線程的數(shù)據(jù),每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量
?第一,文件的的編碼方式其實就包括兩方面:存和取,存文件必須以一種編碼存;讀文件也必須以一種編碼讀。如果存取按照相同的編碼方式,則不會有問題,關(guān)鍵就是很多時候存取的方式不一致,產(chǎn)生亂碼。,如不特別設(shè)置取系統(tǒng)默認的編碼,中文windows為GBK編碼。
從.java->.class過程是,先編寫.java文件并按莫種編碼方式保存,然后用javac方法編譯此文件,注意如.java沒按系統(tǒng)默認編碼保存則要帶encoding參數(shù)指明實際編碼,否則出錯,生成的.class文件存為系統(tǒng)默認編碼。
從.jsp->.java->.class,先存為某種編碼的.jsp文件,然后tomcat根據(jù)pageEncoding讀取并轉(zhuǎn)化為servlet存為系統(tǒng)默認編碼,然后同上面.java->.class過程。
第二,IDE的encoding為對系統(tǒng)下文件打開的解碼方式或保存的編碼方式。特例:如果.jsp文件有<%@ page language="java" pageEncoding="UTF-8"%>,則eclipse會自動存為UTF-8方式,不管eclipse的encoding是什么,這也是 eclipse的聰明之處。
第三,
pageEncoding="UTF-8"表示此文件的編碼方式,必須與此文件存儲方式一致(所以eclipse會首選根據(jù)它來存文件),tomcat根據(jù)這個來讀此.jsp文件并編譯為servlet(至于編譯成的.java和.class文件應(yīng)該為tomcat服務(wù)器默認編碼)。
contentType="text/html;charset=UTF-8"表示當(dāng)服務(wù)器給瀏覽器傳頁面文件時編碼方式為UTF-8,形式為HTML。例如:
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page contentType="text/html;charset=GBK"%>
<html>
?<head>
??<title>test</title>
?</head>
?<body>
??我是個好人
?</body>
</html>
表示本jsp文件存為UTF-8字符集,當(dāng)瀏覽器打開此頁面后,查看原碼就會發(fā)現(xiàn)源碼為GBK字符集。
第四,
request.setCharacterEncoding("UTF-8")是把提交內(nèi)容的字符集設(shè)為UTF-8
response.setCharacterEncoding("UTF-8")可以把頁面中的<%@ page contentType="text/html;charset=iso8859-1"%>換為charset=UTF-8,是給告訴瀏覽器我這個文件的編碼方式。
第五,表單提交:無論何種表單提交都可以在后臺的java文件中通過String des = new String(s.getBytes("iso8859-1"),"UTF-8");來轉(zhuǎn)換成你想要的UTF-8編碼方式。但如果每處都加詞句太麻煩,故分post和get兩種方式區(qū)分提交(tomcat5以后分開處理,之前處理方式一樣,即都可以用 request.setCharacterEncoding("UTF-8")方法處理,不過tomcat5以后get提交方法用此語句無效)。
1,post提交的數(shù)據(jù):
程序加上org.springframework.web.filter.CharacterEncodingFilter過濾器.
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
因為規(guī)范要求瀏覽器提交數(shù)據(jù)都要用utf8編碼,所以這里設(shè)置編碼方式為UTF8.
特別注意:
a,這個過濾器只是簡單的調(diào)用:request.setCharacterEncoding(this.encoding);
在這個語句之前不能調(diào)用任何的request.getParameter()方法,否則會設(shè)置tomcat的缺省字符集為"ISO-8859-1",并且使 setCharacterEncoding的調(diào)用失效.所以在這個過濾器之前的過濾器中不能有對getParameter這類方法的調(diào)用,比較安全的做法就是把這個過濾器盡量靠前放.
b,在server.xml中不能加上<Valve className="org.apache.catalina.valves.RequestDumperValve"/>
這個value也設(shè)置tomcat的缺省字符集為"ISO-8859-1",使setCharacterEncoding的調(diào)用失效.可能其他的value也有這個問題,我沒有測試過.
如果要觀察http請求參數(shù),可以考慮用過濾器或者其他工具,例如ethereal(http://www.ethereal.com/)
2,get提交的數(shù)據(jù):
兩種情況:
a,如果從地址欄直接輸入漢字,則一般編碼為"GBK",需要用
new String(request.getParameter("something").getBytes("ISO-8859-1"),"GBK")
取出
b,如果是頁面超連接連接中帶的漢字,則編碼根據(jù)頁面編碼的不同而不同,如果頁面的
content="text/html; charset=utf-8",則在tomcat/conf/server.xml中的配置文件中:
<!-- Define a non-SSL Coyote HTTP/1.1 Connector on port 8080 -->
<Connector port="8080"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000" useBodyEncodingForURI="true"
disableUploadTimeout="true" />
加上:useBodyEncodingForURI="true"即可正常使用getParameter取出正確內(nèi)容.
如果content="text/html; charset=GBK",需用
new String(request.getParameter("something").getBytes("ISO-8859-1"),"GBK")
取出,其他情況類似.
總結(jié):
1,所有頁面使用utf8編碼,
2,服務(wù)器加上過濾器,
3,server.xml中不要使用
<Valve className="org.apache.catalina.valves.RequestDumperValve"/>
4,server.xml文件加上useBodyEncodingForURI="true"
這樣應(yīng)該可以搞定大多數(shù)前臺的中文問題.至于地址欄輸入中文,不支持也罷,一般的程序很少要求
從這里輸入.
第六,連接數(shù)據(jù)庫?
1、mysql配置文件:
修改mysql在windows\my.ini里default-character-set=utf-8
2、mysql里數(shù)據(jù)庫和表也都設(shè)為utf8_unicode_ci
3、數(shù)據(jù)庫連結(jié):jdbc:mysql://localhost/mydb?useUnicode=true&characterEncoding=utf-8
注意,關(guān)鍵就在于此:此句中間是'&'不是'&'這是因為數(shù)據(jù)庫連結(jié)時,在.jsp和.java文件中應(yīng)該用&號,而XML文件中需要用&
Java基礎(chǔ)方面:
1、作用域public,private,protected,以及不寫時的區(qū)別
答:區(qū)別如下:
作用域?????????? 當(dāng)前類?????? 同一package? 子孫類?????? 其他package
public??????????? √????????????? √????????????????? √???????????? √
protected??????? √????????????? √????????????????? √???????????? ×
friendly????????? √????????????? √?????????????????? ×??????????? ×
private?????????? √????????????? ×?????????????????? ×??????????? ×
不寫時默認為friendly
2、ArrayList和Vector的區(qū)別,HashMap和Hashtable的區(qū)別
答:就ArrayList與Vector主要從二方面來說.
一.同步性:Vector是線程安全的,也就是說是同步的,而ArrayList是線程序不安全的,不是同步的
二.數(shù)據(jù)增長:當(dāng)需要增長時,Vector默認增長為原來一培,而ArrayList卻是原來的一半
就HashMap與HashTable主要從三方面來說。
一.歷史原因:Hashtable是基于陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現(xiàn)
二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的
三.值:只有HashMap可以讓你將空值作為一個表的條目的key或value
3、char型變量中能不能存貯一個中文漢字?為什么?
答:是能夠定義成為一個中文的,因為java中以unicode編碼,一個char占16個字節(jié),所以放一個中文是沒問題的
4、多線程有幾種實現(xiàn)方法,都是什么?同步有幾種實現(xiàn)方法,都是什么?
答:多線程有兩種實現(xiàn)方法,分別是繼承Thread類與實現(xiàn)Runnable接口
同步的實現(xiàn)方面有兩種,分別是synchronized,wait與notify
5、繼承時候類的執(zhí)行順序問題,一般都是選擇題,問你將會打印出什么?
答:父類:
package test;
public class? FatherClass
{
??? public FatherClass()
?{
??System.out.println("FatherClass Create");
?}
}
子類:
package test;
import test.FatherClass;
public class? ChildClass extends FatherClass
{
?public ChildClass()
?{
??System.out.println("ChildClass Create");
?}
?public static void main(String[] args)
?{
??FatherClass fc = new FatherClass();
??ChildClass cc = new ChildClass();
?}
}
輸出結(jié)果:
C:\>java test.ChildClass
FatherClass Create
FatherClass Create
ChildClass Create
6、內(nèi)部類的實現(xiàn)方式?
答:示例代碼如下:
package test;
public class? OuterClass
{
?private class InterClass
?{
??public InterClass()
??{
???System.out.println("InterClass Create");
??}
?}
?public OuterClass()
?{
??InterClass ic = new InterClass();
??System.out.println("OuterClass Create");
?}
?public static void main(String[] args)
?{
??OuterClass oc = new OuterClass();
?}
}
輸出結(jié)果:
C:\>java test/OuterClass
InterClass Create
OuterClass Create
再一個例題:
public class OuterClass {
? private double d1 = 1.0;
??? //insert code here
}
You need to insert an inner class declaration at line 3. Which two inner class declarations are
valid?(Choose two.)
A. class InnerOne{
???? public static double methoda() {return d1;}
?? }
B. public class InnerOne{
???? static double methoda() {return d1;}
?? }
C. private class InnerOne{
???? double methoda() {return d1;}
?? }
D. static class InnerOne{
???? protected double methoda() {return d1;}
?? }
E. abstract class InnerOne{
???? public abstract double methoda();
?? }
說明如下:
一.靜態(tài)內(nèi)部類可以有靜態(tài)成員,而非靜態(tài)內(nèi)部類則不能有靜態(tài)成員。 故 A、B 錯
二.靜態(tài)內(nèi)部類的非靜態(tài)成員可以訪問外部類的靜態(tài)變量,而不可訪問外部類的非靜態(tài)變量;return d1 出錯。
故 D 錯
三.非靜態(tài)內(nèi)部類的非靜態(tài)成員可以訪問外部類的非靜態(tài)變量。 故 C 正確
四.答案為C、E
7、垃圾回收機制,如何優(yōu)化程序?
希望大家補上,謝謝
8、float型float f=3.4是否正確?
答:不正確。精度不準(zhǔn)確,應(yīng)該用強制類型轉(zhuǎn)換,如下所示:float f=(float)3.4
9、介紹JAVA中的Collection FrameWork(包括如何寫自己的數(shù)據(jù)結(jié)構(gòu))?
答:Collection FrameWork如下:
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)
Map提供key到value的映射
10、Java中異常處理機制,事件機制?
11、JAVA中的多形與繼承?
希望大家補上,謝謝
12、抽象類與接口?
答:抽象類與接口都用于抽象,但是抽象類(JAVA中)可以有自己的部分實現(xiàn),而接口則完全是一個標(biāo)識(同時有多重繼承的功能)。
13、Java 的通信編程,編程題(或問答),用JAVA SOCKET編程,讀服務(wù)器幾個字符,再寫入本地顯示?
答:Server端程序:
package test;
import java.net.*;
import java.io.*;
public class Server
{
?private ServerSocket ss;
?private Socket socket;
?private BufferedReader in;
?private PrintWriter out;
?public Server()
?{
??try
??{
???ss=new ServerSocket(10000);
???while(true)
???{
????socket = ss.accept();
????String RemoteIP = socket.getInetAddress().getHostAddress();
????String RemotePort = ":"+socket.getLocalPort();
????System.out.println("A client come in!IP:"+RemoteIP+RemotePort);
????in = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
????String line = in.readLine();
????System.out.println("Cleint send is :" + line);
????out = new PrintWriter(socket.getOutputStream(),true);
????out.println("Your Message Received!");
????out.close();
????in.close();
????socket.close();
???}
??}catch (IOException e)
??{
???out.println("wrong");
??}
?}
?public static void main(String[] args)
?{
??new Server();
?}
};
Client端程序:
package test;
import java.io.*;
import java.net.*;
public class Client
{
?Socket socket;
?BufferedReader in;
?PrintWriter out;
?public Client()
?{
??try
??{
???System.out.println("Try to Connect to 127.0.0.1:10000");
???socket = new Socket("127.0.0.1",10000);
???System.out.println("The Server Connected!");
???System.out.println("Please enter some Character:");
???BufferedReader line = new BufferedReader(new
InputStreamReader(System.in));
???out = new PrintWriter(socket.getOutputStream(),true);
???out.println(line.readLine());
???in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
???System.out.println(in.readLine());
???out.close();
???in.close();
???socket.close();
??}catch(IOException e)
??{
???out.println("Wrong");
??}
?}
?public static void main(String[] args)
?{
??new Client();
?}
};
14、用JAVA實現(xiàn)一種排序,JAVA類實現(xiàn)序列化的方法(二種)? 如在COLLECTION框架中,實現(xiàn)比較要實現(xiàn)什么樣的接口?
答:用插入法進行排序代碼如下
package test;
import java.util.*;
class? InsertSort
{
?ArrayList al;
?public InsertSort(int num,int mod)
?{
??al = new ArrayList(num);
??Random rand = new Random();
??System.out.println("The ArrayList Sort Before:");
??for (int i=0;i<num ;i++ )
??{
???al.add(new Integer(Math.abs(rand.nextInt()) % mod + 1));
???System.out.println("al["+i+"]="+al.get(i));
??}
?}
?public void SortIt()
?{
??Integer tempInt;
??int MaxSize=1;
??for(int i=1;i<al.size();i++)
??{
?????? tempInt = (Integer)al.remove(i);
????if(tempInt.intValue()>=((Integer)al.get(MaxSize-1)).intValue())
????{
?????al.add(MaxSize,tempInt);
?????MaxSize++;
?????System.out.println(al.toString());
????} else {
?????for (int j=0;j<MaxSize ;j++ )
?????{
??????if
(((Integer)al.get(j)).intValue()>=tempInt.intValue())
??????{
???????al.add(j,tempInt);
???????MaxSize++;
???????System.out.println(al.toString());
???????break;
??????}
?????}
????}
??}
??System.out.println("The ArrayList Sort After:");
??for(int i=0;i<al.size();i++)
??{
???System.out.println("al["+i+"]="+al.get(i));
??}
?}
?public static void main(String[] args)
?{
??InsertSort is = new InsertSort(10,100);
??is.SortIt();
?}
}
JAVA類實現(xiàn)序例化的方法是實現(xiàn)java.io.Serializable接口
Collection框架中實現(xiàn)比較要實現(xiàn)Comparable 接口和 Comparator 接口
15、編程:編寫一個截取字符串的函數(shù),輸入為一個字符串和字節(jié)數(shù),輸出為按字節(jié)截取的字符串。 但是要保證漢字不被截半個,如“我ABC”4,應(yīng)該截為“我AB”,輸入“我ABC漢DEF”,6,應(yīng)該輸出為“我ABC”而不是“我ABC+漢的半個”。
答:代碼如下:
package test;
class? SplitString
{
?String SplitStr;
?int SplitByte;
?public SplitString(String str,int bytes)
?{
??SplitStr=str;
??SplitByte=bytes;
??System.out.println("The String is:'"+SplitStr+"';SplitBytes="+SplitByte);
?}
?public void SplitIt()
?{
??int loopCount;
??
loopCount=(SplitStr.length()%SplitByte==0)?(SplitStr.length()/SplitByte):(SplitStr.length()/Split
Byte+1);
??System.out.println("Will Split into "+loopCount);
??for (int i=1;i<=loopCount ;i++ )
??{
???if (i==loopCount){
????
System.out.println(SplitStr.substring((i-1)*SplitByte,SplitStr.length()));
???} else {
????
System.out.println(SplitStr.substring((i-1)*SplitByte,(i*SplitByte)));
???}
??}
?}
?public static void main(String[] args)
?{
??SplitString ss = new SplitString("test中dd文dsaf中男大3443n中國43中國人
0ewldfls=103",4);
??ss.SplitIt();
?}
}
16、JAVA多線程編程。 用JAVA寫一個多線程程序,如寫四個線程,二個加1,二個對一個變量減一,輸出。
希望大家補上,謝謝
17、STRING與STRINGBUFFER的區(qū)別。
答:STRING的長度是不可變的,STRINGBUFFER的長度是可變的。如果你對字符串中的內(nèi)容經(jīng)常進行操作,特別是內(nèi)容要修改時,那么使用StringBuffer,如果最后需要String,那么使用StringBuffer的toString()方法
Jsp方面
1、jsp有哪些內(nèi)置對象?作用分別是什么?
答:JSP共有以下9種基本內(nèi)置組件(可與ASP的6種內(nèi)部組件相對應(yīng)):
request 用戶端請求,此請求會包含來自GET/POST請求的參數(shù)
?? response 網(wǎng)頁傳回用戶端的回應(yīng)
?? pageContext 網(wǎng)頁的屬性是在這里管理
?? session 與請求有關(guān)的會話期
?? application servlet 正在執(zhí)行的內(nèi)容
?? out 用來傳送回應(yīng)的輸出
?? config servlet的構(gòu)架部件
?? page JSP網(wǎng)頁本身
?? exception 針對錯誤網(wǎng)頁,未捕捉的例外
2、jsp有哪些動作?作用分別是什么?
答:JSP共有以下6種基本動作
?? jsp:include:在頁面被請求的時候引入一個文件。
?? jsp:useBean:尋找或者實例化一個JavaBean。
?? jsp:setProperty:設(shè)置JavaBean的屬性。
?? jsp:getProperty:輸出某個JavaBean的屬性。
?? jsp:forward:把請求轉(zhuǎn)到一個新的頁面。
?? jsp:plugin:根據(jù)瀏覽器類型為Java插件生成OBJECT或EMBED標(biāo)記
3、JSP中動態(tài)INCLUDE與靜態(tài)INCLUDE的區(qū)別?
答:動態(tài)INCLUDE用jsp:include動作實現(xiàn)
?? <jsp:include page="included.jsp" flush="true" />它總是會檢查所含文件中的變化,適合用于包含動態(tài)頁面,并且可以帶參數(shù)
?? 靜態(tài)INCLUDE用include偽碼實現(xiàn),定不會檢查所含文件的變化,適用于包含靜態(tài)頁面
?? <%@ include file="included.htm" %>
4、兩種跳轉(zhuǎn)方式分別是什么?有什么區(qū)別?
答:有兩種,分別為:
? <jsp:include page="included.jsp" flush="true">
? <jsp:forward page= "nextpage.jsp"/>
? 前者頁面不會轉(zhuǎn)向include所指的頁面,只是顯示該頁的結(jié)果,主頁面還是原來的頁面。執(zhí)行完后還會回來,相當(dāng)于函數(shù)調(diào)用。并且可以帶參數(shù).后者完全轉(zhuǎn)向新頁面,不會再回來。相當(dāng)于go to 語句。
Servlet方面
1、說一說Servlet的生命周期?
答:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務(wù)結(jié)束。這個生存期由javax.servlet.Servlet接口的init,service和destroy方法表達。
2、Servlet版本間(忘了問的是哪兩個版本了)的不同?
希望大家補上,謝謝
3、JAVA SERVLET API中forward() 與redirect()的區(qū)別?
答:前者僅是容器中控制權(quán)的轉(zhuǎn)向,在客戶端瀏覽器地址欄中不會顯示出轉(zhuǎn)向后的地址;后者則是完全的跳轉(zhuǎn),瀏覽器將會得到跳轉(zhuǎn)的地址,并重新發(fā)送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉(zhuǎn)后的鏈接地址。所以,前者更加高效,在前者可以滿足需要時,盡量使用forward()方法,并且,這樣也有助于隱藏實際的鏈接。在有些情況下,比如,需要跳轉(zhuǎn)到一個其它服務(wù)器上的資源,則必須使用sendRedirect()方法。
4、Servlet的基本架構(gòu)
public class ServletName extends HttpServlet {
? public void doPost(HttpServletRequest request, HttpServletResponse response) throws
????? ServletException, IOException? {
????? }
? public void doGet(HttpServletRequest request, HttpServletResponse response) throws
????? ServletException, IOException? {
????? }
}
Jdbc、Jdo方面
1、可能會讓你寫一段Jdbc連Oracle的程序,并實現(xiàn)數(shù)據(jù)查詢.
答:程序如下:
package hello.ant;
import java.sql.*;
public class? jdbc
{
?String dbUrl="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
?String theUser="admin";
?String thePw="manager";
?Connection c=null;
?Statement conn;
?ResultSet rs=null;
?public jdbc()
?{
??try{
??? Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
????????? c = DriverManager.getConnection(dbUrl,theUser,thePw);
??? conn=c.createStatement();
??}catch(Exception e){
???e.printStackTrace();
??}
?}
?public boolean executeUpdate(String sql)
?{
???try
???{
?????conn.executeUpdate(sql);
?????return true;
???}
???catch (SQLException e)
???{
?????e.printStackTrace();
?????return false;
???}
?}
?public ResultSet executeQuery(String sql)
?{
???rs=null;
???try
???{
?????rs=conn.executeQuery(sql);
???}
???catch (SQLException e)
???{
?????e.printStackTrace();
???}
???return rs;
?}
?public void close()
?{
???try
???{
?????conn.close();
?????c.close();
???}
???catch (Exception e)
???{
?????e.printStackTrace();
???}
?}
?public static void main(String[] args)
?{
??ResultSet rs;
??jdbc conn = new jdbc();
??rs=conn.executeQuery("select * from test");
??try{
??while (rs.next())
??{
???System.out.println(rs.getString("id"));
???System.out.println(rs.getString("name"));
??}
??}catch(Exception e)
??{
???e.printStackTrace();
??}
?}
}
2、Class.forName的作用?為什么要用?
答:調(diào)用該訪問返回一個以字符串指定類名的類的對象。
3、Jdo是什么?
答:JDO 是Java對象持久化的新的規(guī)范,為java data object的簡稱,也是一個用于存取某種數(shù)據(jù)倉庫中的對象的標(biāo)準(zhǔn)化API。JDO提供了透明的對象存儲,因此對開發(fā)人員來說,存儲數(shù)據(jù)對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經(jīng)轉(zhuǎn)移到JDO產(chǎn)品提供商身上,使開發(fā)人員解脫出來,從而集中時間和精力在業(yè)務(wù)邏輯上。另外,JDO很靈活,因為它可以在任何數(shù)據(jù)底層上運行。JDBC只是面向關(guān)系數(shù)據(jù)庫(RDBMS)JDO更通用,提供到任何數(shù)據(jù)底層的存儲功能,比如關(guān)系數(shù)據(jù)庫、文件、XML以及對象數(shù)據(jù)庫(ODBMS)等等,使得應(yīng)用可移植性更強。
4、在ORACLE大數(shù)據(jù)量下的分頁解決方法。一般用截取ID方法,還有是三層嵌套方法。
答:一種分頁方法
<%
? int i=1;
? int numPages=14;
? String pages = request.getParameter("page") ;
? int currentPage = 1;
? currentPage=(pages==null)?(1):{Integer.parseInt(pages)}
? sql = "select count(*) from tables";
? ResultSet rs = DBLink.executeQuery(sql) ;
? while(rs.next()) i = rs.getInt(1) ;
? int intPageCount=1;
? intPageCount=(i%numPages==0)?(i/numPages):(i/numPages+1);
? int nextPage ;
? int upPage;
? nextPage = currentPage+1;
? if (nextPage>=intPageCount) nextPage=intPageCount;
? upPage = currentPage-1;
? if (upPage<=1) upPage=1;
? rs.close();
? sql="select * from tables";
? rs=DBLink.executeQuery(sql);
? i=0;
? while((i<numPages*(currentPage-1))&&rs.next()){i++;}
%>
//輸出內(nèi)容
//輸出翻頁連接
合計:<%=currentPage%>/<%=intPageCount%><a href="List.jsp?page=1">第一頁</a><a
href="List.jsp?page=<%=upPage%>">上一頁</a>
<%
? for(int j=1;j<=intPageCount;j++){
? if(currentPage!=j){
%>
? <a href="list.jsp?page=<%=j%>">[<%=j%>]</a>
<%
? }else{
? out.println(j);
? }
? }
%>
<a href="List.jsp?page=<%=nextPage%>">下一頁</a><a href="List.jsp?page=<%=intPageCount%>">最后頁
</a>
Xml方面
1、xml有哪些解析技術(shù)?區(qū)別是什么?
答:有DOM,SAX,STAX等
DOM: 處理大型文件時其性能下降的非常厲害。這個問題是由DOM的樹結(jié)構(gòu)所造成的,這種結(jié)構(gòu)占用的內(nèi)存較多,而且DOM必須在解析文件之前把整個文檔裝入內(nèi)存, 適合對 XML的隨機訪問SAX:不現(xiàn)于DOM,SAX是事件驅(qū)動型的XML解析方式。它順序讀取XML文件,不需要一次全部裝載整個文件。當(dāng)遇到像文件開頭,文檔結(jié)束,或者標(biāo)簽開頭與標(biāo)簽結(jié)束時,它會觸發(fā)一個事件,用戶通過在其回調(diào)事件中寫入處理代碼來處理XML文件,適合對XML的順序訪問
STAX:Streaming API for XML (StAX)
2、你在項目中用到了xml技術(shù)的哪些方面?如何實現(xiàn)的?
答:用到了數(shù)據(jù)存貯,信息配置兩方面。在做數(shù)據(jù)交換平臺時,將不能數(shù)據(jù)源的數(shù)據(jù)組裝成XML文件,然后將XML文件壓縮打包加密后通過網(wǎng)絡(luò)傳送給接收者,接收解密與解壓縮后再同XML文件中還原相關(guān)信息進行處理。在做軟件配置時,利用XML可以很方便的進行,軟件的各種配置參數(shù)都存貯在XML文件中。
3、用jdom解析xml文件時如何解決中文問題?如何解析?
答:看如下代碼,用編碼方式加以解決
package test;
import java.io.*;
public class DOMTest
{
?private String inFile = "c:\\people.xml";
?private String outFile = "c:\\people.xml";?
?public static void main(String args[])
?{
??? ?new DOMTest();
??? }
?public DOMTest()
?{
??try
???? {?
???? ?javax.xml.parsers.DocumentBuilder builder =
???? ??
javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();
???? ?org.w3c.dom.Document doc = builder.newDocument();
???? ?org.w3c.dom.Element root = doc.createElement("老師");
???? ?org.w3c.dom.Element wang = doc.createElement("王");
???org.w3c.dom.Element liu = doc.createElement("劉");
???? ?wang.appendChild(doc.createTextNode("我是王老師"));
???? ?root.appendChild(wang);
???? ?doc.appendChild(root);
???? ?javax.xml.transform.Transformer transformer =
???? ??javax.xml.transform.TransformerFactory.newInstance().newTransformer();
???? ?transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "gb2312");
???? ?transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");??
? ?
???? ?transformer.transform(new javax.xml.transform.dom.DOMSource(doc),
???? ???????new
javax.xml.transform.stream.StreamResult(outFile));
???? }
???? catch (Exception e)
???? {
???? ?System.out.println (e.getMessage());
???? }
??? }
}
4、編程用JAVA解析XML的方式.
答:用SAX方式解析XML,XML文件如下:
<?xml version="1.0" encoding="gb2312"?>
<person>
? <name>王小明</name>
? <college>信息學(xué)院</college>??
? <telephone>6258113</telephone>
? <notes>男,1955年生,博士,95年調(diào)入海南大學(xué)</notes>
?</person>
?事件回調(diào)類SAXHandler.java
?import java.io.*;
import java.util.Hashtable;
import org.xml.sax.*;
public class SAXHandler extends HandlerBase
? {
? private Hashtable table = new Hashtable();
? private String currentElement = null;
? private String currentValue = null;
? public void setTable(Hashtable table)
??? {
??? this.table = table;
??? }
? public Hashtable getTable()
??? {
??? return table;
??? }
? public void startElement(String tag, AttributeList attrs)
? throws SAXException
??? {
??? currentElement = tag;
??? }
? public void characters(char[] ch, int start, int length)
? throws SAXException
??? {
??? currentValue = new String(ch, start, length);
??? }
? public void endElement(String name) throws SAXException
??? {
??? if (currentElement.equals(name))
????? table.put(currentElement, currentValue);
??? }
? }
JSP內(nèi)容顯示源碼,SaxXml.jsp:
<HTML>
<HEAD>
<TITLE>剖析XML文件people.xml</TITLE>
</HEAD>
<BODY>
<%@ page errorPage="ErrPage.jsp"
contentType="text/html;charset=GB2312" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.Hashtable" %>
<%@ page import="org.w3c.dom.*" %>
<%@ page import="org.xml.sax.*" %>
<%@ page import="javax.xml.parsers.SAXParserFactory" %>
<%@ page import="javax.xml.parsers.SAXParser" %>
<%@ page import="SAXHandler" %>
<%
File file = new File("c:\\people.xml");
FileReader reader = new FileReader(file);
Parser parser;
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
SAXHandler handler = new SAXHandler();
sp.parse(new InputSource(reader), handler);
Hashtable hashTable = handler.getTable();
out.println("<TABLE BORDER=2><CAPTION>教師信息表</CAPTION>");
out.println("<TR><TD>姓名</TD>" + "<TD>" +
? (String)hashTable.get(new String("name")) + "</TD></TR>");
out.println("<TR><TD>學(xué)院</TD>" + "<TD>" +
? (String)hashTable.get(new String("college"))+"</TD></TR>");
out.println("<TR><TD>電話</TD>" + "<TD>" +
? (String)hashTable.get(new String("telephone")) + "</TD></TR>");
out.println("<TR><TD>備注</TD>" + "<TD>" +
? (String)hashTable.get(new String("notes")) + "</TD></TR>");
out.println("</TABLE>");
%>
</BODY>
</HTML>
EJB方面
1、EJB2.0有哪些內(nèi)容?分別用在什么場合? EJB2.0和EJB1.1的區(qū)別?
答:規(guī)范內(nèi)容包括Bean提供者,應(yīng)用程序裝配者,EJB容器,EJB配置工具,EJB服務(wù)提供者,系統(tǒng)管理員。這里面,EJB容器是EJB之所以能夠運行的核心。 EJB容器管理著EJB的創(chuàng)建,撤消,激活,去活,與數(shù)據(jù)庫的連接等等重要的核心工作。JSP,Servlet,EJB,JNDI,JDBC, JMS.....
2、EJB與JAVA BEAN的區(qū)別?
答:Java Bean 是可復(fù)用的組件,對Java Bean并沒有嚴格的規(guī)范,理論上講,任何一個Java類都可以是一個Bean。但通常情況下,由于Java Bean是被容器所創(chuàng)建(如Tomcat)的,所以Java Bean應(yīng)具有一個無參的構(gòu)造器,另外,通常Java Bean還要實現(xiàn)Serializable接口用于實現(xiàn)Bean的持久性。Java Bean實際上相當(dāng)于微軟COM模型中的本地進程內(nèi)COM組件,它是不能被跨進程訪問的。Enterprise Java Bean 相當(dāng)于DCOM,即分布式組件。它是基于Java的遠程方法調(diào)用(RMI)技術(shù)的,所以EJB可以被遠程訪問(跨進程、跨計算機)。但EJB必須被布署在諸如Webspere、WebLogic這樣的容器中,EJB客戶從不直接訪問真正的EJB組件,而是通過其容器訪問。EJB容器是EJB組件的代理, EJB組件由容器所創(chuàng)建和管理。客戶通過容器來訪問真正的EJB組件。
3、EJB的基本架構(gòu)
答:一個EJB包括三個部分:
? Remote Interface 接口的代碼
? package Beans;
? import javax.ejb.EJBObject;
? import java.rmi.RemoteException;
? public interface Add extends EJBObject
? {
?? //some method declare
? }
? Home Interface 接口的代碼
? package Beans;
? import java.rmi.RemoteException;
? import jaax.ejb.CreateException;
? import javax.ejb.EJBHome;
? public interface AddHome extends EJBHome
? {
??? //some method declare
? }
? EJB類的代碼
? package Beans;
? import java.rmi.RemoteException;
? import javax.ejb.SessionBean;
? import javx.ejb.SessionContext;
? public class AddBean Implements SessionBean
? {
??? //some method declare
? }?
J2EE,MVC方面
1、MVC的各個部分都有那些技術(shù)來實現(xiàn)?如何實現(xiàn)?
答:MVC 是Model-View- Controller的簡寫。"Model" 代表的是應(yīng)用的業(yè)務(wù)邏輯(通過JavaBean,EJB組件實現(xiàn)), "View" 是應(yīng)用的表示面(由JSP頁面產(chǎn)生),"Controller" 是提供應(yīng)用的處理過程控制(一般是一個Servlet),通過這種設(shè)計模型把應(yīng)用邏輯,處理過程和顯示邏輯分成不同的組件實現(xiàn)。這些組件可以進行交互和重用。
2、應(yīng)用服務(wù)器與WEB SERVER的區(qū)別?
希望大家補上,謝謝
3、J2EE是什么?
答:Je22 是Sun公司提出的多層(multi-diered),分布式(distributed),基于組件(component-base)的企業(yè)級應(yīng)用模型 (enterpriese application model).在這樣的一個應(yīng)用系統(tǒng)中,可按照功能劃分為不同的組件,這些組件又可在不同計算機上,并且處于相應(yīng)的層次(tier)中。所屬層次包括客戶層(clietn tier)組件,web層和組件,Business層和組件,企業(yè)信息系統(tǒng)(EIS)層。
4、WEB SERVICE名詞解釋。JSWDL開發(fā)包的介紹。JAXP、JAXM的解釋。SOAP、UDDI,WSDL解釋。
答:Web Service描述語言WSDL
SOAP即簡單對象訪問協(xié)議(Simple Object Access Protocol),它是用于交換XML編碼信息的輕量級協(xié)議。
UDDI 的目的是為電子商務(wù)建立標(biāo)準(zhǔn);UDDI是一套基于Web的、分布式的、為Web Service提供的、信息注冊中心的實現(xiàn)標(biāo)準(zhǔn)規(guī)范,同時也包含一組使企業(yè)能將自身提供的Web Service注冊,以使別的企業(yè)能夠發(fā)現(xiàn)的訪問協(xié)議的實現(xiàn)標(biāo)準(zhǔn)。
5、BS與CS的聯(lián)系與區(qū)別。
希望大家補上,謝謝
6、STRUTS的應(yīng)用(如STRUTS架構(gòu))
答:Struts 是采用Java Servlet/JavaServer Pages技術(shù),開發(fā)Web應(yīng)用程序的開放源碼的framework。采用Struts能開發(fā)出基于MVC(Model-View- Controller)設(shè)計模式的應(yīng)用構(gòu)架。 Struts有如下的主要功能:
一.包含一個controller servlet,能將用戶的請求發(fā)送到相應(yīng)的Action對象。
二.JSP自由tag庫,并且在controller servlet中提供關(guān)聯(lián)支持,幫助開發(fā)員創(chuàng)建交互式表單應(yīng)用。
三.提供了一系列實用對象:XML處理、通過Java reflection APIs自動處理JavaBeans屬性、國際化的提示和消息。
設(shè)計模式方面
1、開發(fā)中都用到了那些設(shè)計模式?用在什么場合?
答:每個模式都描述了一個在我們的環(huán)境中不斷出現(xiàn)的問題,然后描述了該問題的解決方案的核心。通過這種方式,你可以無數(shù)次地使用那些已有的解決方案,無需在重復(fù)相同的工作。主要用到了MVC的設(shè)計模式。用來開發(fā)JSP/Servlet或者J2EE的相關(guān)應(yīng)用。簡單工廠模式等。
2、UML方面
答:標(biāo)準(zhǔn)建模語言UML。用例圖,靜態(tài)圖(包括類圖、對象圖和包圖),行為圖,交互圖(順序圖,合作圖),實現(xiàn)圖,
JavaScript方面
1、如何校驗數(shù)字型?
var re=/^\d{1,8}$|\.\d{1,2}$/;
var str=document.form1.all(i).value;
var r=str.match(re);
if (r==null)
{
?? sign=-4;
?? break;
}
else{
?? document.form1.all(i).value=parseFloat(str);
}
CORBA方面
1、CORBA是什么?用途是什么?
答:CORBA 標(biāo)準(zhǔn)是公共對象請求代理結(jié)構(gòu)(Common Object Request Broker Architecture),由對象管理組織 (Object Management Group,縮寫為 OMG)標(biāo)準(zhǔn)化。它的組成是接口定義語言(IDL), 語言綁定(binding:也譯為聯(lián)編)和允許應(yīng)用程序間互操作的協(xié)議。其目的為:
用不同的程序設(shè)計語言書寫
在不同的進程中運行
為不同的操作系統(tǒng)開發(fā)
LINUX方面
1、LINUX下線程,GDI類的解釋。
答:LINUX實現(xiàn)的就是基于核心輕量級進程的"一對一"線程模型,一個線程實體對應(yīng)一個核心輕量級進程,而線程之間的管理在核外函數(shù)庫中實現(xiàn)。
GDI類為圖像設(shè)備編程接口類庫。
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 | |||
4 | 5 | 6 | 7 | 8 | 9 | 10 | |||
11 | 12 | 13 | 14 | 15 | 16 | 17 | |||
18 | 19 | 20 | 21 | 22 | 23 | 24 | |||
25 | 26 | 27 | 28 | 29 | 30 | 31 | |||
1 | 2 | 3 | 4 | 5 | 6 | 7 |