91福利视频久久久久,九色综合国产一区二区三区,欧美日韩一区二区三区http://www.aygfsteel.com/liaojiyong/category/11431.htmlzh-cnTue, 15 May 2007 09:10:59 GMTTue, 15 May 2007 09:10:59 GMT60JSTL 入門(轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2007/03/21/105235.htmlliaojiyongliaojiyongWed, 21 Mar 2007 04:15:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2007/03/21/105235.htmlhttp://www.aygfsteel.com/liaojiyong/comments/105235.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2007/03/21/105235.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/105235.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/105235.html

通過避免使用腳本編制元素來簡化對(duì) JSP 應(yīng)用程序的軟件維護(hù)

?

?


?


級(jí)別: 初級(jí)

Mark A. Kolb (mak@taglib.com), 軟件工程師

2003 年 5 月 27 日

JSP 標(biāo)準(zhǔn)標(biāo)記庫(JSP Standard Tag Library,JSTL)是一個(gè)實(shí)現(xiàn) Web 應(yīng)用程序中常見的通用功能的定制標(biāo)記庫集,這些功能包括迭代和條件判斷、數(shù)據(jù)管理格式化、XML 操作以及數(shù)據(jù)庫訪問。在 developerWorks 上其新系列的第一篇文章中,軟件工程師 Mark Kolb 向您展示了如何使用 JSTL 標(biāo)記來避免在 JSP 頁面中使用腳本編制元素。您還將了解如何通過從表示層刪除源代碼來簡化軟件維護(hù)。最后,您將了解 JSTL 經(jīng)過簡化的表達(dá)式語言,它允許在不必使用功能齊全的編程語言的情況下對(duì) JSTL 操作指定動(dòng)態(tài)屬性值。

JavaServer Pages(JSP)是用于 J2EE 平臺(tái)的標(biāo)準(zhǔn)表示層技術(shù)。JSP 技術(shù)提供了用于執(zhí)行計(jì)算(這些計(jì)算用來動(dòng)態(tài)地生成頁面內(nèi)容)的腳本編制元素和操作。腳本編制元素允許在 JSP 頁面中包括程序源代碼,在為響應(yīng)用戶請(qǐng)求而呈現(xiàn)頁面時(shí)可以執(zhí)行這些源代碼。操作將計(jì)算操作封裝到很象 HTML 或 XML 標(biāo)記的標(biāo)記中,JSP 頁面的模板文本通常包含這些標(biāo)記。JSP 規(guī)范只將幾種操作定義成了標(biāo)準(zhǔn),但從 JSP 1.1 開始,開發(fā)人員已經(jīng)能夠以定制標(biāo)記庫的方式創(chuàng)建其自己的操作了。

JSP 標(biāo)準(zhǔn)標(biāo)記庫(JSTL)是 JSP 1.2 定制標(biāo)記庫集,這些標(biāo)記庫實(shí)現(xiàn)大量服務(wù)器端 Java 應(yīng)用程序常用的基本功能。通過為典型表示層任務(wù)(如數(shù)據(jù)格式化和迭代或條件內(nèi)容)提供標(biāo)準(zhǔn)實(shí)現(xiàn),JSTL 使 JSP 作者可以專注于特定于應(yīng)用程序的開發(fā)需求,而不是為這些通用操作“另起爐灶”。

當(dāng)然,您可以使用 JSP 腳本編制元素(scriptlet、表達(dá)式和聲明)來實(shí)現(xiàn)此類任務(wù)。例如,可以使用三個(gè) scriptlet 實(shí)現(xiàn)條件內(nèi)容,清單 1 中著重顯示了這三個(gè) scriptlet。但是,因?yàn)槟_本編制元素依賴于在頁面中嵌入程序源代碼(通常是 Java 代碼),所以對(duì)于使用這些腳本編制元素的 JSP 頁面,其軟件維護(hù)任務(wù)的復(fù)雜度大大增加了。例如,清單 1 中的 scriptlet 示例嚴(yán)格地依賴于花括號(hào)的正確匹配。如果不經(jīng)意間引入了一個(gè)語法錯(cuò)誤,則條件內(nèi)容中的嵌套其它 scriptlet 可能會(huì)造成嚴(yán)重破壞,并且在 JSP 容器編譯該頁面時(shí),要使所產(chǎn)生的錯(cuò)誤信息有意義可能會(huì)很困難。



清單 1. 通過 scriptlet 實(shí)現(xiàn)條件內(nèi)容
<% if (user.getRole() == "member")) { %>
    <p>Welcome, member!</p>
<% } else { %>
    <p>Welcome, guest!</p>
<% } %>

修正此類問題通常需要相當(dāng)豐富的編程經(jīng)驗(yàn)。盡管通常會(huì)由十分精通頁面布局和圖形設(shè)計(jì)的設(shè)計(jì)人員來開發(fā)和維護(hù) JSP,但是同一頁面中的腳本編制元素出現(xiàn)問題時(shí),需要程序員的介入。這種狀況將單個(gè)文件中代碼的責(zé)任分擔(dān)給多人,因而使得開發(fā)、調(diào)試和增強(qiáng)此類 JSP 頁面成為很麻煩的任務(wù)。通過將常用功能包裝到定制標(biāo)記庫的標(biāo)準(zhǔn)集合中,JSTL 使 JSP 作者可以減少對(duì)編制腳本元素的需求,甚至可以不需要它們,并避免了相關(guān)的維護(hù)成本。





JSTL 1.0

JSTL 1.0 發(fā)布于 2002 年 6 月,由四個(gè)定制標(biāo)記庫( coreformatxmlsql )和一對(duì)通用標(biāo)記庫驗(yàn)證器( ScriptFreeTLVPermittedTaglibsTLV )組成。 core 標(biāo)記庫提供了定制操作,通過限制了作用域的變量管理數(shù)據(jù),以及執(zhí)行頁面內(nèi)容的迭代和條件操作。它還提供了用來生成和操作 URL 的標(biāo)記。顧名思義, format 標(biāo)記庫定義了用來格式化數(shù)據(jù)(尤其是數(shù)字和日期)的操作。它還支持使用本地化資源束進(jìn)行 JSP 頁面的國際化。 xml 庫包含一些標(biāo)記,這些標(biāo)記用來操作通過 XML 表示的數(shù)據(jù),而 sql 庫定義了用來查詢關(guān)系數(shù)據(jù)庫的操作。

兩個(gè) JSTL 標(biāo)記庫驗(yàn)證器允許開發(fā)人員在其 JSP 應(yīng)用程序中強(qiáng)制使用編碼標(biāo)準(zhǔn)。可以配置 ScriptFreeTLV 驗(yàn)證器以在 JSP 頁面中禁用各種類型的 JSP 腳本元素 ― scriptlet、表達(dá)式和聲明。類似地, PermittedTaglibsTLV 驗(yàn)證器可以用來限制可能由應(yīng)用程序的 JSP 頁面訪問的定制標(biāo)記庫集(包括 JSTL 標(biāo)記庫)。

盡管 JSTL 最終將會(huì)成為 J2EE 平臺(tái)的必需組件,但目前只有少數(shù)應(yīng)用程序服務(wù)器包括它。JSTL 1.0 的參考實(shí)現(xiàn)可作為 Apache 軟件基金會(huì)(Apache Software Foundation)的 Jakarta Taglibs 項(xiàng)目(請(qǐng)參閱 參考資料)的一部分而獲得。可以將該參考實(shí)現(xiàn)中的定制標(biāo)記庫合并到任何支持 JSP 1.2 和 Servlet 2.3 規(guī)范的服務(wù)器,以添加對(duì) JSTL 的支持。





表達(dá)式語言

在 JSP 1.2 中,可以使用靜態(tài)字符串或表達(dá)式(如果允許的話)指定 JSP 操作的屬性。例如,在清單 2 中,對(duì) <jsp:setProperty> 操作的 nameproperty 屬性指定了靜態(tài)值,而用表達(dá)式指定了其 value 屬性。這個(gè)操作的效果是將請(qǐng)求參數(shù)的當(dāng)前值賦予命名的 bean 特性。以這種形式使用的表達(dá)式被稱為 請(qǐng)求時(shí)屬性值(request-time attribute value),這是構(gòu)建到 JSP 規(guī)范中的用于動(dòng)態(tài)指定屬性值的唯一機(jī)制。



清單 2. 合并請(qǐng)求時(shí)屬性值的 JSP 操作
<jsp:setProperty name="user" property="timezonePref"
                 value='<%= request.getParameter("timezone") %>'/>

因?yàn)檎?qǐng)求時(shí)屬性值是用表達(dá)式指定的,所以它們往往有和其它腳本元素一樣的軟件維護(hù)問題。因此,JSTL 定制標(biāo)記支持另一種用于指定動(dòng)態(tài)屬性值的機(jī)制。可以用簡化的 表達(dá)式語言(EL)而不使用完整的 JSP 表達(dá)式來指定 JSTL 操作的屬性值。EL 提供了一些標(biāo)識(shí)符、存取器和運(yùn)算符,用來檢索和操作駐留在 JSP 容器中的數(shù)據(jù)。EL 在某種程度上以 EcmaScript(請(qǐng)參閱 參考資料)和 XML 路徑語言(XML Path Language,XPath)為基礎(chǔ),因此頁面設(shè)計(jì)人員和程序員都應(yīng)該熟悉它的語法。EL 擅長尋找對(duì)象及其特性,然后對(duì)它們執(zhí)行簡單操作;它不是編程語言,甚至不是腳本編制語言。但是,與 JSTL 標(biāo)記一起使用時(shí),它就能使用簡單而又方便的符號(hào)來表示復(fù)雜的行為。EL 表達(dá)式的格式是這樣的:用美元符號(hào)($)定界,內(nèi)容包括在花括號(hào)({})中,如清單 3 所示。



清單 3. 說明 EL 表達(dá)式定界符的 JSTL 操作
<c:out value="${user.firstName}"/>

此外,您可以將多個(gè)表達(dá)式與靜態(tài)文本組合在一起以通過字符串并置來構(gòu)造動(dòng)態(tài)屬性值,如清單 4 所示。單獨(dú)的表達(dá)式由標(biāo)識(shí)符、存取器、文字和運(yùn)算符組成。標(biāo)識(shí)符用來引用存儲(chǔ)在數(shù)據(jù)中心中的數(shù)據(jù)對(duì)象。EL 有 11 個(gè)保留標(biāo)識(shí)符,對(duì)應(yīng)于 11 個(gè) EL 隱式對(duì)象。假定所有其它標(biāo)識(shí)符都引用 限制了作用域的變量。存取器用來檢索對(duì)象的特性或集合的元素。文字表示固定的值 ― 數(shù)字、字符、字符串、布爾型或空值。運(yùn)算符允許對(duì)數(shù)據(jù)和文字進(jìn)行組合以及比較。



清單 4. 組合靜態(tài)文本和多個(gè) EL 表達(dá)式以指定動(dòng)態(tài)屬性值
<c:out value="Hello ${user.firstName} ${user.lastName}"/>

限制了作用域的變量

JSP API 通過 <jsp:useBean> 操作允許從 JSP 容器內(nèi)的四個(gè)不同作用域中存儲(chǔ)和檢索數(shù)據(jù)。JSTL 通過提供用于指定和除去這些作用域中的對(duì)象的附加操作來擴(kuò)展這一能力。此外,EL 提供將這些對(duì)象作為限制了作用域的變量進(jìn)行檢索的內(nèi)置支持。特別地,任何出現(xiàn)在 EL 表達(dá)式中但不對(duì)應(yīng)于任何 EL 隱式對(duì)象的標(biāo)識(shí)符,都被自動(dòng)假定為引用存儲(chǔ)在四個(gè) JSP 作用域的其中某個(gè)中的對(duì)象,這四個(gè)作用域是:

  • 頁面作用域
  • 請(qǐng)求作用域
  • 會(huì)話作用域
  • 應(yīng)用程序作用域

您可能還記得,只有在為特定請(qǐng)求處理頁面期間才能檢索存儲(chǔ)在該頁面作用域中的對(duì)象。如果對(duì)象是存儲(chǔ)在請(qǐng)求作用域中的,可以在處理所有參與處理某請(qǐng)求的頁面期間檢索這些對(duì)象(譬如在對(duì)某個(gè)請(qǐng)求的處理中遇到了一個(gè)或多個(gè) <jsp:include><jsp:forward> 操作)。如果對(duì)象是存儲(chǔ)在會(huì)話作用域中的,則在與 Web 應(yīng)用程序的交互式會(huì)話期間,可以由用戶訪問的任何頁面檢索它(即,直到與該用戶交互相關(guān)聯(lián)的 HttpSession 對(duì)象無效為止)。可以由任何用戶從任何頁面訪問存儲(chǔ)在應(yīng)用程序作用域中的對(duì)象,直到卸載 Web 應(yīng)用程序本身為止(通常是由于關(guān)閉 JSP 容器所致)。

通過將字符串映射為期望作用域中的對(duì)象來將對(duì)象存儲(chǔ)到該作用域。然后,就可以通過提供相同字符串來從該作用域檢索該對(duì)象。在作用域的映射中查找字符串,并返回被映射的對(duì)象。在 Servlet API 中,將此類對(duì)象稱為相應(yīng)作用域的 屬性。但是,在 EL 的上下文中,也將與屬性相關(guān)聯(lián)的字符串看作變量的名稱,該變量通過屬性映射的方式獲得特定的值。

在 EL 中,與隱式對(duì)象無關(guān)聯(lián)的標(biāo)識(shí)符被認(rèn)為是存儲(chǔ)在四個(gè) JSP 作用域中的名稱對(duì)象。首先對(duì)頁面作用域檢查是否存在這樣的標(biāo)識(shí)符,其次對(duì)請(qǐng)求作用域、然后對(duì)會(huì)話作用域、最后對(duì)應(yīng)用程序作用域依次進(jìn)行這樣的檢查,然后測試該標(biāo)識(shí)符的名稱是否與存儲(chǔ)在該作用域中的某個(gè)對(duì)象的名稱匹配。第一個(gè)這樣的匹配作為 EL 標(biāo)識(shí)符的值被返回。通過這種方法,可以將 EL 標(biāo)識(shí)符看作引用限制了作用域的變量。

從更技術(shù)的方面來說,沒有映射到隱式對(duì)象的標(biāo)識(shí)符是用 PageContext 實(shí)例的 findAttribute() 方法求值的,該實(shí)例表示對(duì)頁面的處理,在該頁面上,當(dāng)前正在處理用于請(qǐng)求的表達(dá)式。標(biāo)識(shí)符的名稱作為參數(shù)傳遞給這個(gè)方法,然后該方法依次在四個(gè)作用域中搜索具有相同名稱的屬性。并將所找到的第一個(gè)匹配項(xiàng)作為 findAttribute() 方法的值返回。如果未在這四個(gè)作用域中找到這樣的屬性,則返回 null

最終,限制了作用域的變量是四個(gè) JSP 作用域的屬性,這些屬性具有可以用作 EL 標(biāo)識(shí)符的名稱。只要對(duì)限制了作用域的變量賦予由字母數(shù)字組成的名稱,就可以通過 JSP 中提供的用于設(shè)置屬性的任何機(jī)制來創(chuàng)建它們。這包括內(nèi)置的 <jsp:useBean> 操作,以及由 Servlet API 中的幾個(gè)類定義的 setAttribute() 方法。此外,四個(gè) JSTL 庫中定義的許多定制標(biāo)記本身就能夠設(shè)置作為限制了作用域的變量使用的屬性值。

隱式對(duì)象

表 1 中列出了 11 個(gè) EL 隱式對(duì)象的標(biāo)識(shí)符。不要將這些對(duì)象與 JSP 隱式對(duì)象(一共只有九個(gè))混淆,其中只有一個(gè)對(duì)象是它們所共有的。

表 1. EL 隱式對(duì)象

類別 標(biāo)識(shí)符 描述
JSP pageContext PageContext 實(shí)例對(duì)應(yīng)于當(dāng)前頁面的處理
作用域 pageScope 與頁面作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的 Map
requestScope 與請(qǐng)求作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的 Map
sessionScope 與會(huì)話作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的 Map
applicationScope 與應(yīng)用程序作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的 Map
請(qǐng)求參數(shù) param 按名稱存儲(chǔ)請(qǐng)求參數(shù)的主要值的 Map
paramValues 將請(qǐng)求參數(shù)的所有值作為 String 數(shù)組存儲(chǔ)的 Map
請(qǐng)求頭 header 按名稱存儲(chǔ)請(qǐng)求頭主要值的 Map
headerValues 將請(qǐng)求頭的所有值作為 String 數(shù)組存儲(chǔ)的 Map
Cookie cookie 按名稱存儲(chǔ)請(qǐng)求附帶的 cookie 的 Map
初始化參數(shù) initParam 按名稱存儲(chǔ) Web 應(yīng)用程序上下文初始化參數(shù)的 Map

盡管 JSP 和 EL 隱式對(duì)象中只有一個(gè)公共對(duì)象( pageContext ),但通過 EL 也可以訪問其它 JSP 隱式對(duì)象。原因是 pageContext 擁有訪問所有其它八個(gè) JSP 隱式對(duì)象的特性。實(shí)際上,這是將它包括在 EL 隱式對(duì)象中的主要理由。

其余所有 EL 隱式對(duì)象都是映射,可以用來查找對(duì)應(yīng)于名稱的對(duì)象。前四個(gè)映射表示先前討論的各種屬性作用域。可以用它們來查找特定作用域中的標(biāo)識(shí)符,而不用依賴于 EL 在缺省情況下使用的順序查找過程。

接下來的四個(gè)映射用來獲取請(qǐng)求參數(shù)和請(qǐng)求頭的值。因?yàn)?HTTP 協(xié)議允許請(qǐng)求參數(shù)和請(qǐng)求頭具有多個(gè)值,所以它們各有一對(duì)映射。每對(duì)中的第一個(gè)映射返回請(qǐng)求參數(shù)或頭的主要值,通常是恰巧在實(shí)際請(qǐng)求中首先指定的那個(gè)值。每對(duì)中第二個(gè)映射允許檢索參數(shù)或頭的所有值。這些映射中的鍵是參數(shù)或頭的名稱,但這些值是 String 對(duì)象的數(shù)組,其中的每個(gè)元素都是單一參數(shù)值或頭值。

cookie 隱式對(duì)象提供了對(duì)由請(qǐng)求設(shè)置的 cookie 名稱的訪問。這個(gè)對(duì)象將所有與請(qǐng)求相關(guān)聯(lián)的 cookie 名稱映射到表示那些 cookie 特性的 Cookie 對(duì)象。

最后一個(gè) EL 隱式對(duì)象 initParam 是一個(gè)映射,它儲(chǔ)存與 Web 應(yīng)用程序相關(guān)聯(lián)的所有上下文的初始化參數(shù)的名稱和值。初始化參數(shù)是通過 web.xml 部署描述符文件指定的,該文件位于應(yīng)用程序的 WEB-INF 目錄中。


存取器

因?yàn)?EL 標(biāo)識(shí)符是作為隱式對(duì)象或限制了作用域的變量(通過屬性來實(shí)現(xiàn))解析的,因此有必要將它們轉(zhuǎn)換成 Java 對(duì)象。EL 可以自動(dòng)包裝和解包其相應(yīng)的 Java 類中的基本類型(例如,可以在后臺(tái)將 int 強(qiáng)制轉(zhuǎn)換成 Integer 類,反之亦可),但大多數(shù)的標(biāo)識(shí)符將成為指向完整的 Java 對(duì)象的指針。

結(jié)果是,對(duì)這些對(duì)象的特性或(在對(duì)象是數(shù)組和集合的情況下)對(duì)其元素的訪問通常是令人滿意的。就為了實(shí)現(xiàn)這種用途,EL 提供了兩種不同的存取器(點(diǎn)運(yùn)算符( . )和方括號(hào)運(yùn)算符( [] )),也支持通過 EL 操作特性和元素。

點(diǎn)運(yùn)算符通常用于訪問對(duì)象的特性。例如,在表達(dá)式 ${user.firstName} 中,使用點(diǎn)運(yùn)算符來訪問 user 標(biāo)識(shí)符所引用對(duì)象的名為 firstName 的特性。EL 使用 Java bean 約定訪問對(duì)象特性,因此必須定義這個(gè)特性的 getter 方法(通常是名為 getFirstName() 的方法),以便表達(dá)式正確求值。當(dāng)被訪問的特性本身是對(duì)象時(shí),可以遞歸地應(yīng)用點(diǎn)運(yùn)算符。例如,如果我們虛構(gòu)的 user 對(duì)象有一個(gè)實(shí)現(xiàn)為 Java 對(duì)象的 address 特性,那么也可以用點(diǎn)運(yùn)算符來訪問這個(gè)對(duì)象的特性。例如,表達(dá)式 ${user.address.city} 將會(huì)返回這個(gè)地址對(duì)象嵌套的 city 特性。

方括號(hào)運(yùn)算符用來檢索數(shù)組和集合的元素。在數(shù)組和有序集合(也即,實(shí)現(xiàn)了 java.util.List 接口的集合)的情況下,把要檢索的元素的下標(biāo)放在方括號(hào)中。例如,表達(dá)式 ${urls[3]} 返回 urls 標(biāo)識(shí)符所引用的數(shù)組或集合的第四個(gè)元素(和 Java 語言以及 JavaScript 中一樣,EL 中的下標(biāo)是從零開始的)。

對(duì)于實(shí)現(xiàn) java.util.Map 接口的集合,方括號(hào)運(yùn)算符使用關(guān)聯(lián)的鍵查找存儲(chǔ)在映射中的值。在方括號(hào)中指定鍵,并將相應(yīng)的值作為表達(dá)式的值返回。例如,表達(dá)式 ${commands["dir"]} 返回與 commands 標(biāo)識(shí)符所引用的 Map 中的 "dir" 鍵相關(guān)聯(lián)的值。

對(duì)于上述兩種情況,都可允許表達(dá)式出現(xiàn)在方括號(hào)中。對(duì)嵌套表達(dá)式求值的結(jié)果將被作為下標(biāo)或鍵,用來檢索集合或數(shù)組的適當(dāng)元素。和點(diǎn)運(yùn)算符一樣,方括號(hào)運(yùn)算符也可以遞歸應(yīng)用。這使得 EL 能夠從多維數(shù)組、嵌套集合或兩者的任意組合中檢索元素。此外,點(diǎn)運(yùn)算符和方括號(hào)運(yùn)算符還可以互操作。例如,如果數(shù)組的元素本身是對(duì)象,則可以使用方括號(hào)運(yùn)算符來檢索該數(shù)組的元素,并結(jié)合點(diǎn)運(yùn)算符來檢索該元素的一個(gè)特性(例如 ${urls[3].protocol} )。

假定 EL 充當(dāng)指定動(dòng)態(tài)屬性值的簡化語言,EL 存取器有一個(gè)有趣的功能(與 Java 語言的存取器不同),那就是它們在應(yīng)用于 null 時(shí)不拋出異常。如果應(yīng)用 EL 存取器的對(duì)象(例如, ${foo.bar}${foo["bar"]} 中的 foo 標(biāo)識(shí)符)是 null ,那么應(yīng)用存取器的結(jié)果也是 null 。事實(shí)證明,在大多數(shù)情況下,這是一個(gè)相當(dāng)有用的行為,不久您就會(huì)了解這一點(diǎn)。

最后,點(diǎn)運(yùn)算符和方括號(hào)運(yùn)算符可能實(shí)現(xiàn)某種程度的互換。例如,也可以使用 ${user["firstName"]} 來檢索 user 對(duì)象的 firstName 特性,正如可以用 ${commands.dir} 獲取與 commands 映射中的 "dir" 鍵相關(guān)聯(lián)的值一樣。


運(yùn)算符

EL 還可以通過使用標(biāo)識(shí)符和存取器,遍歷包含應(yīng)用程序數(shù)據(jù)(通過限制了作用域的變量公開)或關(guān)于環(huán)境的信息(通過 EL 隱式對(duì)象)的對(duì)象層次結(jié)構(gòu)。但是,只是訪問這些數(shù)據(jù),通常不足以實(shí)現(xiàn)許多 JSP 應(yīng)用程序所需的表示邏輯。

最終,EL 還包括了幾個(gè)用來操作和比較 EL 表達(dá)式所訪問數(shù)據(jù)的運(yùn)算符。表 2 中匯總了這些運(yùn)算符。

表 2. EL 運(yùn)算符

類別 運(yùn)算符
算術(shù)運(yùn)算符 +-*/ (或 div )和 % (或 mod
關(guān)系運(yùn)算符 == (或 eq )、 != (或 ne )、 < (或 lt )、 > (或 gt )、 <= (或 le )和 >= (或 ge
邏輯運(yùn)算符 && (或 and )、 || (或 or )和 ! (或 not
驗(yàn)證運(yùn)算符 empty

算術(shù)運(yùn)算符支持?jǐn)?shù)值的加法、減法、乘法和除法。還提供了一個(gè)求余運(yùn)算符。注:除法和求余運(yùn)算符都有替代的、非符號(hào)的名稱(為的是與 XPath 保持一致)。清單 5 中顯示了一個(gè)演示算術(shù)運(yùn)算符用法的示例表達(dá)式。對(duì)幾個(gè) EL 表達(dá)式應(yīng)用算術(shù)運(yùn)算符的結(jié)果是將該算術(shù)運(yùn)算符應(yīng)用于這些表達(dá)式返回的數(shù)值所得的結(jié)果。



清單 5. 利用算術(shù)運(yùn)算符的 EL 表達(dá)式
${item.price * (1 + taxRate[user.address.zipcode])}

關(guān)系運(yùn)算符允許比較數(shù)字或文本數(shù)據(jù)。比較的結(jié)果作為布爾值返回。邏輯運(yùn)算符允許合并布爾值,返回新的布爾值。因此,可以將 EL 邏輯運(yùn)算符應(yīng)用于嵌套的關(guān)系或邏輯運(yùn)算符的結(jié)果,如清單 6 所示。



清單 6. 利用關(guān)系和邏輯運(yùn)算符的 EL 表達(dá)式
${(x >= min) && (x <= max)}

最后一種 EL 運(yùn)算符是 empty ,它對(duì)于驗(yàn)證數(shù)據(jù)特別有用。 empty 運(yùn)算符采用單個(gè)表達(dá)式作為其變量(也即, ${empty input} ),并返回一個(gè)布爾值,該布爾值表示對(duì)表達(dá)式求值的結(jié)果是不是“空”值。求值結(jié)果為 null 的表達(dá)式被認(rèn)為是空,即無元素的集合或數(shù)組。如果參數(shù)是對(duì)長度為零的 String 求值所得的結(jié)果,則 empty 運(yùn)算符也將返回 true

表 3 顯示了 EL 運(yùn)算符的優(yōu)先級(jí)。正如清單 5 和 6 所示,可以用圓括號(hào)對(duì)表達(dá)式分組,高于普通的優(yōu)先級(jí)規(guī)則。

表 3. EL 運(yùn)算符優(yōu)先級(jí)(自頂?shù)降祝瑥淖蟮接遥?/font>

[] , .
()
unary -not!empty
*/div%mod
+ 、binary -
() <</code>><=>=ltgtlege
==!=eqne
&&and
||or

文字

在 EL 表達(dá)式中,數(shù)字、字符串、布爾值和 null 都可以被指定為文字值。字符串可以用單引號(hào)或雙引號(hào)定界。布爾值被指定為 truefalse


Taglib 偽指令

正如我們先前討論的,JSTL 1.0 包括四個(gè)定制標(biāo)記庫。為了演示 JSTL 標(biāo)記和表達(dá)式語言的交互,我們將研究幾個(gè)來自 JSTL core 庫的標(biāo)記。和使用任何 JSP 定制標(biāo)記庫一樣,必須在您想要使用這個(gè)庫標(biāo)記的任何頁面中包括 taglib 偽指令。清單 7 顯示了用于這個(gè)特定庫的偽指令。



清單 7. 用于 JSTL core 庫 EL 版本的 taglib 偽指令
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

實(shí)際上,對(duì)應(yīng)于 JSTL core 庫的 taglib 偽指令有兩種,因?yàn)樵?JSTL 1.0 中,EL 是可選的。所有四個(gè) JSTL 1.0 定制標(biāo)記庫都有使用 JSP 表達(dá)式(而不是 EL)指定動(dòng)態(tài)屬性值的備用版本。因?yàn)檫@些備用庫依賴于 JSP 的更傳統(tǒng)的請(qǐng)求時(shí)屬性值,所以它們被稱為 RT庫,而那些使用表達(dá)式語言的則被稱為 EL 庫。開發(fā)人員用不同的 taglib 偽指令來區(qū)分每個(gè)庫的這兩個(gè)版本。清單 8 顯示了使用 core 庫的 RT 版本的偽指令。但是,由于現(xiàn)在我們討論的重點(diǎn)是 EL,所以首先需要這些偽指令。



清單 8. 用于 JSTL core 庫 RT 版本的 taglib 偽指令
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %>

變量標(biāo)記

我們首先要考慮的 JSTL 定制標(biāo)記是 <c:set> 操作。正如已經(jīng)說明的,限制了作用域的變量在 JSTL 中起關(guān)鍵作用, <c:set> 操作提供基于標(biāo)記的機(jī)制來創(chuàng)建和設(shè)置限制了作用域的變量。清單 9 中顯示了該操作的語法,其中 var 屬性指定了限制了作用域的變量的名稱, scope 屬性表明了該變量駐留在哪個(gè)作用域中, value 屬性指定了分配給該變量的值。如果指定變量已經(jīng)存在,則簡單地將所指明的值賦給它。如果不存在,則創(chuàng)建新的限制了作用域的變量,并用該值初始化這個(gè)變量。



清單 9. <c:set> 操作的語法
<c:set var="
        name" scope="
        scope" value="
        expression"/>
      

scope 屬性是可選的,其缺省值是 page

清單 10 中顯示了 <c:set> 的兩個(gè)示例。在第一個(gè)示例中,將會(huì)話作用域變量設(shè)置成 String 值。在第二個(gè)示例中,用表達(dá)式來設(shè)置數(shù)值:將頁面作用域內(nèi)名為 square 的變量賦值為名為 x 的請(qǐng)求參數(shù)的值的平方。



清單 10. <c:set> 操作示例
<c:set var="timezone" scope="session" value="CST"/>
<c:set var="square" value="${param['x'] * param['x']}"/>

您還可以將限制了作用域的變量的值指定為 <c:set> 操作的主體內(nèi)容,而不是使用屬性。使用這種方法,您可以重新編寫清單 10 中的第一個(gè)示例,如清單 11 所示。此外,正如我們馬上可以看到的, <c:set> 標(biāo)記的主體內(nèi)容本身也可以使用定制標(biāo)記。 <c:set> 主體內(nèi)生成的所有內(nèi)容都將作為一個(gè) String 值賦給指定變量。



清單 11. 通過主體內(nèi)容指定 <c:set> 操作的值
<c:set var="timezone" scope="session">CST</c:set>

JSTL core 庫包含第二個(gè)用于管理限制了作用域的變量的標(biāo)記 ― <c:remove> 。顧名思義, <c:remove> 操作是用來刪除限制了作用域的變量的,它獲取兩個(gè)屬性。 var 屬性指定待刪除變量的名稱, scope 屬性是可選的,它表示待刪除變量來自哪個(gè)作用域,缺省為 page ,如清單 12 所示。

清單 12. <c:remove> 操作示例
<c:remove var="timezone" scope="session"/>

輸出

盡管 <c:set> 操作允許將表達(dá)式結(jié)果賦給限制了作用域的變量,但開發(fā)人員通常會(huì)希望只顯示表達(dá)式的值,而不存儲(chǔ)它。JSTL <c:out> 定制標(biāo)記承擔(dān)這一任務(wù),其語法如清單 13 所示。該標(biāo)記對(duì)由其 value 屬性指定的表達(dá)式進(jìn)行求值,然后打印結(jié)果。如果指定了可選屬性 default ,那么,在對(duì) value 屬性的表達(dá)式求值所得結(jié)果為 null 或空 String 的情況下, <c:out> 將打印其值。



清單 13. <c:out> 操作的語法
<c:out value="
        expression" default="
        expression" escapeXml="
        boolean"/>
      

escapeXml 屬性也是可選的。它控制當(dāng)用 <c:out> 標(biāo)記輸出諸如“<”、“>”和“&”之類的字符(在 HTML 和 XML 中具有特殊意義)時(shí)是否應(yīng)該進(jìn)行轉(zhuǎn)義。如果將 escapeXml 設(shè)置為 true,則會(huì)自動(dòng)將這些字符轉(zhuǎn)換成相應(yīng)的 XML 實(shí)體(此處提到的字符分別轉(zhuǎn)換成 <>& )。

例如,假定有一個(gè)名為 user 的會(huì)話作用域變量,它是一個(gè)類的實(shí)例,該類為用戶定義了兩個(gè)特性: usernamecompany 。每當(dāng)用戶訪問站點(diǎn)時(shí),這個(gè)對(duì)象被自動(dòng)分配給會(huì)話,但直到用戶實(shí)際登錄后,才會(huì)設(shè)置這兩個(gè)特性。假定是這種方案,請(qǐng)考慮清單 14 中的 JSP 片段。在用戶登錄之后,這個(gè)片段將顯示單詞“Hello”,其后是他/她的用戶名和一個(gè)驚嘆號(hào)。但是,在用戶登錄之前,由這個(gè)片段生成的內(nèi)容則是短語“Hello Guest!”。在這種情況下,因?yàn)?username 特性還有待初始化,所以 <c:out> 標(biāo)記將轉(zhuǎn)而打印出 default 屬性的值(即字符串“Guest”)。



清單 14. 帶缺省內(nèi)容的 <c:out> 操作示例
Hello <c:out value="${user.username}" default=="Guest"/>!

接下來,考慮清單 15,它使用了 <c:out> 標(biāo)記的 escapeXml 屬性。如果在這種情況下已經(jīng)將 company 特性設(shè)置成 Java String"Flynn & Sons" ,那么,實(shí)際上該操作生成的內(nèi)容將是 Flynn & Sons 。如果這個(gè)操作是生成 HTML 或 XML 內(nèi)容的 JSP 頁面的一部分,那么,這個(gè)字符串中間的“&”符號(hào)最終可能被解釋為 HTML 或 XML 控制字符,從而妨礙了對(duì)該內(nèi)容的顯示或解析。但是,如果將 escapeXml 屬性值設(shè)置成 true ,則所生成的內(nèi)容將是 Flynn & Sons 。瀏覽器或解析器不會(huì)因在解釋時(shí)遇到這種內(nèi)容而出問題。假定 HTML 和 XML 是 JSP 應(yīng)用程序中最常見的內(nèi)容類型,所以 escapeXml 屬性的缺省值是 true 就不足為奇了。



清單 15. 禁用轉(zhuǎn)義的 <c:out> 操作示例
<c:out value="${user.company}" escapeXml=="false"/>




用缺省值設(shè)置變量

除了簡化動(dòng)態(tài)數(shù)據(jù)的顯示之外,當(dāng)通過 <c:set> 設(shè)置變量值時(shí), <c:out> 指定缺省值的能力也很有用。正如 清單 11 所示,用來賦給限制了作用域的變量的值可以指定為 <c:set> 標(biāo)記的主體內(nèi)容,也可以通過其值屬性來指定。通過將 <c:out> 操作嵌套在 <c:set> 標(biāo)記的主體內(nèi)容中,變量賦值就可以利用其缺省值能力。

清單 16 中說明了這種方法。外部 <c:set> 標(biāo)記的行為非常簡單:它根據(jù)其主體內(nèi)容設(shè)置會(huì)話作用域 timezone 變量的值。但是,在這種情況下,主體內(nèi)容是通過 <c:out> 操作生成的。這個(gè)嵌套操作的值屬性是表達(dá)式 ${cookie['tzPref'].value} ,它嘗試通過 cookie 隱式對(duì)象返回名為 tzPref 的 cookie 值。( cookie 隱式對(duì)象將 cookie 名稱映射到相應(yīng)的 Cookie 實(shí)例,這意味著必須通過對(duì)象的 value 特性使用點(diǎn)運(yùn)算符來檢索儲(chǔ)存在 cookie 中的實(shí)際數(shù)據(jù)。)



清單 16. 合并 <c:set> 和 <c:out> 以提供缺省變量值
<c:set var="timezone" scope=="session">
   <c:out value="${cookie['tzPref'].value}" default=="CST"/>
</c:set>

但是,請(qǐng)考慮以下情況,用戶是第一次嘗試使用這段代碼的 Web 應(yīng)用程序。結(jié)果是,請(qǐng)求中沒有提供名為 tzPref 的 cookie。這意味著使用隱式對(duì)象的查找將返回 null ,在這種情況下整個(gè)表達(dá)式將返回 null 。因?yàn)閷?duì) <c:out> 標(biāo)記的 value 屬性求值的結(jié)果是 null ,所以 <c:out> 標(biāo)記會(huì)轉(zhuǎn)而輸出對(duì)其 default 屬性求值的結(jié)果。在這里是字符串 CST 。因此,實(shí)際的結(jié)果是將 timezone 限制了作用域的變量設(shè)置成用戶的 tzPref cookie 中存儲(chǔ)的時(shí)區(qū),或者,如果沒有,則使用缺省時(shí)區(qū) CST

EL 和 JSP 2.0

目前,表達(dá)式語言僅可用于指定 JSTL 定制標(biāo)記中的動(dòng)態(tài)屬性值。但 JSTL 1.0 表達(dá)式語言的一個(gè)擴(kuò)展已經(jīng)被提出,會(huì)把它包括到 JSP 2.0 中去,眼下正在進(jìn)行最后評(píng)審。這個(gè)擴(kuò)展將允許開發(fā)人員通過自己的定制標(biāo)記來使用 EL。頁面作者將可以在目前允許使用 JSP 表達(dá)式的任何地方使用 EL 表達(dá)式,譬如將動(dòng)態(tài)值插入模板文本中: <p>Your preferred time zone is ${timezone}</p>

這個(gè) JSP 2.0 功能(就象 JSTL 本身一樣)將支持頁面作者進(jìn)一步減少對(duì) JSP 編制腳本元素的依賴,從而改進(jìn) JSP 應(yīng)用程序的可維護(hù)性。


結(jié)束語

EL(與四個(gè) JSTL 定制標(biāo)記庫提供的操作結(jié)合起來)允許頁面作者不使用腳本元素即可實(shí)現(xiàn)表示層邏輯。例如,對(duì)比本文開頭 清單 1 中的 JSP 代碼和清單 17 中顯示的通過 JSTL 實(shí)現(xiàn)的同樣功能。(JSTL core 庫中其余的標(biāo)記,包括 <c:choose> 及其子標(biāo)記,將在本系列的下一篇文章中討論。)盡管顯然執(zhí)行了條件邏輯,但是 JSTL 版本中沒有 Java 語言源代碼,并且標(biāo)記之間的關(guān)系(尤其是關(guān)于嵌套需求)對(duì)于任何精通 HTML 語法的人都應(yīng)該是熟悉的。



清單 17. 合并 <c:set> 和 <c:out> 以提供缺省變量值
<c:choose><c:when test="${user.role == 'member'}">
    <p>Welcome, member!</p>
  </c:when><c:otherwise>
    <p>Welcome, guest!</p>
  </c:otherwise></c:choose>

通過提供大多數(shù) Web 應(yīng)用程序常用功能的標(biāo)準(zhǔn)實(shí)現(xiàn),JSTL 有助于加速開發(fā)周期。與 EL 結(jié)合起來,JSTL 可以不需要對(duì)表示層程序編寫代碼,這極大地簡化了 JSP 應(yīng)用程序的維護(hù)。



參考資料



關(guān)于作者

Mark Kolb 是一名在德克薩斯州奧斯汀工作的軟件工程師。他經(jīng)常就服務(wù)器端 Java 主題在業(yè)界發(fā)表演講,并且與人合著了 Web Development with JavaServer Pages,第二版一書。可通過 mak@taglib.com與 Mark 聯(lián)系。




]]>
編碼問題(轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/12/10/86656.htmlliaojiyongliaojiyongSun, 10 Dec 2006 03:46:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/12/10/86656.htmlhttp://www.aygfsteel.com/liaojiyong/comments/86656.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/12/10/86656.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/86656.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/86656.html??? 情況是這樣的:我們現(xiàn)在使用的一個(gè)名為Notepad++的編輯器,它大體上和UltraEdit類似,是我從sourceforge上下載下載使用的。它有個(gè)格式的功能,簡單而言就是設(shè)置使用ascii編碼編輯文檔還是使用utf-8編碼,其實(shí)這里主要是對(duì)應(yīng)非英文方面的字符才發(fā)生差異。
??? 如前那篇隨筆所述utf-8只是用于在數(shù)據(jù)傳輸時(shí)將字符串分割成字節(jié)傳輸出去,它對(duì)于unicode編碼有著嚴(yán)格的一一對(duì)應(yīng)關(guān)系,而對(duì)于gb2312、gbk、gb18030之類的中文編碼是沒有對(duì)應(yīng)關(guān)系的。gb2312、gbk、gb18030是在ascii編碼之上進(jìn)行的中文編碼開發(fā),所以它們是與ascii相兼容的,可以這么理解在我們的文本編輯器中ascii方式編輯的文本是以ascii碼保存,而以u(píng)tf-8方式編輯的文本是以u(píng)nicode編碼保存。
??? 現(xiàn)在,編碼的差異就在這里發(fā)生了,unicode中的英文部分編碼是與ascii相兼容的,具體而言是iso8859-1兼容,所以我們無論用什么編碼保存方式保存jsp文件,在網(wǎng)頁上顯示的都是正確的英文字符。但是對(duì)于中文這個(gè)保存的格式卻非常重要。在了解了jsp頁面的顯示過程我們就會(huì)明白其中的原因。
??? 現(xiàn)在回頭來看看jsp文件是經(jīng)過了哪些步驟才在網(wǎng)頁上顯示出來的。
??? 1、首先我們用編輯器編輯jsp頁面代碼保存;
??? 2、web服務(wù)器對(duì)其進(jìn)行編譯,將jsp頁面編譯成為一個(gè)java的class文件;
??? 3、web服務(wù)器將其class文件用傳輸格式在網(wǎng)絡(luò)上傳輸;
??? 4、客戶端瀏覽器解析代碼生成頁面。
??? 過程大致如上,能夠影響編碼方面的基本上在1、2、4方面,所以對(duì)其進(jìn)行詳細(xì)講解。
??? 我們的編輯器是有一種默認(rèn)的編碼保存方式的。這會(huì)到后面java編譯器是否將其中的中文進(jìn)行轉(zhuǎn)換的問題。大家都知道java是以十六位的unicode編碼編譯、存儲(chǔ)java文件的。因?yàn)橥粋€(gè)漢字在unicode編碼和gb2312編碼中的位置是不一樣的,(具體而言就是這兩種編碼沒有兼容性,也不能通過公式換算出來,只能通過字符對(duì)應(yīng)表進(jìn)行轉(zhuǎn)換)
??? 上面指出的保存格式的重要性就在這里體現(xiàn)出來了,這也是很多人容易遺漏之處,當(dāng)我們用默認(rèn)格式位gbk的編輯器編輯jsp頁面,而在其頭部聲明charset=utf-8,那么返回的頁面會(huì)出現(xiàn)亂碼,而charset=gb2312則正常顯示。本人分析原因在于,在charset=utf-8的聲明有誤時(shí),java編譯器會(huì)錯(cuò)誤的認(rèn)為現(xiàn)在保存的文件就是以u(píng)nicode編碼格式保存的文件,所以在編譯中就不對(duì)其中的中文字符進(jìn)行g(shù)b2312--unicode的轉(zhuǎn)化,而直接將其gb2312指向的編碼地址保存為unicode的編碼地址。反之,當(dāng)編輯器的默認(rèn)編輯保存格式為utf-8時(shí),在jsp中聲明為gb2312,就會(huì)讓編譯器畫蛇添足的多進(jìn)行一次中文編碼轉(zhuǎn)換,從而亂碼出現(xiàn)。
??? 綜上所述,編輯器的默認(rèn)編碼方式是在解決中文亂碼方面是很重要的一個(gè)因素,當(dāng)然我們可以用pageEncoding參數(shù)來說明文本編碼形式。弄清中文顯示后面的具體調(diào)用過程是徹底解決該類問題的終極之道!

posted on 2006-12-07 14:42 stme 閱讀(490) 評(píng)論(7) ?編輯?收藏引用收藏至365Key

評(píng)論

#?re: 編碼問題 2006-12-07 16:22 BeanSoft

不錯(cuò), 必須在頭部加入下列聲明:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="GBK"%>

要不然你就得用編輯器另存為的時(shí)候(例如記事本就有這個(gè)功能, 但是貌似有問題)轉(zhuǎn)換編碼為 UTF-8.

服務(wù)器看到 contentType="text/html; charset=UTF-8" 的頁面聲明的時(shí)候, 就認(rèn)為下面的內(nèi)容都是 UTF-8, 如果這時(shí)候不加上 pageEncoding, 出來的內(nèi)容自然就是亂碼.

因此要么都用 GBK, 要么都用 UTF-8. 可以在 Eclipse 里進(jìn)行設(shè)置讓所有的源文件的默認(rèn)字符集都是 UTF-8. 如果要做開源項(xiàng)目, 強(qiáng)烈建議的是不要用 GBK 格式的編碼, 用 UTF-8 是上上策. 還有就是鼓勵(lì)英文注釋, 網(wǎng)頁內(nèi)容國際化, 呵呵.??回復(fù)??

#?re: 編碼問題 2006-12-07 17:00 hahahehe

1、首先我們用編輯器編輯jsp頁面代碼保存;
2、web服務(wù)器對(duì)其進(jìn)行編譯,將jsp頁面編譯成為一個(gè)java的class文件;
3、web服務(wù)器將其class文件用傳輸格式在網(wǎng)絡(luò)上傳輸;
4、客戶端瀏覽器解析代碼生成頁面。

非applet的情況下,服務(wù)器怎么可能把class傳輸?shù)骄W(wǎng)絡(luò)上去,瀏覽器又怎么可能解析class?服務(wù)器傳輸?shù)氖莌tml,class生成html的過程早在服務(wù)器端就已經(jīng)完成。

亂碼的直接原因就在于服務(wù)器在頭里告訴瀏覽器的編碼 charset=UTF-8 和事實(shí)上生成html的編碼是不一致的??回復(fù)??

#?re: 編碼問題 2006-12-07 17:13 BeanSoft[匿名]

呵呵, 這段話的確是有點(diǎn)問題...

應(yīng)該是:
1. 我們用代碼編輯器編輯了一個(gè)頁面(encoding=GBK)
2. Web 服務(wù)器調(diào)用編譯器將其編譯為 servlet(編譯器也會(huì)有個(gè) encoding 選項(xiàng), 一般都是跟著系統(tǒng)的 encoding 走, 頁面有 charset 的話就跟頁面的 charset 或者 pageEncoding 一致, 所以有時(shí)候不指定JSP編譯默認(rèn)編碼, 不同的服務(wù)器出來的結(jié)果就不一樣), (encoding=GBK);
3. 生成 HTML, 這沒啥, 直接 write string;
4. 瀏覽器根據(jù) head 里的 contentType (UTF-8)來判斷編碼, 或者根據(jù)頁面里的 meta 來判斷編碼
<meta http-equiv="content-type" content="text/html; charset=UTF-8">, 什么都沒的時(shí)候就當(dāng)成西歐字符集, 具體哪個(gè)優(yōu)先? 印象中是頁面里的 meta 優(yōu)先, 這時(shí)候客戶需要手工選一個(gè)編碼才能看到正確的網(wǎng)頁.

所以只有這些條件都一致的時(shí)候, 才不會(huì)亂碼, 否則都會(huì)亂碼. 一般推薦全用 UTF-8(英文服務(wù)器環(huán)境) 或者 GBK(中文服務(wù)器).??回復(fù)??

#?re: 編碼問題 2006-12-08 00:27 weidagang2046

上次看你另一篇文章,對(duì)編碼分析得很詳細(xì),很有幫助。再接再厲!??回復(fù)??

#?re: 編碼問題 2006-12-08 09:44 stme[匿名]

謝謝大家的點(diǎn)評(píng),大家一起進(jìn)步吧!??回復(fù)??

#?re: 編碼問題 2006-12-08 13:44 laoshi

>>utf-8只是用于在數(shù)據(jù)傳輸時(shí)將字符串分割成字節(jié)傳輸出去,它對(duì)于unicode編碼有著嚴(yán)格的一一對(duì)應(yīng)關(guān)系,而對(duì)于gb2312、gbk、gb18030之類的中文編碼是沒有對(duì)應(yīng)關(guān)系的。gb2312、gbk、gb18030是在ascii編碼之上進(jìn)行的中文編碼開發(fā),所以它們是與ascii相兼容的
gb18030也和unicode有著嚴(yán)格的一一對(duì)應(yīng)關(guān)系,gb2312、gbk和unicode的子集有著嚴(yán)格的一一對(duì)應(yīng)關(guān)系
UTF-8和gb18030都是所謂的外碼標(biāo)準(zhǔn)
“gb2312、gbk、gb18030是在ascii編碼之上進(jìn)行的中文編碼開發(fā),所以它們是與ascii相兼容的”是錯(cuò)誤的,只能說UTF-8以及國標(biāo)編碼的單字節(jié)編碼區(qū)和ascii的0~7F區(qū)的編碼是一致的。
Notepad++和UltraEdit的ascii其實(shí)并不是ascii,而是指Windows平臺(tái)的本地多字節(jié)字符集,一般咱們用的中文Windows上就是gbk??回復(fù)??

#?re: 編碼問題2006-12-08 16:13 luguoren

”gb18030也和unicode有著嚴(yán)格的一一對(duì)應(yīng)關(guān)系,gb2312、gbk和unicode的子集有著嚴(yán)格的一一對(duì)應(yīng)關(guān)系“
這個(gè)是對(duì)的嗎?本人好像沒有看到這樣的資料,gb18030只是一部分與unicode對(duì)應(yīng),不會(huì)是全部一一對(duì)應(yīng)吧??回復(fù)??



]]>
代碼生成工具M(jìn)ySQL2JSP 0.3 版本發(fā)布了http://www.aygfsteel.com/liaojiyong/archive/2006/08/24/65499.htmlliaojiyongliaojiyongThu, 24 Aug 2006 05:19:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/08/24/65499.htmlhttp://www.aygfsteel.com/liaojiyong/comments/65499.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/08/24/65499.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/65499.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/65499.html代碼生成工具MySQL2JSP?0.3 版本發(fā)布了。

MySQL2JSP是一個(gè)快速開發(fā)工具,可以讓你從Mysql中直接生成JSP、servlets,以及JavaBeans。并且會(huì)生成增加、刪除、修改、查看記錄等JSP頁面。使用JDBC。某種程度上,有點(diǎn)像是簡化的RAILS。
http://sourceforge.net/projects/db2jspgen/



]]>
使用SiteMesh簡化網(wǎng)頁布局(轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/07/24/59819.htmlliaojiyongliaojiyongMon, 24 Jul 2006 07:25:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/07/24/59819.htmlhttp://www.aygfsteel.com/liaojiyong/comments/59819.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/07/24/59819.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/59819.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/59819.html閱讀全文

]]>
JSP實(shí)現(xiàn)留言板的JavaBean類和分頁顯示的源碼http://www.aygfsteel.com/liaojiyong/archive/2006/07/21/59319.htmlliaojiyongliaojiyongThu, 20 Jul 2006 17:43:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/07/21/59319.htmlhttp://www.aygfsteel.com/liaojiyong/comments/59319.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/07/21/59319.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/59319.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/59319.html

//留言bean
package userinfobean;

/**
?* <p>Title: </p>
?* <p>Description: </p>
?* <p>Copyright: Copyright (c) 2004</p>
?* <p>Company: </p>
?* @author not attributable
?* @version 1.0
?*/

public class memoBean {

? private String id;//1.用戶名
? private String email;//2.密碼
? private String content;//3.留言?

? public memoBean() {
? }
? //1.用戶名
? public void setId(String s){
??? this.id=s;
? }
? //2.密碼
? public void setEmail(String s){
??? this.email=s;
? }
? //3.留言
?? public void setContent(String s){
??? this.content=s;
? }
?

? //1.用戶名
?? public String getId( ){
???? return this.id;
?? }
?? //2.密碼
?? public String getEmail(){
???? return this.email;
?? }
?? //3.留言?
?? public String getContent(){
???? return this.content;
?? }
}
//// 用于數(shù)據(jù)庫操作的bean??????????
package userinfobean;

import userinfobean.*;
import java.io.*;
import java.util.*;
import java.sql.*;


public class databaseBean{
? private String dbName;
? private String dbUser;
? private String dbPass;
???private Vector memoVector;

?? Connection connection;

? public databaseBean(){
??? dbName=new String("×××××××");
??? dbUser=new String("××××××");
??? dbPass=new String("×××××××");
??? String connectionUrl="jdbc:mysql://localhost/"+dbName;
??? try{
????? Class.forName("org.gjt.mm.mysql.Driver");
????? connection=DriverManager.getConnection(connectionUrl,dbUser,dbPass);
??? }
??? catch(Exception e){
????? System.out.println(e.toString());
????? }
? }

? public void dbQueryMemos(){
??? try{
?????? memoVector=new Vector();
????? Statement stmt=connection.createStatement();
????? ResultSet rs=stmt.executeQuery("select * from memo;");
????? while(rs.next()){
??????? memoBean temp=new memoBean();
??????? temp.setId(rs.getString(2));
??????? temp.setEmail(rs.getString(3));
??????? temp.setContent(rs.getString(4));
??????? memoVector.add(temp);
????? }

?? }
?? catch(SQLException e){
???? System.out.println(e.toString());
?? }

?

? }

??? public void setDbName(String s){
??? this.dbName=s;
? }
? public void setDbUser(String s){
??? this.dbUser=s;
? }
? public void setDbPass(String s){
??? this.dbPass=s;
? }

? public String getDbName(){
??? return this.dbName;
? }
? public String getDbUser(){
??? return this.dbUser;
? }
? public String getDbPass(){
??? return this.dbPass;
? }
??? public Vector getMemoVector(){
??? return this.memoVector;

? }

}

///以下是網(wǎng)頁源碼

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ page language="java" import="java.util.*" %>
<%@ page? import="java.text.*" %>
<%@ page? import="userinfobean.*" %>
<jsp:useBean id="memoInfo" scope="page" class="userinfobean.memoBean"/>
<jsp:useBean id="memoQuery" scope="page" class="userinfobean.databaseBean"/>
<%!
int totalPages;
int countPerPage=3;
int totalCount;
int currentPage=0;
int currentStart;
%>
<%
memoQuery.dbQueryMemos();
Vector vt=memoQuery.getMemoVector();
totalCount=vt.size();
totalPages=totalCount/countPerPage;
if(totalCount%countPerPage>0)totalPages=totalPages+1;
if(request.getParameter("page")==null)
{
currentPage=1;
}
else
{
currentPage=Integer.parseInt(request.getParameter("page"));
if(currentPage>totalPages)currentPage=totalPages;
if(currentPage<1)currentPage=1;
}
currentStart=totalCount-1-countPerPage * (currentPage-1);
%>
<html>
<head>
<title>NetGreen</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
? <link rel="stylesheet" href="main.css">????????????????????????????
</head>
<script language="JavaScript" >
function page_check()
{
if(document.pageForm.page.value=="")
{alert("請(qǐng)輸入頁數(shù)");
document.pageForm.page.focus();
return false;
}
return true;
}</script>
<body bgcolor="ffffff"? >

<center>
? <table width="800" border="0" height="622">
??? <tr>
????? <td height="71" align="center" valign="middle"> <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0099CC">
????????? <tr>
??????????? <td width="19%" height="60" align="left" valign="bottom" bgcolor="#FFFFFF"><b><font size="4" color="#00cc66" ><img src="image/logo.gif" width="156" height="60"></font></b></td>
??????????? <td width="57%" align="left" valign="bottom" bgcolor="#FFFFFF"><img src="image/banner.gif" width="100%" height="60"></td>
??????????? <td width="24%" align="left" valign="bottom"> <table width="102%" height="60" border="1" cellpadding="0" cellspacing="0" bordercolor="#0099CC" bgcolor="#FFFFFF">
??????????????? <tr>
????????????????? <td width="50%" height="27" align="center">上 傳</td>
????????????????? <td width="50%" align="center">收藏本頁</td>
??????????????? </tr>
??????????????? <tr>
????????????????? <td height="21" align="center" bgcolor="#FFFFFF" >退 出 </td>
????????????????? <td align="center"><a href="memoForm.htm" target="_self">我要留言</a></td>
??????????????? </tr>
????????????? </table></td>
????????? </tr>
??????? </table></td>
??? </tr>
??? <tr>
????? <td height="31"><table width="100%" border="1" bordercolor="#0099CC">
????????? <tr bgcolor="#00CC66">
??????????? <td width="12%" height="23" align="center" bgcolor="#CCFFFF"><a href="index.htm" >首頁</a></td>
??????????? <td width="12%" align="center" bgcolor="#CCFFFF"><a href="loginForm.htm" >登陸</a></td>
??????????? <td width="12%" align="center" bgcolor="#CCFFFF">&nbsp;</td>
??????????? <td width="12%" align="center" bgcolor="#CCFFFF">&nbsp;</td>
??????????? <td width="12%" align="center" bgcolor="#CCFFFF" >&nbsp; </td>
??????????? <td width="12%" align="center" bgcolor="#CCFFFF">&nbsp;</td>
??????????? <td width="12%" align="center" bgcolor="#CCFFFF"><a href="memoDisplay.jsp" >留言板</a></td>
??????????? <td width="12%" align="center"? bgcolor="#CCFFFF"><a href="registForm.htm">注冊</a></td>
????????? </tr>
??????? </table></td>
??? </tr>
??? <tr>
????? <td height="435" align="center" valign="top" nowrap>
??????? <table width="100%"? border="1" cellpadding="0" cellspacing="0" bordercolor="#0099CC">
????????? <tr>
??????????? <td width="18%" height="431" align="center" valign="middle" bgcolor="#CCFFFF">
??????????? </td>
??????????? <td width="83%" align="center" valign="top" bgcolor="#FFFFFF"><table width="100%" border="1"><form name="pageForm" method="post"? onSubmit="return page_check();"action="memoDisplay.jsp">
??????????????? <tr>
????????????????? <td width="36%">共有留言<%out.print(totalPages);%> 頁,現(xiàn)在是第<%out.print(currentPage);%>? 頁</td>
??????????????????? <td width="64%">
?????<a href="memoDisplay.jsp?page=<%=currentPage-1%>" >上一頁 </a>
?????<a href="memoDisplay.jsp?page=<%=currentPage+1%>" >下一頁? </a>
?????<a href="memoDisplay.jsp?page=1" >首頁 </a>
????? <a href="memoDisplay.jsp?page=<%=totalPages%>" >尾頁? </a>
????? <input type="submit" name="Submit" value="G0">
????????????????????? <input name="page" type="text" size="10">
????????????????????? 頁</td>
??????????????? </tr>
????????????? </form></table>
????????????? <%
????
????for(int i=0;i<countPerPage&&currentStart-i>=0;i++)
????{
?????memoInfo.setId(((memoBean)vt.get(currentStart-i)).getId());
?????memoInfo.setEmail(((memoBean)vt.get(currentStart-i)).getEmail());
?????memoInfo.setContent(((memoBean)vt.get(currentStart-i)).getContent());
?????
?????
?????
???out.print("<table width='100%' border='1' ><tr><td width='19%'>");
???out.print(memoInfo.getId());
???out.print("</td><td width='81%'>");
???out.print(memoInfo.getEmail());
???out.print("</td></tr><tr><td height='44' colspan='2'>");
???out.print(memoInfo.getContent());
???out.print("</td></tr></table> ");
???out.print("<br>");
?????
????}
??
???%>
???</td>
????????? </tr>
??????? </table>
????? </td>
??? </tr>
??? <tr>
????? <td height="73" align="center" valign="top" nowrap>
??????? <table width="100%" border="0">
????????? <tr>
??????????? <td height="21" align="center" bgcolor="#FFFFFF"><hr width="85%" noshade? color="#00CC66"></td>
????????? </tr>
????????? <tr>
??????????? <td height="12" align="center">Copyright @ HomeLee. All rights reserved.
??????????? </td>
????????? </tr>
????????? <tr>
??????????? <td height="12" align="center" bgcolor="#FFFFFF">&nbsp;</td>
????????? </tr>
??????? </table></td>
??? </tr>
? </table>
? </center></body>
</html>



]]>
上傳下載全攻略jspSmartUpload(轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/07/03/56388.htmlliaojiyongliaojiyongMon, 03 Jul 2006 09:24:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/07/03/56388.htmlhttp://www.aygfsteel.com/liaojiyong/comments/56388.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/07/03/56388.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/56388.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/56388.html一、安裝篇?

  jspSmartUpload是由www.jspsmart.com網(wǎng)站開發(fā)的一個(gè)可免費(fèi)使用的全功能的文件上傳下載組件,適于嵌入執(zhí)行上傳下載操作的JSP文件中。該組件有以下幾個(gè)特點(diǎn):?

1、使用簡單。在JSP文件中僅僅書寫三五行JAVA代碼就可以搞定文件的上傳或下載,方便。?

2、能全程控制上傳。利用jspSmartUpload組件提供的對(duì)象及其操作方法,可以獲得全部上傳文件的信息(包括文件名,大小,類型,擴(kuò)展名,文件數(shù)據(jù)等),方便存取。?

3、能對(duì)上傳的文件在大小、類型等方面做出限制。如此可以濾掉不符合要求的文件。?

4、下載靈活。僅寫兩行代碼,就能把Web服務(wù)器變成文件服務(wù)器。不管文件在Web服務(wù)器的目錄下或在其它任何目錄下,都可以利用jspSmartUpload進(jìn)行下載。?

5、能將文件上傳到數(shù)據(jù)庫中,也能將數(shù)據(jù)庫中的數(shù)據(jù)下載下來。這種功能針對(duì)的是MYSQL數(shù)據(jù)庫,因?yàn)椴痪哂型ㄓ眯裕员疚牟粶?zhǔn)備舉例介紹這種用法。?

  jspSmartUpload組件可以從www.jspsmart.com網(wǎng)站上自由下載,壓縮包的名字是jspSmartUpload.zip。下載后,用WinZip或WinRAR將其解壓到Tomcat的webapps目錄下(本文以Tomcat服務(wù)器為例進(jìn)行介紹)。解壓后,將webapps/jspsmartupload目錄下的子目錄Web-inf名字改為全大寫的WEB-INF,這樣一改jspSmartUpload類才能使用。因?yàn)門omcat對(duì)文件名大小寫敏感,它要求Web應(yīng)用程序相關(guān)的類所在目錄為WEB-INF,且必須是大寫。接著重新啟動(dòng)Tomcat,這樣就可以在JSP文件中使用jspSmartUpload組件了。?

  注意,按上述方法安裝后,只有webapps/jspsmartupload目錄下的程序可以使用jspSmartUpload組件,如果想讓Tomcat服務(wù)器的所有Web應(yīng)用程序都能用它,必須做如下工作:?

1.進(jìn)入命令行狀態(tài),將目錄切換到Tomcat的webapps/jspsmartupload/WEB-INF目錄下。?

2.運(yùn)行JAR打包命令:jar?cvf?jspSmartUpload.jar?com?

(也可以打開資源管理器,切換到當(dāng)前目錄,用WinZip將com目錄下的所有文件壓縮成jspSmartUpload.zip,然后將jspSmartUpload.zip換名為jspSmartUpload.jar文件即可。)?

3.將jspSmartUpload.jar拷貝到Tomcat的shared/lib目錄下。?

二、相關(guān)類說明篇?

㈠?File類?

  這個(gè)類包裝了一個(gè)上傳文件的所有信息。通過它,可以得到上傳文件的文件名、文件大小、擴(kuò)展名、文件數(shù)據(jù)等信息。?

  File類主要提供以下方法:?

1、saveAs作用:將文件換名另存。?

原型:?

public?void?saveAs(java.lang.String?destFilePathName)?

或?

public?void?saveAs(java.lang.String?destFilePathName,?int?optionSaveAs)?

其中,destFilePathName是另存的文件名,optionSaveAs是另存的選項(xiàng),該選項(xiàng)有三個(gè)值,分別是SAVEAS_PHYSICAL,SAVEAS_VIRTUAL,SAVEAS_AUTO。SAVEAS_PHYSICAL表明以操作系統(tǒng)的根目錄為文件根目錄另存文件,SAVEAS_VIRTUAL表明以Web應(yīng)用程序的根目錄為文件根目錄另存文件,SAVEAS_AUTO則表示讓組件決定,當(dāng)Web應(yīng)用程序的根目錄存在另存文件的目錄時(shí),它會(huì)選擇SAVEAS_VIRTUAL,否則會(huì)選擇SAVEAS_PHYSICAL。?

例如,saveAs("/upload/sample.zip",SAVEAS_PHYSICAL)執(zhí)行后若Web服務(wù)器安裝在C盤,則另存的文件名實(shí)際是c:\upload\sample.zip。而saveAs("/upload/sample.zip",SAVEAS_VIRTUAL)執(zhí)行后若Web應(yīng)用程序的根目錄是webapps/jspsmartupload,則另存的文件名實(shí)際是webapps/
建議:對(duì)于Web程序的開發(fā)來說,最好使用SAVEAS_VIRTUAL,以便移植。?

2、isMissing?

作用:這個(gè)方法用于判斷用戶是否選擇了文件,也即對(duì)應(yīng)的表單項(xiàng)是否有值。選擇了文件時(shí),它返回false。未選文件時(shí),它返回true。?

原型:public?boolean?isMissing()?

3、getFieldName?

作用:取HTML表單中對(duì)應(yīng)于此上傳文件的表單項(xiàng)的名字。?

原型:public?String?getFieldName()?

4、getFileName?

作用:取文件名(不含目錄信息)?

原型:public?String?getFileName()?

5、getFilePathName?

作用:取文件全名(帶目錄)?

原型:public?String?getFilePathName?

6、getFileExt?

作用:取文件擴(kuò)展名(后綴)?

原型:public?String?getFileExt()?

7、getSize?

作用:取文件長度(以字節(jié)計(jì))?

原型:public?int?getSize()?

8、getBinaryData?

作用:取文件數(shù)據(jù)中指定位移處的一個(gè)字節(jié),用于檢測文件等處理。?

原型:public?byte?getBinaryData(int?index)。其中,index表示位移,其值在0到getSize()-1之間。?

㈡?Files類?

  這個(gè)類表示所有上傳文件的集合,通過它可以得到上傳文件的數(shù)目、大小等信息。有以下方法:?

1、getCount?

作用:取得上傳文件的數(shù)目。?

原型:public?int?getCount()?

2、getFile?

作用:取得指定位移處的文件對(duì)象File(這是com.
jspsmart.upload.File,不是java.io.File,注意區(qū)分)。?

原型:public?File?getFile(int?index)。其中,index為指定位移,其值在0到getCount()-1之間。?

3、getSize?

作用:取得上傳文件的總長度,可用于限制一次性上傳的數(shù)據(jù)量大小。?

原型:public?long?getSize()?

4、getCollection?

作用:將所有上傳文件對(duì)象以Collection的形式返回,以便其它應(yīng)用程序引用,瀏覽上傳文件信息。?

原型:public?Collection?getCollection()?

5、getEnumeration?

作用:將所有上傳文件對(duì)象以Enumeration(枚舉)的形式返回,以便其它應(yīng)用程序?yàn)g覽上傳文件信息。?

原型:public?Enumeration?getEnumeration()?

㈢?Request類?

  這個(gè)類的功能等同于JSP內(nèi)置的對(duì)象request。只所以提供這個(gè)類,是因?yàn)閷?duì)于文件上傳表單,通過request對(duì)象無法獲得表單項(xiàng)的值,必須通過jspSmartUpload組件提供的Request對(duì)象來獲取。該類提供如下方法:?

1、getParameter?

作用:獲取指定參數(shù)之值。當(dāng)參數(shù)不存在時(shí),返回值為null。?

原型:public?String?getParameter(String?name)。其中,name為參數(shù)的名字。?

2、getParameterValues?

作用:當(dāng)一個(gè)參數(shù)可以有多個(gè)值時(shí),用此方法來取其值。它返回的是一個(gè)字符串?dāng)?shù)組。當(dāng)參數(shù)不存在時(shí),返回值為null。?

原型:public?String[]?getParameterValues(String?name)。其中,name為參數(shù)的名字。?

3、getParameterNames?

作用:取得Request對(duì)象中所有參數(shù)的名字,用于遍歷所有參數(shù)。它返回的是一個(gè)枚舉型的對(duì)象。?

原型:public?Enumeration?getParameterNames()?

㈣?SmartUpload類這個(gè)類完成上傳下載工作。?

A.上傳與下載共用的方法:?

只有一個(gè):initialize。?

作用:執(zhí)行上傳下載的初始化工作,必須第一個(gè)執(zhí)行。?

原型:有多個(gè),主要使用下面這個(gè):?

public?final?void?initialize(javax.servlet.jsp.PageContext?pageContext)?

其中,pageContext為JSP頁面內(nèi)置對(duì)象(頁面上下文)。?

B.上傳文件使用的方法:?

1、upload?

作用:上傳文件數(shù)據(jù)。對(duì)于上傳操作,第一步執(zhí)行initialize方法,第二步就要執(zhí)行這個(gè)方法。?

原型:public?void?upload()?

2、save?

作用:將全部上傳文件保存到指定目錄下,并返回保存的文件個(gè)數(shù)。?

原型:public?int?save(String?destPathName)?

和public?int?save(String?destPathName,int?option)?

其中,destPathName為文件保存目錄,option為保存選項(xiàng),它有三個(gè)值,分別是SAVE_PHYSICAL,SAVE_VIRTUAL和SAVE_AUTO。(同F(xiàn)ile類的saveAs方法的選項(xiàng)之值類似)SAVE_PHYSICAL指示組件將文件保存到以操作系統(tǒng)根目錄為文件根目錄的目錄下,SAVE_VIRTUAL指示組件將文件保存到以Web應(yīng)用程序根目錄為文件根目錄的目錄下,而SAVE_AUTO則表示由組件自動(dòng)選擇。?

注:save(destPathName)作用等同于save(destPathName,SAVE_AUTO)。?

3、getSize?

作用:取上傳文件數(shù)據(jù)的總長度?

原型:public?int?getSize()?

4、getFiles?

作用:取全部上傳文件,以Files對(duì)象形式返回,可以利用Files類的操作方法來獲得上傳文件的數(shù)目等信息。?

原型:public?Files?getFiles()?

5、getRequest?

作用:取得Request對(duì)象,以便由此對(duì)象獲得上傳表單參數(shù)之值。?

原型:public?Request?getRequest()?

6、setAllowedFilesList?

作用:設(shè)定允許上傳帶有指定擴(kuò)展名的文件,當(dāng)上傳過程中有文件名不允許時(shí),組件將拋出異常。?

原型:public?void?setAllowedFilesList(String?allowedFilesList)?

其中,allowedFilesList為允許上傳的文件擴(kuò)展名列表,各個(gè)擴(kuò)展名之間以逗號(hào)分隔。如果想允許上傳那些沒有擴(kuò)展名的文件,可以用兩個(gè)逗號(hào)表示。例如:setAllowedFilesList("doc,txt,,")將允許上傳帶doc和txt擴(kuò)展名的文件以及沒有擴(kuò)展名的文件。?

7、setDeniedFilesList?

作用:用于限制上傳那些帶有指定擴(kuò)展名的文件。若有文件擴(kuò)展名被限制,則上傳時(shí)組件將拋出異常。?

原型:public?void?setDeniedFilesList(String?deniedFilesList)?

其中,deniedFilesList為禁止上傳的文件擴(kuò)展名列表,各個(gè)擴(kuò)展名之間以逗號(hào)分隔。如果想禁止上傳那些沒有擴(kuò)展名的文件,可以用兩個(gè)逗號(hào)來表示。例如:setDeniedFilesList("exe,bat,,")將禁止上傳帶exe和bat擴(kuò)展名的文件以及沒有擴(kuò)展名的文件。?

8、setMaxFileSize?

作用:設(shè)定每個(gè)文件允許上傳的最大長度。?

原型:public?void?setMaxFileSize(long?maxFileSize)?

其中,maxFileSize為為每個(gè)文件允許上傳的最大長度,當(dāng)文件超出此長度時(shí),將不被上傳。?

9、setTotalMaxFileSize?

作用:設(shè)定允許上傳的文件的總長度,用于限制一次性上傳的數(shù)據(jù)量大小。?

原型:public?void?setTotalMaxFileSize(long?totalMaxFileSize)?

其中,totalMaxFileSize為允許上傳的文件的總長度。



1、setContentDisposition?

作用:將數(shù)據(jù)追加到MIME文件頭的CONTENT-DISPOSITION域。jspSmartUpload組件會(huì)在返回下載的信息時(shí)自動(dòng)填寫MIME文件頭的CONTENT-DISPOSITION域,如果用戶需要添加額外信息,請(qǐng)用此方法。?

原型:public?void?setContentDisposition(String?contentDisposition)?

其中,contentDisposition為要添加的數(shù)據(jù)。如果contentDisposition為null,則組件將自動(dòng)添加"attachment;",以表明將下載的文件作為附件,結(jié)果是IE瀏覽器將會(huì)提示另存文件,而不是自動(dòng)打開這個(gè)文件(IE瀏覽器一般根據(jù)下載的文件擴(kuò)展名決定執(zhí)行什么操作,擴(kuò)展名為doc的將用word程序打開,擴(kuò)展名為pdf的將用acrobat程序打開,等等)。?

2、downloadFile?

作用:下載文件。?

原型:共有以下三個(gè)原型可用,第一個(gè)最常用,后兩個(gè)用于特殊情況下的文件下載(如更改內(nèi)容類型,更改另存的文件名)。?

①?public?void?downloadFile(String?sourceFilePathName)?

其中,sourceFilePathName為要下載的文件名(帶目錄的文件全名)?

②?public?void?downloadFile(String?sourceFilePathName,String?contentType)?

其中,sourceFilePathName為要下載的文件名(帶目錄的文件全名),contentType為內(nèi)容類型(MIME格式的文件類型信息,可被瀏覽器識(shí)別)。?

③?public?void?downloadFile(String?sourceFilePathName,String?contentType,String?destFileName)?

其中,sourceFilePathName為要下載的文件名(帶目錄的文件全名),contentType為內(nèi)容類型(MIME格式的文件類型信息,可被瀏覽器識(shí)別),destFileName為下載后默認(rèn)的另存文件名。?

三、文件上傳篇?

㈠?表單要求?

對(duì)于上傳文件的FORM表單,有兩個(gè)要求:?

1、METHOD應(yīng)用POST,即METHOD="POST"。?

2、增加屬性:ENCTYPE="multipart/form-data"?

下面是一個(gè)用于上傳文件的FORM表單的例子:?



<FORM?METHOD="POST"?ENCTYPE="multipart/form-data"?
ACTION="/jspSmartUpload/upload.<INPUT?TYPE="FILE"?NAME="MYFILE">
<INPUT?TYPE="SUBMIT">
</FORM>
?


㈡?上傳的例子?

1、上傳頁面upload.html?

本頁面提供表單,讓用戶選擇要上傳的文件,點(diǎn)擊"上傳"按鈕執(zhí)行上傳操作。?

頁面源碼如下:?

<!--
????文件名:upload.html
作??者:縱橫軟件制作中心雨亦奇(zhsoft88@sohu.com)
-->
<!DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN">
<html>
<head>
<title>文件上傳</title>
<meta?http-equiv="Content-Type"?content="text/html;?charset=gb2312">
</head>

<body>
<p>?</p>
<p?align="center">上傳文件選擇</p>
<FORM?METHOD="POST"?ACTION="
jsp/do_upload.ENCTYPE="multipart/form-data">
<input?type="hidden"?name="TEST"?value="good">
??<table?width="75%"?border="1"?align="center">
????<tr>?
??????<td><div?align="center">1、?
??????????<input?type="FILE"?name="FILE1"?size="30">
????????</div></td>
????</tr>
????<tr>?
??????<td><div?align="center">2、?
??????????<input?type="FILE"?name="FILE2"?size="30">
????????</div></td>
????</tr>
????<tr>?
??????<td><div?align="center">3、?
??????????<input?type="FILE"?name="FILE3"?size="30">
????????</div></td>
????</tr>
????<tr>?
??????<td><div?align="center">4、?
??????????<input?type="FILE"?name="FILE4"?size="30">
????????</div></td>
????</tr>
????<tr>?
??????<td><div?align="center">
??????????<input?type="submit"?name="Submit"?value="上傳它!">
????????</div></td>
????</tr>
??</table>
</FORM>
</body>
</html>
?


2、上傳處理頁面do_upload.
jsp?

本頁面執(zhí)行文件上傳操作。頁面源碼中詳細(xì)介紹了上傳方法的用法,在此不贅述了。?

頁面源碼如下:?

<%--
文件名:do_upload.jsp
作??者:縱橫軟件制作中心雨亦奇(zhsoft88@sohu.com)
--%>
<%@?page?contentType="text/html;?charset=gb2312"?language="java"?
import="java.util.*,com.<html>
<head>
<title>文件上傳處理頁面</title>
<meta?http-equiv="Content-Type"?content="text/html;?charset=gb2312">
</head>

<body>
<%
//?新建一個(gè)SmartUpload對(duì)象
SmartUpload?su?=?new?SmartUpload();
//?上傳初始化
su.initialize(pageContext);
//?設(shè)定上傳限制
//?1.限制每個(gè)上傳文件的最大長度。
//?su.setMaxFileSize(10000);
//?2.限制總上傳數(shù)據(jù)的長度。
//?su.setTotalMaxFileSize(20000);
//?3.設(shè)定允許上傳的文件(通過擴(kuò)展名限制),僅允許doc,txt文件。
//?su.setAllowedFilesList("doc,txt");
//?4.設(shè)定禁止上傳的文件(通過擴(kuò)展名限制),禁止上傳帶有exe,bat,
jsp,htm,html擴(kuò)展名的文件和沒有擴(kuò)展名的文件。
//?su.setDeniedFilesList("exe,bat,//?上傳文件
su.upload();
//?將上傳文件全部保存到指定目錄
int?count?=?su.save("/upload");
out.println(count+"個(gè)文件上傳成功!<br>");

//?利用Request對(duì)象獲取參數(shù)之值
out.println("TEST="+su.getRequest().getParameter("TEST")
+"<BR><BR>");

//?逐一提取上傳文件信息,同時(shí)可保存文件。
for?(int?i=0;i<su.getFiles().getCount();i++)
{
com.
jspsmart.upload.File?file?=?su.getFiles().getFile(i);

//?若文件不存在則繼續(xù)
if?(file.isMissing())?continue;

//?顯示當(dāng)前文件信息
out.println("<TABLE?BORDER=1>");
out.println("<TR><TD>表單項(xiàng)名(FieldName)</TD><TD>"
+?file.getFieldName()?+?"</TD></TR>");
out.println("<TR><TD>文件長度(Size)</TD><TD>"?+?
file.getSize()?+?"</TD></TR>");
out.println("<TR><TD>文件名(FileName)</TD><TD>"?
+?file.getFileName()?+?"</TD></TR>");
out.println("<TR><TD>文件擴(kuò)展名(FileExt)</TD><TD>"?
+?file.getFileExt()?+?"</TD></TR>");
out.println("<TR><TD>文件全名(FilePathName)</TD><TD>"
+?file.getFilePathName()?+?"</TD></TR>");
out.println("</TABLE><BR>");

//?將文件另存
//?file.saveAs("/upload/"?+?myFile.getFileName());
//?另存到以WEB應(yīng)用程序的根目錄為文件根目錄的目錄下
//?file.saveAs("/upload/"?+?myFile.getFileName(),?
su.SAVE_VIRTUAL);
//?另存到操作系統(tǒng)的根目錄為文件根目錄的目錄下
//?file.saveAs("c:\\temp\\"?+?myFile.getFileName(),?
su.SAVE_PHYSICAL);

}
%>
</body>
</html>
?


四、文件下載篇?

1、下載鏈接頁面download.html?

頁面源碼如下:?

<!--
文件名:download.html
作??者:縱橫軟件制作中心雨亦奇(zhsoft88@sohu.com)
-->
<!DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN">
<html>
<head>
<title>下載</title>
<meta?http-equiv="Content-Type"?content="text/html;?charset=gb2312">
</head>
<body>
<a?href="jsp/do_download.</body>
</html>
?


2、下載處理頁面do_download.
jsp?do_download.jsp展示了如何利用jspSmartUpload組件來下載文件,從下面的源碼中就可以看到,下載何其簡單。?

源碼如下:?

<%@?page?contentType="text/html;charset=gb2312"?
import="com.//?新建一個(gè)SmartUpload對(duì)象
SmartUpload?su?=?new?SmartUpload();
//?初始化
su.initialize(pageContext);
//?設(shè)定contentDisposition為null以禁止瀏覽器自動(dòng)打開文件,
//保證點(diǎn)擊鏈接后是下載文件。若不設(shè)定,則下載的文件擴(kuò)展名為
//doc時(shí),瀏覽器將自動(dòng)用word打開它。擴(kuò)展名為pdf時(shí),
//瀏覽器將用acrobat打開。
su.setContentDisposition(null);
//?下載文件
su.downloadFile("/upload/如何賺取我的第一桶金.doc");
%>
?


注意,執(zhí)行下載的頁面,在Java腳本范圍外(即<%?...?%>之外),不要包含HTML代碼、空格、回車或換行等字符,有的話將不能正確下載。不信的話,可以在上述源碼中%><%之間加入一個(gè)換行符,再下載一下,保證出錯(cuò)。因?yàn)樗绊懥朔祷亟o瀏覽器的數(shù)據(jù)流,導(dǎo)致解析出錯(cuò)。?

3、如何下載中文文件?

jspSmartUpload雖然能下載文件,但對(duì)中文支持不足。若下載的文件名中有漢字,則瀏覽器在提示另存的文件名時(shí),顯示的是一堆亂碼,很掃人興。上面的例子就是這樣。(這個(gè)問題也是眾多下載組件所存在的問題,很少有人解決,搜索不到相關(guān)資料,可嘆!)?

為了給jspSmartUpload組件增加下載中文文件的支持,我對(duì)該組件進(jìn)行了研究,發(fā)現(xiàn)對(duì)返回給瀏覽器的另存文件名進(jìn)行UTF-8編碼后,瀏覽器便能正確顯示中文名字了。這是一個(gè)令人高興的發(fā)現(xiàn)。于是我對(duì)jspSmartUpload組件的SmartUpload類做了升級(jí)處理,增加了toUtf8String這個(gè)方法,改動(dòng)部分源碼如下:?

public?void?downloadFile(String?s,?String?s1,?String?s2,?int?i)
throws?ServletException,?IOException,?SmartUploadException
????{
if(s?==?null)
????throw?new?IllegalArgumentException("File?''"?+?s?+
????"''?not?found?(1040).");
if(s.equals(""))
????throw?new?IllegalArgumentException("File?''"?+?s?+
????"''?not?found?(1040).");
if(!isVirtual(s)?&&?m_denyPhysicalPath)
????throw?new?SecurityException("Physical?path?is
????denied?(1035).");
if(isVirtual(s))
????s?=?m_application.getRealPath(s);
java.io.File?file?=?new?java.io.File(s);
FileInputStream?fileinputstream?=?new?FileInputStream(file);
long?l?=?file.length();
boolean?flag?=?false;
int?k?=?0;
byte?abyte0[]?=?new?byte[i];
if(s1?==?null)
????m_response.setContentType("application/x-msdownload");
else
if(s1.length()?==?0)
????m_response.setContentType("application/x-msdownload");
else
????m_response.setContentType(s1);
m_response.setContentLength((int)l);
m_contentDisposition?=?m_contentDisposition?!=?null??
m_contentDisposition?:?"attachment;";
if(s2?==?null)
????m_response.setHeader("Content-Disposition",?
????m_contentDisposition?+?"?filename="?+?
????toUtf8String(getFileName(s)));
else
if(s2.length()?==?0)
????m_response.setHeader("Content-Disposition",?
????m_contentDisposition);
else
????m_response.setHeader("Content-Disposition",?
????m_contentDisposition?+?"?filename="?+?toUtf8String(s2));
while((long)k?<?l)
{
????int?j?=?fileinputstream.read(abyte0,?0,?i);
????k?+=?j;
????m_response.getOutputStream().write(abyte0,?0,?j);
}
fileinputstream.close();
????}

????/**
?????*?將文件名中的漢字轉(zhuǎn)為UTF8編碼的串,以便下載時(shí)能正確顯示另存的文件名.
?????*?縱橫軟件制作中心雨亦奇2003.08.01
?????*?@param?s?原文件名
?????*?@return?重新編碼后的文件名
?????*/
????public?static?String?toUtf8String(String?s)?{
StringBuffer?sb?=?new?StringBuffer();
for?(int?i=0;i<s.length();i++)?{
????char?c?=?s.charAt(i);
????if?(c?>=?0?&&?c?<=?255)?{
sb.append(c);
????}?else?{
byte[]?b;
try?{
????b?=?Character.toString(c).getBytes("utf-8");
}?catch?(Exception?ex)?{
????System.out.println(ex);
????b?=?new?byte[0];
}
for?(int?j?=?0;?j?<?b.length;?j++)?{
????int?k?=?b[j];
????if?(k?<?0)?k?+=?256;
????sb.append("%"?+?Integer.toHexString(k).
????toUpperCase());
}
????}
}
return?sb.toString();
????}
?


注意源碼中粗體部分,原jspSmartUpload組件對(duì)返回的文件未作任何處理,現(xiàn)在做了編碼的轉(zhuǎn)換工作,將文件名轉(zhuǎn)換為UTF-8形式的編碼形式。UTF-8編碼對(duì)英文未作任何處理,對(duì)中文則需要轉(zhuǎn)換為%XX的形式。toUtf8String方法中,直接利用Java語言提供的編碼轉(zhuǎn)換方法獲得漢字字符的UTF-8編碼,之后將其轉(zhuǎn)換為%XX的形式。?

將源碼編譯后打包成jspSmartUpload.jar,拷貝到Tomcat的shared/lib目錄下(可為所有WEB應(yīng)用程序所共享),然后重啟Tomcat服務(wù)器就可以正常下載含有中文名字的文件了。另,toUtf8String方法也可用于轉(zhuǎn)換含有中文的超級(jí)鏈接,以保證鏈接的有效,因?yàn)橛械腤EB服務(wù)器不支持中文鏈接。?

小結(jié):jspSmartUpload組件是應(yīng)用JSP進(jìn)行B/S程序開發(fā)過程中經(jīng)常使用的上傳下載組件,它使用簡單,方便。現(xiàn)在我又為其加上了下載中文名字的文件的支持,真?zhèn)€是如虎添翼,必將贏得更多開發(fā)者的青睞。




smartupload中文亂碼文題
smartupload存在字符編碼的問題,下面是處理下載時(shí)使用中文文件名的處理方法(轉(zhuǎn)貼),上傳可以采用類似的方法:
jspSmartUpload雖然能下載文件,但對(duì)中文支持不足。若下載的文件名中有漢字,則瀏覽器在提示另存的文件名時(shí),顯示的是一堆亂碼,很掃人興。上面的例子就是這樣。(這個(gè)問題也是眾多下載組件所存在的問題,很少有人解決,搜索不到相關(guān)資料,可嘆!)

為了給jspSmartUpload組件增加下載中文文件的支持,我對(duì)該組件進(jìn)行了研究,發(fā)現(xiàn)對(duì)返回給瀏覽器的另存文件名進(jìn)行UTF-8編碼后,瀏覽器便能正確顯示中文名字了。這是一個(gè)令人高興的發(fā)現(xiàn)。于是我對(duì)jspSmartUpload組件的SmartUpload類做了升級(jí)處理,增加了toUtf8String這個(gè)方法,改動(dòng)部分源碼如下:

public void downloadFile(String s, String s1, String s2, int i)
throws ServletException, IOException, SmartUploadException
??? {
if(s == null)
??? throw new IllegalArgumentException("File ''''" + s +
??? "'''' not found (1040).");
if(s.equals(""))
??? throw new IllegalArgumentException("File ''''" + s +
??? "'''' not found (1040).");
if(!isVirtual(s) && m_denyPhysicalPath)
??? throw new SecurityException("Physical path is
??? denied (1035).");
if(isVirtual(s))
??? s = m_application.getRealPath(s);
java.io.File file = new java.io.File(s);
FileInputStream fileinputstream = new FileInputStream(file);
long l = file.length();
boolean flag = false;
int k = 0;
byte abyte0[] = new byte;
if(s1 == null)
??? m_response.setContentType("application/x-msdownload");
else
if(s1.length() == 0)
??? m_response.setContentType("application/x-msdownload");
else
??? m_response.setContentType(s1);
m_response.setContentLength((int)l);
m_contentDisposition = m_contentDisposition != null ?
m_contentDisposition : "attachment;";
if(s2 == null)
??? m_response.setHeader("Content-Disposition",
??? m_contentDisposition + " filename=" +
??? toUtf8String(getFileName(s)));
else
if(s2.length() == 0)
??? m_response.setHeader("Content-Disposition",
??? m_contentDisposition);
else
??? m_response.setHeader("Content-Disposition",
??? m_contentDisposition + " filename=" + toUtf8String(s2));
while((long)k < l)
{
??? int j = fileinputstream.read(abyte0, 0, i);
??? k += j;
??? m_response.getOutputStream().write(abyte0, 0, j);
}
fileinputstream.close();
??? }

??? /**
???? * 將文件名中的漢字轉(zhuǎn)為UTF8編碼的串,以便下載時(shí)能正確顯示另存的文件名.
???? * 縱橫軟件制作中心雨亦奇2003.08.01
???? * @param s 原文件名
???? * @return 重新編碼后的文件名
???? */
??? public static String toUtf8String(String s) {
StringBuffer sb = new StringBuffer();
for (int i=0;i<s.length();i++) {
??? char c = s.charAt(i);
??? if (c >= 0 && c <= 255) {
sb.append(c);
??? } else {
byte[] b;
try {
??? b = Character.toString(c).getBytes("utf-8");
} catch (Exception ex) {
??? System.out.println(ex);
??? b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
??? int k = b[j];
??? if (k < 0) k += 256;
??? sb.append("%" + Integer.toHexString(k).
??? toUpperCase());
}
??? }
}
return sb.toString();
??? }



]]>
介紹一篇關(guān)于session的好文章,寫的很詳細(xì)(jsp-servlet 技術(shù)) (轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/06/29/55750.htmlliaojiyongliaojiyongThu, 29 Jun 2006 06:54:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/06/29/55750.htmlhttp://www.aygfsteel.com/liaojiyong/comments/55750.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/06/29/55750.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/55750.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/55750.html

摘要:雖然session機(jī)制在web應(yīng)用程序中被采用已經(jīng)很長時(shí)間了,但是仍然有很多人不清楚session機(jī)制的本質(zhì),以至不能正確的應(yīng)用這一技術(shù)。本文將詳細(xì)討論session的工作機(jī)制并且對(duì)在Java?web?application中應(yīng)用session機(jī)制時(shí)常見的問題作出解答。

目錄:
一、術(shù)語session
二、HTTP協(xié)議與狀態(tài)保持
三、理解cookie機(jī)制
四、理解session機(jī)制
五、理解javax.servlet.http.HttpSession
六、HttpSession常見問題
七、跨應(yīng)用程序的session共享
八、總結(jié)
參考文檔

一、術(shù)語session
在我的經(jīng)驗(yàn)里,session這個(gè)詞被濫用的程度大概僅次于transaction,更加有趣的是transaction與session在某些語境下的含義是相同的。

session,中文經(jīng)常翻譯為會(huì)話,其本來的含義是指有始有終的一系列動(dòng)作/消息,比如打電話時(shí)從拿起電話撥號(hào)到掛斷電話這中間的一系列過程可以稱之為一個(gè)?session。有時(shí)候我們可以看到這樣的話“在一個(gè)瀏覽器會(huì)話期間,...”,這里的會(huì)話一詞用的就是其本義,是指從一個(gè)瀏覽器窗口打開到關(guān)閉這個(gè)期間?①。最混亂的是“用戶(客戶端)在一次會(huì)話期間”這樣一句話,它可能指用戶的一系列動(dòng)作(一般情況下是同某個(gè)具體目的相關(guān)的一系列動(dòng)作,比如從登錄到選購商品到結(jié)賬登出這樣一個(gè)網(wǎng)上購物的過程,有時(shí)候也被稱為一個(gè)transaction),然而有時(shí)候也可能僅僅是指一次連接,也有可能是指含義①,其中的差別只能靠上下文來推斷②。

然而當(dāng)session一詞與網(wǎng)絡(luò)協(xié)議相關(guān)聯(lián)時(shí),它又往往隱含了“面向連接”和/或“保持狀態(tài)”這樣兩個(gè)含義,?“面向連接”指的是在通信雙方在通信之前要先建立一個(gè)通信的渠道,比如打電話,直到對(duì)方接了電話通信才能開始,與此相對(duì)的是寫信,在你把信發(fā)出去的時(shí)候你并不能確認(rèn)對(duì)方的地址是否正確,通信渠道不一定能建立,但對(duì)發(fā)信人來說,通信已經(jīng)開始了。“保持狀態(tài)”則是指通信的一方能夠把一系列的消息關(guān)聯(lián)起來,使得消息之間可以互相依賴,比如一個(gè)服務(wù)員能夠認(rèn)出再次光臨的老顧客并且記得上次這個(gè)顧客還欠店里一塊錢。這一類的例子有“一個(gè)TCP?session”或者?“一個(gè)POP3?session”③。

而到了web服務(wù)器蓬勃發(fā)展的時(shí)代,session在web開發(fā)語境下的語義又有了新的擴(kuò)展,它的含義是指一類用來在客戶端與服務(wù)器之間保持狀態(tài)的解決方案④。有時(shí)候session也用來指這種解決方案的存儲(chǔ)結(jié)構(gòu),如“把xxx保存在session?里”⑤。由于各種用于web開發(fā)的語言在一定程度上都提供了對(duì)這種解決方案的支持,所以在某種特定語言的語境下,session也被用來指代該語言的解決方案,比如經(jīng)常把Java里提供的javax.servlet.http.HttpSession簡稱為session⑥。

鑒于這種混亂已不可改變,本文中session一詞的運(yùn)用也會(huì)根據(jù)上下文有不同的含義,請(qǐng)大家注意分辨。
在本文中,使用中文“瀏覽器會(huì)話期間”來表達(dá)含義①,使用“session機(jī)制”來表達(dá)含義④,使用“session”表達(dá)含義⑤,使用具體的“HttpSession”來表達(dá)含義⑥

二、HTTP協(xié)議與狀態(tài)保持
HTTP?協(xié)議本身是無狀態(tài)的,這與HTTP協(xié)議本來的目的是相符的,客戶端只需要簡單的向服務(wù)器請(qǐng)求下載某些文件,無論是客戶端還是服務(wù)器都沒有必要紀(jì)錄彼此過去的行為,每一次請(qǐng)求之間都是獨(dú)立的,好比一個(gè)顧客和一個(gè)自動(dòng)售貨機(jī)或者一個(gè)普通的(非會(huì)員制)大賣場之間的關(guān)系一樣。

然而聰明(或者貪心?)的人們很快發(fā)現(xiàn)如果能夠提供一些按需生成的動(dòng)態(tài)信息會(huì)使web變得更加有用,就像給有線電視加上點(diǎn)播功能一樣。這種需求一方面迫使HTML逐步添加了表單、腳本、DOM等客戶端行為,另一方面在服務(wù)器端則出現(xiàn)了CGI規(guī)范以響應(yīng)客戶端的動(dòng)態(tài)請(qǐng)求,作為傳輸載體的HTTP協(xié)議也添加了文件上載、?cookie這些特性。其中cookie的作用就是為了解決HTTP協(xié)議無狀態(tài)的缺陷所作出的努力。至于后來出現(xiàn)的session機(jī)制則是又一種在客戶端與服務(wù)器之間保持狀態(tài)的解決方案。

讓我們用幾個(gè)例子來描述一下cookie和session機(jī)制之間的區(qū)別與聯(lián)系。筆者曾經(jīng)常去的一家咖啡店有喝5杯咖啡免費(fèi)贈(zèng)一杯咖啡的優(yōu)惠,然而一次性消費(fèi)5杯咖啡的機(jī)會(huì)微乎其微,這時(shí)就需要某種方式來紀(jì)錄某位顧客的消費(fèi)數(shù)量。想象一下其實(shí)也無外乎下面的幾種方案:
1、該店的店員很厲害,能記住每位顧客的消費(fèi)數(shù)量,只要顧客一走進(jìn)咖啡店,店員就知道該怎么對(duì)待了。這種做法就是協(xié)議本身支持狀態(tài)。
2、發(fā)給顧客一張卡片,上面記錄著消費(fèi)的數(shù)量,一般還有個(gè)有效期限。每次消費(fèi)時(shí),如果顧客出示這張卡片,則此次消費(fèi)就會(huì)與以前或以后的消費(fèi)相聯(lián)系起來。這種做法就是在客戶端保持狀態(tài)。
3、發(fā)給顧客一張會(huì)員卡,除了卡號(hào)之外什么信息也不紀(jì)錄,每次消費(fèi)時(shí),如果顧客出示該卡片,則店員在店里的紀(jì)錄本上找到這個(gè)卡號(hào)對(duì)應(yīng)的紀(jì)錄添加一些消費(fèi)信息。這種做法就是在服務(wù)器端保持狀態(tài)。

由于HTTP協(xié)議是無狀態(tài)的,而出于種種考慮也不希望使之成為有狀態(tài)的,因此,后面兩種方案就成為現(xiàn)實(shí)的選擇。具體來說cookie機(jī)制采用的是在客戶端保持狀態(tài)的方案,而session機(jī)制采用的是在服務(wù)器端保持狀態(tài)的方案。同時(shí)我們也看到,由于采用服務(wù)器端保持狀態(tài)的方案在客戶端也需要保存一個(gè)標(biāo)識(shí),所以session機(jī)制可能需要借助于cookie機(jī)制來達(dá)到保存標(biāo)識(shí)的目的,但實(shí)際上它還有其他選擇。

三、理解cookie機(jī)制?
cookie機(jī)制的基本原理就如上面的例子一樣簡單,但是還有幾個(gè)問題需要解決:“會(huì)員卡”如何分發(fā);“會(huì)員卡”的內(nèi)容;以及客戶如何使用“會(huì)員卡”。

正統(tǒng)的cookie分發(fā)是通過擴(kuò)展HTTP協(xié)議來實(shí)現(xiàn)的,服務(wù)器通過在HTTP的響應(yīng)頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應(yīng)的cookie。然而純粹的客戶端腳本如JavaScript或者VBScript也可以生成cookie。

而cookie?的使用是由瀏覽器按照一定的原則在后臺(tái)自動(dòng)發(fā)送給服務(wù)器的。瀏覽器檢查所有存儲(chǔ)的cookie,如果某個(gè)cookie所聲明的作用范圍大于等于將要請(qǐng)求的資源所在的位置,則把該cookie附在請(qǐng)求資源的HTTP請(qǐng)求頭上發(fā)送給服務(wù)器。意思是麥當(dāng)勞的會(huì)員卡只能在麥當(dāng)勞的店里出示,如果某家分店還發(fā)行了自己的會(huì)員卡,那么進(jìn)這家店的時(shí)候除了要出示麥當(dāng)勞的會(huì)員卡,還要出示這家店的會(huì)員卡。

cookie的內(nèi)容主要包括:名字,值,過期時(shí)間,路徑和域。
其中域可以指定某一個(gè)域比如.google.com,相當(dāng)于總店招牌,比如寶潔公司,也可以指定一個(gè)域下的具體某臺(tái)機(jī)器比如www.google.com或者froogle.google.com,可以用飄柔來做比。
路徑就是跟在域名后面的URL路徑,比如/或者/foo等等,可以用某飄柔專柜做比。
路徑與域合在一起就構(gòu)成了cookie的作用范圍。
如果不設(shè)置過期時(shí)間,則表示這個(gè)cookie的生命期為瀏覽器會(huì)話期間,只要關(guān)閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽器會(huì)話期的?cookie被稱為會(huì)話cookie。會(huì)話cookie一般不存儲(chǔ)在硬盤上而是保存在內(nèi)存里,當(dāng)然這種行為并不是規(guī)范規(guī)定的。如果設(shè)置了過期時(shí)間,瀏覽器就會(huì)把cookie保存到硬盤上,關(guān)閉后再次打開瀏覽器,這些cookie仍然有效直到超過設(shè)定的過期時(shí)間。

存儲(chǔ)在硬盤上的cookie?可以在不同的瀏覽器進(jìn)程間共享,比如兩個(gè)IE窗口。而對(duì)于保存在內(nèi)存里的cookie,不同的瀏覽器有不同的處理方式。對(duì)于IE,在一個(gè)打開的窗口上按?Ctrl-N(或者從文件菜單)打開的窗口可以與原窗口共享,而使用其他方式新開的IE進(jìn)程則不能共享已經(jīng)打開的窗口的內(nèi)存cookie;對(duì)于?Mozilla?Firefox0.8,所有的進(jìn)程和標(biāo)簽頁都可以共享同樣的cookie。一般來說是用javascript的window.open打開的窗口會(huì)與原窗口共享內(nèi)存cookie。瀏覽器對(duì)于會(huì)話cookie的這種只認(rèn)cookie不認(rèn)人的處理方式經(jīng)常給采用session機(jī)制的web應(yīng)用程序開發(fā)者造成很大的困擾。

下面就是一個(gè)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這個(gè)HTTP?Sniffer軟件來俘獲的HTTP通訊紀(jì)錄的一部分




瀏覽器在再次訪問goolge的資源時(shí)自動(dòng)向外發(fā)送cookie




使用Firefox可以很容易的觀察現(xiàn)有的cookie的值
使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。




IE也可以設(shè)置在接受cookie前詢問




這是一個(gè)詢問接受cookie的對(duì)話框。

四、理解session機(jī)制
session機(jī)制是一種服務(wù)器端的機(jī)制,服務(wù)器使用一種類似于散列表的結(jié)構(gòu)(也可能就是使用散列表)來保存信息。

當(dāng)程序需要為某個(gè)客戶端的請(qǐng)求創(chuàng)建一個(gè)session的時(shí)候,服務(wù)器首先檢查這個(gè)客戶端的請(qǐng)求里是否已包含了一個(gè)session標(biāo)識(shí)?-?稱為?session?id,如果已包含一個(gè)session?id則說明以前已經(jīng)為此客戶端創(chuàng)建過session,服務(wù)器就按照session?id把這個(gè)?session檢索出來使用(如果檢索不到,可能會(huì)新建一個(gè)),如果客戶端請(qǐng)求不包含session?id,則為此客戶端創(chuàng)建一個(gè)session并且生成一個(gè)與此session相關(guān)聯(lián)的session?id,session?id的值應(yīng)該是一個(gè)既不會(huì)重復(fù),又不容易被找到規(guī)律以仿造的字符串,這個(gè)?session?id將被在本次響應(yīng)中返回給客戶端保存。

保存這個(gè)session?id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動(dòng)的按照規(guī)則把這個(gè)標(biāo)識(shí)發(fā)揮給服務(wù)器。一般這個(gè)cookie的名字都是類似于SEEESIONID,而。比如weblogic對(duì)于web應(yīng)用程序生成的cookie,JSESSIONID=?ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是?JSESSIONID。

由于cookie可以被人為的禁止,必須有其他機(jī)制以便在cookie被禁止時(shí)仍然能夠把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
這兩種方式對(duì)于用戶來說是沒有區(qū)別的,只是服務(wù)器在解析的時(shí)候處理的方式不同,采用第一種方式也有利于把session?id的信息和正常程序參數(shù)區(qū)分開來。
為了在整個(gè)交互過程中始終保持狀態(tài),就必須在每個(gè)客戶端可能請(qǐng)求的路徑后面都包含這個(gè)session?id。

另一種技術(shù)叫做表單隱藏字段。就是服務(wù)器會(huì)自動(dòng)修改表單,添加一個(gè)隱藏字段,以便在表單提交時(shí)能夠把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í)際上這種技術(shù)可以簡單的用對(duì)action應(yīng)用URL重寫來代替。

在談?wù)搒ession機(jī)制的時(shí)候,常常聽到這樣一種誤解“只要關(guān)閉瀏覽器,session就消失了”。其實(shí)可以想象一下會(huì)員卡的例子,除非顧客主動(dòng)對(duì)店家提出銷卡,否則店家絕對(duì)不會(huì)輕易刪除顧客的資料。對(duì)session來說也是一樣的,除非程序通知服務(wù)器刪除一個(gè)session,否則服務(wù)器會(huì)一直保留,程序一般都是在用戶做log?off的時(shí)候發(fā)個(gè)指令去刪除session。然而瀏覽器從來不會(huì)主動(dòng)在關(guān)閉之前通知服務(wù)器它將要關(guān)閉,因此服務(wù)器根本不會(huì)有機(jī)會(huì)知道瀏覽器已經(jīng)關(guān)閉,之所以會(huì)有這種錯(cuò)覺,是大部分session機(jī)制都使用會(huì)話cookie來保存session?id,而關(guān)閉瀏覽器后這個(gè)?session?id就消失了,再次連接服務(wù)器時(shí)也就無法找到原來的session。如果服務(wù)器設(shè)置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發(fā)出的HTTP請(qǐng)求頭,把原來的session?id發(fā)送給服務(wù)器,則再次打開瀏覽器仍然能夠找到原來的session。

恰恰是由于關(guān)閉瀏覽器不會(huì)導(dǎo)致session被刪除,迫使服務(wù)器為seesion設(shè)置了一個(gè)失效時(shí)間,當(dāng)距離客戶端上一次使用session的時(shí)間超過這個(gè)失效時(shí)間時(shí),服務(wù)器就可以認(rèn)為客戶端已經(jīng)停止了活動(dòng),才會(huì)把session刪除以節(jié)省存儲(chǔ)空間。

五、理解javax.servlet.http.HttpSession
HttpSession是Java平臺(tái)對(duì)session機(jī)制的實(shí)現(xiàn)規(guī)范,因?yàn)樗鼉H僅是個(gè)接口,具體到每個(gè)web應(yīng)用服務(wù)器的提供商,除了對(duì)規(guī)范支持之外,仍然會(huì)有一些規(guī)范里沒有規(guī)定的細(xì)微差異。這里我們以BEA的Weblogic?Server8.1作為例子來演示。

首先,Weblogic?Server提供了一系列的參數(shù)來控制它的HttpSession的實(shí)現(xiàn),包括使用cookie的開關(guān)選項(xiàng),使用URL重寫的開關(guān)選項(xiàng),session持久化的設(shè)置,session失效時(shí)間的設(shè)置,以及針對(duì)cookie的各種設(shè)置,比如設(shè)置cookie的名字、路徑、域,?cookie的生存時(shí)間等。

一般情況下,session都是存儲(chǔ)在內(nèi)存里,當(dāng)服務(wù)器進(jìn)程被停止或者重啟的時(shí)候,內(nèi)存里的session也會(huì)被清空,如果設(shè)置了session的持久化特性,服務(wù)器就會(huì)把session保存到硬盤上,當(dāng)服務(wù)器進(jìn)程重新啟動(dòng)或這些信息將能夠被再次使用,?Weblogic?Server支持的持久性方式包括文件、數(shù)據(jù)庫、客戶端cookie保存和復(fù)制。

復(fù)制嚴(yán)格說來不算持久化保存,因?yàn)閟ession實(shí)際上還是保存在內(nèi)存里,不過同樣的信息被復(fù)制到各個(gè)cluster內(nèi)的服務(wù)器進(jìn)程中,這樣即使某個(gè)服務(wù)器進(jìn)程停止工作也仍然可以從其他進(jìn)程中取得session。

cookie生存時(shí)間的設(shè)置則會(huì)影響瀏覽器生成的cookie是否是一個(gè)會(huì)話cookie。默認(rèn)是使用會(huì)話cookie。有興趣的可以用它來試驗(yàn)我們在第四節(jié)里提到的那個(gè)誤解。

cookie的路徑對(duì)于web應(yīng)用程序來說是一個(gè)非常重要的選項(xiàng),Weblogic?Server對(duì)這個(gè)選項(xiàng)的默認(rèn)處理方式使得它與其他服務(wù)器有明顯的區(qū)別。后面我們會(huì)專題討論。

關(guān)于session的設(shè)置參考[5]?
http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

六、HttpSession常見問題
(在本小節(jié)中session的含義為⑤和⑥的混合)


1、session在何時(shí)被創(chuàng)建
一個(gè)常見的誤解是以為session在有客戶端訪問時(shí)就被創(chuàng)建,然而事實(shí)是直到某server端程序調(diào)用?HttpServletRequest.getSession(true)這樣的語句時(shí)才被創(chuàng)建,注意如果JSP沒有顯示的使用?<%?@page?session="false"%>?關(guān)閉session,則JSP文件在編譯成Servlet時(shí)將會(huì)自動(dòng)加上這樣一條語句?HttpSession?session?=?HttpServletRequest.getSession(true);這也是JSP中隱含的?session對(duì)象的來歷。

由于session會(huì)消耗內(nèi)存資源,因此,如果不打算使用session,應(yīng)該在所有的JSP中關(guān)閉它。

2、session何時(shí)被刪除
綜合前面的討論,session在下列情況下被刪除a.程序調(diào)用HttpSession.invalidate();或b.距離上一次收到客戶端發(fā)送的session?id時(shí)間間隔超過了session的超時(shí)設(shè)置;或c.服務(wù)器進(jìn)程被停止(非持久session)

3、如何做到在瀏覽器關(guān)閉時(shí)刪除session
嚴(yán)格的講,做不到這一點(diǎn)。可以做一點(diǎn)努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監(jiān)視瀏覽器的關(guān)閉動(dòng)作,然后向服務(wù)器發(fā)送一個(gè)請(qǐng)求來刪除session。但是對(duì)于瀏覽器崩潰或者強(qiáng)行殺死進(jìn)程這些非常規(guī)手段仍然無能為力。

4、有個(gè)HttpSessionListener是怎么回事
你可以創(chuàng)建這樣的listener去監(jiān)控session的創(chuàng)建和銷毀事件,使得在發(fā)生這樣的事件時(shí)你可以做一些相應(yīng)的工作。注意是session的創(chuàng)建和銷毀動(dòng)作觸發(fā)listener,而不是相反。類似的與HttpSession有關(guān)的listener還有?HttpSessionBindingListener,HttpSessionActivationListener和?HttpSessionAttributeListener。

5、存放在session中的對(duì)象必須是可序列化的嗎
不是必需的。要求對(duì)象可序列化只是為了session能夠在集群中被復(fù)制或者能夠持久保存或者在必要時(shí)server能夠暫時(shí)把session交換出內(nèi)存。在?Weblogic?Server的session中放置一個(gè)不可序列化的對(duì)象在控制臺(tái)上會(huì)收到一個(gè)警告。我所用過的某個(gè)iPlanet版本如果?session中有不可序列化的對(duì)象,在session銷毀時(shí)會(huì)有一個(gè)Exception,很奇怪。

6、如何才能正確的應(yīng)付客戶端禁止cookie的可能性
對(duì)所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

7、開兩個(gè)瀏覽器窗口訪問應(yīng)用程序會(huì)使用同一個(gè)session還是不同的session
參見第三小節(jié)對(duì)cookie的討論,對(duì)session來說是只認(rèn)id不認(rèn)人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲(chǔ)方式都會(huì)對(duì)這個(gè)問題的答案有影響。

8、如何防止用戶打開兩個(gè)瀏覽器窗口操作導(dǎo)致的session混亂
這個(gè)問題與防止表單多次提交是類似的,可以通過設(shè)置客戶端的令牌來解決。就是在服務(wù)器每次生成一個(gè)不同的id返回給客戶端,同時(shí)保存在session里,客戶端提交表單時(shí)必須把這個(gè)id也返回服務(wù)器,程序首先比較返回的id與保存在session里的值是否一致,如果不一致則說明本次操作已經(jīng)被提交過了。可以參看《J2EE核心模式》關(guān)于表示層模式的部分。需要注意的是對(duì)于使用javascript?window.open打開的窗口,一般不設(shè)置這個(gè)id,或者使用單獨(dú)的id,以防主窗口無法操作,建議不要再window.open打開的窗口里做修改操作,這樣就可以不用設(shè)置。

9、為什么在Weblogic?Server中改變session的值后要重新調(diào)用一次session.setValue
做這個(gè)動(dòng)作主要是為了在集群環(huán)境中提示W(wǎng)eblogic?Server?session中的值發(fā)生了改變,需要向其他服務(wù)器進(jìn)程復(fù)制新的session值。

10、為什么session不見了
排除session正常失效的因素之外,服務(wù)器本身的可能性應(yīng)該是微乎其微的,雖然筆者在iPlanet6SP1加若干補(bǔ)丁的Solaris版本上倒也遇到過;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題;理論上防火墻或者代理服務(wù)器在cookie處理上也有可能會(huì)出現(xiàn)問題。
出現(xiàn)這一問題的大部分原因都是程序的錯(cuò)誤,最常見的就是在一個(gè)應(yīng)用程序中去訪問另外一個(gè)應(yīng)用程序。我們在下一節(jié)討論這個(gè)問題。

七、跨應(yīng)用程序的session共享

常常有這樣的情況,一個(gè)大項(xiàng)目被分割成若干小項(xiàng)目開發(fā),為了能夠互不干擾,要求每個(gè)小項(xiàng)目作為一個(gè)單獨(dú)的web應(yīng)用程序開發(fā),可是到了最后突然發(fā)現(xiàn)某幾個(gè)小項(xiàng)目之間需要共享一些信息,或者想使用session來實(shí)現(xiàn)SSO(single?sign?on),在session中保存login的用戶信息,最自然的要求是應(yīng)用程序間能夠訪問彼此的session。

然而按照Servlet規(guī)范,session的作用范圍應(yīng)該僅僅限于當(dāng)前應(yīng)用程序下,不同的應(yīng)用程序之間是不能夠互相訪問對(duì)方的session的。各個(gè)應(yīng)用服務(wù)器從實(shí)際效果上都遵守了這一規(guī)范,但是實(shí)現(xiàn)的細(xì)節(jié)卻可能各有不同,因此解決跨應(yīng)用程序session共享的方法也各不相同。

首先來看一下Tomcat是如何實(shí)現(xiàn)web應(yīng)用程序之間session的隔離的,從?Tomcat設(shè)置的cookie路徑來看,它對(duì)不同的應(yīng)用程序設(shè)置的cookie路徑是不同的,這樣不同的應(yīng)用程序所用的session?id是不同的,因此即使在同一個(gè)瀏覽器窗口里訪問不同的應(yīng)用程序,發(fā)送給服務(wù)器的session?id也可以是不同的。


??

根據(jù)這個(gè)特性,我們可以推測Tomcat中session的內(nèi)存結(jié)構(gòu)大致如下。




筆者以前用過的iPlanet也采用的是同樣的方式,估計(jì)SunONE與iPlanet之間不會(huì)有太大的差別。對(duì)于這種方式的服務(wù)器,解決的思路很簡單,實(shí)際實(shí)行起來也不難。要么讓所有的應(yīng)用程序共享一個(gè)session?id,要么讓應(yīng)用程序能夠獲得其他應(yīng)用程序的session?id。

iPlanet中有一種很簡單的方法來實(shí)現(xiàn)共享一個(gè)session?id,那就是把各個(gè)應(yīng)用程序的cookie路徑都設(shè)為/(實(shí)際上應(yīng)該是/NASApp,對(duì)于應(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。對(duì)于版本4以上的Tomcat,目前筆者尚未發(fā)現(xiàn)簡單的辦法。只能借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端cookie,URL參數(shù)或者隱藏字段等手段。

我們再看一下Weblogic?Server是如何處理session的。


??

從截屏畫面上可以看到Weblogic?Server對(duì)所有的應(yīng)用程序設(shè)置的cookie的路徑都是/,這是不是意味著在Weblogic?Server中默認(rèn)的就可以共享session了呢?然而一個(gè)小實(shí)驗(yàn)即可證明即使不同的應(yīng)用程序使用的是同一個(gè)session,各個(gè)應(yīng)用程序仍然只能訪問自己所設(shè)置的那些屬性。這說明Weblogic?Server中的session的內(nèi)存結(jié)構(gòu)可能如下




對(duì)于這樣一種結(jié)構(gòu),在?session機(jī)制本身上來解決session共享的問題應(yīng)該是不可能的了。除了借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端?cookie,URL參數(shù)或者隱藏字段等手段,還有一種較為方便的做法,就是把一個(gè)應(yīng)用程序的session放到ServletContext中,這樣另外一個(gè)應(yīng)用程序就可以從ServletContext中取得前一個(gè)應(yīng)用程序的引用。示例代碼如下,

應(yīng)用程序A
context.setAttribute("appA",?session);?

應(yīng)用程序B
contextA?=?context.getContext("/appA");
HttpSession?sessionA?=?(HttpSession)contextA.getAttribute("appA");?

值得注意的是這種用法不可移植,因?yàn)楦鶕?jù)ServletContext的JavaDoc,應(yīng)用服務(wù)器可以處于安全的原因?qū)τ赾ontext.getContext("/appA");返回空值,以上做法在Weblogic?Server?8.1中通過。

那么Weblogic?Server為什么要把所有的應(yīng)用程序的cookie路徑都設(shè)為/呢?原來是為了SSO,凡是共享這個(gè)session的應(yīng)用程序都可以共享認(rèn)證的信息。一個(gè)簡單的實(shí)驗(yàn)就可以證明這一點(diǎn),修改首先登錄的那個(gè)應(yīng)用程序的描述符weblogic.xml,把cookie路徑修改為/appA?訪問另外一個(gè)應(yīng)用程序會(huì)重新要求登錄,即使是反過來,先訪問cookie路徑為/的應(yīng)用程序,再訪問修改過路徑的這個(gè),雖然不再提示登錄,但是登錄的用戶信息也會(huì)丟失。注意做這個(gè)實(shí)驗(yàn)時(shí)認(rèn)證方式應(yīng)該使用FORM,因?yàn)闉g覽器和web服務(wù)器對(duì)basic認(rèn)證方式有其他的處理方式,第二次請(qǐng)求的認(rèn)證不是通過?session來實(shí)現(xiàn)的。具體請(qǐng)參看[7]?secion?14.8?Authorization,你可以修改所附的示例程序來做這些試驗(yàn)。

八、總結(jié)
session機(jī)制本身并不復(fù)雜,然而其實(shí)現(xiàn)和配置上的靈活性卻使得具體情況復(fù)雜多變。這也要求我們不能把僅僅某一次的經(jīng)驗(yàn)或者某一個(gè)瀏覽器,服務(wù)器的經(jīng)驗(yàn)當(dāng)作普遍適用的經(jīng)驗(yàn),而是始終需要具體情況具體分析。
摘要:雖然session機(jī)制在web應(yīng)用程序中被采用已經(jīng)很長時(shí)間了,但是仍然有很多人不清楚session機(jī)制的本質(zhì),以至不能正確的應(yīng)用這一技術(shù)。本文將詳細(xì)討論session的工作機(jī)制并且對(duì)在Java?web?application中應(yīng)用session機(jī)制時(shí)常見的問題作出解答。


]]>
JSP實(shí)用篇(轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/06/29/55749.htmlliaojiyongliaojiyongThu, 29 Jun 2006 06:52:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/06/29/55749.htmlhttp://www.aygfsteel.com/liaojiyong/comments/55749.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/06/29/55749.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/55749.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/55749.html一,重定向頁面

1,response.sendRedirect("url");
2,response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.setHeader("Location",newLocation);

二,HTML Encoder和URL Encoder

1,HTML Encoder自定義,原則:''不輸出,'&'-"&amp;",'<'-"&lt;",'>'-"gt;",'"'-"&quot;"
2,URLEncoder 在java.net包中有定義
原型:public static String encode(String s)
例如:URLEncoder.encode("http://wwww.aaa.com/sss.jsp?name=小鬼")

三,在JSP中讀寫文件

1,用FileOutputStream初始化PrintWriter,然后用print或者println方法寫文件
PrintWriter pw=new PrintWriter(new FileOutputStream("file1.txt"));
pw.println("Hello world!");
pw.close();//若有錯(cuò)誤thow IOException

用FileWriter初始化PrintWriter,然后用print或者println方法寫文件
File f=new File("file1.txt");
PrintWriter pw=new PrintWriter(new FileWriter(f));
pw.print("Hello world!\n");
pw.close();
2,用InputStreamReader或者FileReader初始化BufferedReader,然后用readLine()方法讀取文件
BufferedReader br=new BufferedReader(new FileReader("file1.txt"));
String rt=br.readLine();//結(jié)尾為null
br.close();
3,用FileWriter初始化PrintWriter,然后用pint或者println方法添加文件
PrintWriter pw=new PrintWriter(new FileWriter("file1.txt"),true);
4,import java.io.*;
File f=new File(request.getRealPath(""),"file1.txt");
boolean f.exists();
f.delete();f.createNewFile();

File d=new File(request.getRealPath(""));
boolean d.exists();
d.delete();d.mkdir();

request.getRealPath("url");//虛擬目錄映射為實(shí)際目錄
request.getRealPath("./");//網(wǎng)頁所在的目錄
request.getRealPath("../");//網(wǎng)頁所在目錄的上一層目錄

File f=new File("path","file1.txt");
f.getName();
f.isFile();
f.isDirectory();
f.canRead();
f.canWrite();
f.isHidden();
f.lastModified;
f.createNewFile();
f.length();

File d=new File("path");
File list[]=d.listFiles();//list是一個(gè)File數(shù)組
for(int i=0;i<list.length;i++)out.println(list[i].getName());

FileReader fr=new FileReader("path"+"\\file1.txt");
if(fr.read()==-1)//空文件
fr.close();
fr.read(int i)//讀取i個(gè)字符,-1如果不再有數(shù)據(jù)
//用BufferedReader可以一次讀取一行數(shù)據(jù)
fr.skip(int i);//略過i個(gè)字符


在引用parseInt等函數(shù)的時(shí)候,出錯(cuò)是NumberFormatException等
Random獲得隨機(jī)數(shù),
Random rd=new Random((new Date()).getTime());
int p=Math.abs(rd.nextInt())%s;//s為0到的范圍

四,URL重組、表單隱藏域Cookie

1,這些是用來彌補(bǔ)HTTP協(xié)議無狀態(tài)特征的技術(shù)(Sessions技術(shù))的一部分
2,URL重組是用Get方法向服務(wù)器發(fā)送的信息“?param1=value1&param2=value2&...&paramn=valuen”
如果服務(wù)器已經(jīng)在超鏈接上面作了session標(biāo)記,那么客戶端通過這個(gè)走超鏈接發(fā)送請(qǐng)來時(shí)就會(huì)包含此標(biāo)記
3,form中的<input type=hidden name="key1" value="value1" />也可以像URL重組那樣使用。
4,Cookie對(duì)象
Cookie c=new Cookie("key", "value");
response.addCookie(c);

Cookie[] c=request.getCookies();
c.setMaxAge(int k);//k以秒為單位
一般瀏覽器能放20個(gè)Cookie

五,session對(duì)象

1,session對(duì)象不僅僅能放String數(shù)據(jù),還能放復(fù)雜的對(duì)象。
2,session.putValue("key1",Object1);
Object o=session.getValue("key1");

六,處理JSP中的中文問題

1,ASCII碼
8bit存儲(chǔ),0~31和127是控制字符,32~126是可見字符。
2,GB2312
兩個(gè)8bit表示。前一個(gè)127~255,以區(qū)分ASCII碼。
3,Unicode
可以將世界上幾十種文字編碼統(tǒng)一在同一種編碼機(jī)制下。以16bit為單位存儲(chǔ)。0x0000~0xffff
4,ISO-8859-1 或稱為Latin-1,8859-1。在Unicode所占的值域?yàn)?~255,低位為ASCII擴(kuò)展到0~255,然后在高位補(bǔ)上0x00,組成16bit(此處不太懂)。
5,字節(jié)和unicode Java內(nèi)核是unicode,class文件也是。但是流卻是采用的byte方式。char為unicode方式,byte是字節(jié)方式。轉(zhuǎn)換函數(shù):sun.io里面:
public static ByteToCharConverter getDefault();//獲取系統(tǒng)使用的編碼方式。
public static ByteToCharConverter getConverter(String encoding);
ByteToCharConverter c=New ByteToCharConverter(["encoding"]);
Byte[] s=c.convertAll(Char[] d);
也可以 Char[] d=c.converterAll(Byte[] s);
6,一些函數(shù):
Integer.toHexString(int i);
String s;s.getBytes();
String(byte[]);String(byte[],encoding);//constructors
//關(guān)于Unicode編碼打算單獨(dú)寫一篇

七,獲取JVM屬性值

Properties props=System.getProperties();
Enumeration enum=props.propertyNames(); //key枚舉
key=(String)enum.nextElement();
String s=(String)props.getProperty(key);

八,JSP錯(cuò)誤處理

1,所有可被throw和catch的Exception對(duì)象都繼承自Throwable。Exception應(yīng)該被catch才對(duì);Error對(duì)象也是繼承自Throwable,只是不應(yīng)該catch,而的結(jié)束程序。
2,catch序列針對(duì)的Exception應(yīng)該從低級(jí)到高級(jí)才對(duì)。
3,轉(zhuǎn)譯錯(cuò)誤和客戶端端請(qǐng)求錯(cuò)誤。jsp源程序錯(cuò)誤、import路徑不正確等會(huì)在生成Servlet Class文檔時(shí)產(chǎn)生轉(zhuǎn)譯錯(cuò)誤(500)。在執(zhí)行Servlet Class時(shí)客戶端請(qǐng)求錯(cuò)誤會(huì)被catch。
4,錯(cuò)誤產(chǎn)生時(shí),可以jsp:forward來控制,但更好是用errorPage來處理。也可以throw new Exception("errMsg")。

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=601253



]]>
關(guān)于JSP文件路徑問題 (轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/06/16/53301.htmlliaojiyongliaojiyongFri, 16 Jun 2006 06:45:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/06/16/53301.htmlhttp://www.aygfsteel.com/liaojiyong/comments/53301.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/06/16/53301.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/53301.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/53301.html<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>文件的建立、檢查與刪除</title>
</head>
<body>
<%
String path=request.getRealPath("");
//out.println(path);
File f=new File(path,"File.txt");
//out.println(f);
//out.println(f.exists());

if(f.exists()){//檢查File.txt是否存在
f.delete();//刪除File.txt文件
out.println(path + "\\File.txt 存在,已刪除。");
}else{
f.createNewFile();//在當(dāng)前目錄下建立一個(gè)名為File.txt的文件
out.println(path + "\\File.txt 不存在,已建立。");//輸出目前所在的目錄路徑
}
%>

目錄的建立/檢查與刪除
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>目錄的建立/檢查與刪除</title>
</head>
<body>
<%
String path=request.getRealPath("");
path=path + "\\Sub";//將要建立的目錄路徑
File d=new File(path);//建立代表Sub目錄的File對(duì)象,并得到它的一個(gè)引用
if(d.exists()){//檢查Sub目錄是否存在
d.delete();
out.println("Sub目錄存在,已刪除");
}else{
d.mkdir();//建立Sub目錄
out.println("Sub目錄不存在,已建立");
}
%>
</body>
</html>


如何在JSP中處理虛擬目錄
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>JSP中如何處理虛擬目錄</title>
</head>
<body>
取得虛擬目錄對(duì)應(yīng)的磁盤路徑<br>
Web站點(diǎn)主目錄的位置為<font color=#ff0000><%=request.getRealPath("/")%></font><br>
JSP網(wǎng)頁所在的目錄位置<font color=#ff0000><%=request.getRealPath("./")%></font><br>
JSP網(wǎng)頁所在目錄上一層目錄的位置<font color=#ff0000><%=request.getRealPath("../")%></font><br>
</body>
</html>


文件屬性的取得
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date,java.io.*"%>
<html>
<head>
<title>文件屬性的取得</title>
</head>
<body>
<%
String path=request.getRealPath("/");
File f=new File(path,"ReadData.txt");
if(f.exists()){
%>
<%=f.getName()%>的屬性如下:<br><br>
文件長度為:<%=f.length()%>
<%=f.isFile()?"是文件":"不是文件"%><br>
<%=f.isDirectory()?"是目錄":"不是目錄"%><br>
<%=f.canRead()?"可讀取":"不可讀取"%><br>
<%=f.canWrite()?"可寫入":"不可寫入"%><br>
<%=f.isHidden()?"是隱藏文件":"不是隱藏文件"%><br>
文件的最后修改日期為:<%=new Date(f.lastModified())%><br>
<%
}else{
f.createNewFile();//在當(dāng)前目錄下建立一個(gè)名為ReaData.txt的文件
%>
<%=f.getName()%>的屬性如下:<br><br>
文件長度為:<%=f.length()%>
<%=f.isFile()?"是文件":"不是文件"%><br>
<%=f.isDirectory()?"是目錄":"不是目錄"%><br>
<%=f.canRead()?"可讀取":"不可讀取"%><br>
<%=f.canWrite()?"可寫入":"不可寫入"%><br>
<%=f.isHidden()?"是隱藏文件":"不是隱藏文件"%><br>
文件的最后修改日期為:<%=new Date(f.lastModified())%><br>
<%
}
%>
</body>
</html>


取出目錄中文件的方法
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>取出目錄中文件的方法--列出目錄中的文件</title>
</head>
<body>
<%
String path=request.getRealPath("/");
File d=new File(path);//建立當(dāng)前目錄中文件的File對(duì)象
File list[]=d.listFiles();//取得代表目錄中所有文件的File對(duì)象數(shù)組
out.println("<font color=#ff0000>" + path + "目錄下的文件:</font><br>");
for(int i=0;i<list.length;i++){
if(list<I>.isFile()){
out.println(list<I>.getName() + "<br>");
}
}
out.println("<br><font color=#ff0000>" + path + "目錄下的目錄:</font><br>");
for(int i=0;i<list.length;i++){
if(list<I>.isDirectory()){
out.println(list<I>.getName() + "<br>");
}
}
%>
</body>
</html>


判斷是否為空白文件
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>判斷是否為空白文件</title>
</head>
<body>
<%
String path=request.getRealPath("/");
out.println(path);
FileReader fr=new FileReader(path + "\\AtEnd.txt");//建立FileReader對(duì)象,并實(shí)例化為fr
//對(duì)FileReader類生成的對(duì)象使用read()方法,可以從字符流中讀取下一個(gè)字符。
if(fr.read()==-1)//判斷是否已讀到文件的結(jié)尾
{
out.print("AtEnd.txt文件中沒有數(shù)據(jù)<br>");
}else{
out.println("AtEnd.txt文件中有數(shù)據(jù)");
}
fr.close();
%>
</body>
</html>


讀取所有的文件數(shù)據(jù)
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*,java.lang.*"%>
<html>
<head>
<title>讀取所有的文件數(shù)據(jù)</title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileReader fr=new FileReader(path + "\\ReadData.txt");
//關(guān)鍵在于讀取過程中,要判斷所讀取的字符是否已經(jīng)到了文件的末尾,并且這個(gè)字符是不是文件中的斷行符,即判斷該字符值是否為13。
int c=fr.read();//從文件中讀取一個(gè)字符
//判斷是否已讀到文件結(jié)尾
while(c!=-1){
out.print((char)c);//輸出讀到的數(shù)據(jù)
c=fr.read();//從文件中繼續(xù)讀取數(shù)據(jù)
if(c==13){//判斷是否為斷行字符
out.print("<br>");//輸出分行標(biāo)簽
fr.skip(1);//略過一個(gè)字符
//c=fr.read();//讀取一個(gè)字符
}
}
fr.close();
%>
</body>
</html> 一行一行讀取數(shù)據(jù)
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>文件讀取</title>
</head>
<body>
<%
String path=request.getRealPath("");//取得當(dāng)前目錄的路徑
FileReader fr=new FileReader(path + "\\file\\inc\\t.txt");//建立FileReader對(duì)象,并實(shí)例化為fr
BufferedReader br=new BufferedReader(fr);//建立BufferedReader對(duì)象,并實(shí)例化為br
String Line=br.readLine();//從文件讀取一行字符串
//判斷讀取到的字符串是否不為空
while(Line!=null){
out.println(Line + "<br>");//輸出從文件中讀取的數(shù)據(jù)
Line=br.readLine();//從文件中繼續(xù)讀取一行數(shù)據(jù)
}
br.close();//關(guān)閉BufferedReader對(duì)象
fr.close();//關(guān)閉文件
%>
</body>
</html>


略過文件中的字符不讀取
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>略過字節(jié)不讀取</title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileReader fr=new FileReader(path + "\\ReadData.txt");
fr.skip(2);//跳過2個(gè)字節(jié)
int c=fr.read();//讀取一個(gè)字節(jié)
while(c!=-1){
out.print((char)c);
c=fr.read();
}
fr.close();
%>
</body>
</html>


將數(shù)據(jù)寫入文件
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>將數(shù)據(jù)寫入文件</title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileWriter fw=new FileWriter(path + "\\WriteData.txt");//建立FileWriter對(duì)象,并實(shí)例化fw
//將字符串寫入文件
fw.write("大家好!");
fw.write("本書是《JSP編程技巧》");
fw.write("請(qǐng)多多指教!");
fw.write("email:stride@sina.com");
fw.close();

FileReader fr=new FileReader(path + "\\WriteData.txt");
BufferedReader br=new BufferedReader(fr);//建立BufferedReader對(duì)象,并實(shí)例化為br
String Line=br.readLine();
//讀取一行數(shù)據(jù)
out.println(Line + "<br>");
br.close();//關(guān)閉BufferedReader對(duì)象
fr.close();
%>
</body>
</html>


將寫入文件的數(shù)據(jù)分行
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>將寫入文件的數(shù)據(jù)分行</title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileWriter fw=new FileWriter(path + "\\WriteData.txt");
BufferedWriter bw=new BufferedWriter(fw);
bw.write("大家好!");
bw.write("本書是《JSP編程技巧》。");
bw.newLine();//斷行
bw.write("請(qǐng)多多指教!");
bw.newLine();//斷行
bw.write("email: stride@sina.com");
bw.flush();//將數(shù)據(jù)更新至文件
fw.close();//關(guān)閉文件流
out.println("寫入文件內(nèi)容為:<br>");
FileReader fr=new FileReader(path + "\\WriteData.txt");
BufferedReader br=new BufferedReader(fr);
String Line=br.readLine();//讀取一行數(shù)據(jù)
while(Line!=null){
out.println(Line + "<br>");
Line=br.readLine();
}
fr.close();
%>
</body>
</html>
如何將數(shù)據(jù)追加寫入到文件
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>將寫入文件的數(shù)據(jù)分行</title>
</head>
<body>
<%
String path=request.getRealPath(".");
RandomAccessFile rf=new RandomAccessFile(path + "\\WriteData.txt","rw");//定義一個(gè)類RandomAccessFile的對(duì)象,并實(shí)例化
rf.seek(rf.length());//將指針移動(dòng)到文件末尾
rf.writeBytes("\nAppend a line to the file!");
rf.close();//關(guān)閉文件流
out.println("寫入文件內(nèi)容為:<br>");
FileReader fr=new FileReader(path + "\\WriteData.txt");
BufferedReader br=new BufferedReader(fr);//讀取文件的BufferedRead對(duì)象
String Line=br.readLine();
while(Line!=null){
out.println(Line + "<br>");
Line=br.readLine();
}
fr.close();//關(guān)閉文件
%>
</body>
</html></I></I></I></I>



]]>
JSP內(nèi)建對(duì)象http://www.aygfsteel.com/liaojiyong/archive/2006/05/24/47876.htmlliaojiyongliaojiyongWed, 24 May 2006 11:24:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/05/24/47876.htmlhttp://www.aygfsteel.com/liaojiyong/comments/47876.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/05/24/47876.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/47876.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/47876.html① out - javax.servlet.jsp.jspWriter
   out對(duì)象用于把結(jié)果輸出到網(wǎng)頁上。

方法:
1. void clear() ;
   清除輸出緩沖區(qū)的內(nèi)容,但是不輸出到客戶端。

2. void clearBuffer() ;
   清除輸出緩沖區(qū)的內(nèi)容,并輸出到客戶端。

3. void close() ;
   關(guān)閉輸出流,清除所有內(nèi)容。

4. void flush() ;
   輸出緩沖區(qū)里面的數(shù)據(jù)。

5. int getBufferSize() ;
   獲取以kb為單位的目前緩沖區(qū)大小。

6. int getRemaining() ;
   獲取以kb為單位的緩沖區(qū)中未被占用的空間大小。

7. boolean isAutoFlush() ;
   是否自動(dòng)刷新緩沖區(qū)。

8. void newLine() ;
   輸出一個(gè)換行字符。

9. void print( boolean b ) ;
   void print( char c ) ;
   void print( char[] s ) ;
   void print( double d ) ;
   void print( float f ) ;
   void print( int i ) ;
   void print( long l ) ;
   void print( Object obj ) ;
   void print( String s ) ;
   將指定類型的數(shù)據(jù)輸出到Http流,不換行。

10. void println( boolean b ) ;
    void println( char c ) ;
    void println( char[] s ) ;
    void println( double d ) ;
    void println( float f ) ;
    void println( int i ) ;
    void println( long l ) ;
    void println( Object obj ) ;
    void println( String s ) ;
    將指定類型的數(shù)據(jù)輸出到Http流,并輸出一個(gè)換行符。
   
11. Appendable append( char c ) ;
    Appendable append( CharSequence cxq, int start, int end ) ;
    Appendable append( CharSequence cxq ) ;
    將一個(gè)字符或者實(shí)現(xiàn)了CharSequence接口的對(duì)象添加到輸出流的后面。

成員:
int DEFAULT_BUFFER = 0    - 缺省緩沖區(qū)大小
int NO_BUFFER = -1        - writer是否處于緩沖輸出狀態(tài)
int UNBOUNDED_BUFFER = -2 - 是否限制緩沖區(qū)大小


② request - javax.servlet.http.HttpServletRequest
   request對(duì)象包含所有請(qǐng)求的信息,如請(qǐng)求的來源、標(biāo)頭、cookies和請(qǐng)求相關(guān)的參數(shù)值等。

方法:
1. Object getAttribute( String name ) ;
   返回由name指定的屬性值,該屬性不存在時(shí)返回null。

2. Enumeration getAttributeNames() ;
   返回request對(duì)象的所有屬性名稱的集合。

3. String getAuthType() ;
   返回用來保護(hù)servlet的認(rèn)證方法的名稱,未受保護(hù)時(shí)返回null。

4. String getCharacterEncoding() ;
   返回請(qǐng)求中的字符編碼方法,可以在response對(duì)象中設(shè)置。

5. int getContentLength() ;
   返回請(qǐng)求的BODY的長度,不能確定長度時(shí)返回-1。可以在response中設(shè)置。

6. String getContentType() ;
   返回在response中定義的內(nèi)容類型。

7. String getContentPath() ;
   返回請(qǐng)求的路徑。

8. Cookie[] getCookies() ;
   返回客戶端所有的Cookie的數(shù)組。

9. Enumeration getHeaderNames() ;
   返回所有HTTP頭的名稱的集合。

10. Enumeration getHeaders( String name ) ;
    返回指定HTTP頭的所有值的集合。

11. String getHeader( String name ) ;
    返回指定名稱的HTTP頭的信息。

12. long getDateHeader( String name ) ;
    返回指定名稱的Data類型的HTTP頭的信息。

13. int getIntHeader( String name ) ;
    返回指定名稱的Int類型的HTTP頭的信息。

14. ServletInputStream getInputStream() ;
    返回請(qǐng)求的輸入流。

15. Locale getLocale() ;
    返回當(dāng)前頁的Locale對(duì)象,可以在response中設(shè)定。

16. Enumeration getLocales() ;
    返回請(qǐng)求中所有的Locale對(duì)象的集合。

17. String getLocalName() ;
    獲取響應(yīng)請(qǐng)求的服務(wù)器端主機(jī)名。

18. String getLocalAddr() ;
    獲取響應(yīng)請(qǐng)求的服務(wù)器端地址。

19. int getLocalPort() ;
    獲取響應(yīng)請(qǐng)求的服務(wù)器端端口

20. String getMethod() ;
    獲取客戶端向服務(wù)器端發(fā)送請(qǐng)求的方法(GET、POST)。

21. String getParameter( String name ) ;
    獲取客戶端發(fā)送給服務(wù)器端的參數(shù)值。

22. Map getParameterMap() ;
    該方法返回包含請(qǐng)求中所有參數(shù)的一個(gè)Map對(duì)象。

23. Enumeration getParameterNames() ;
    返回請(qǐng)求中所有參數(shù)的集合。

24. String[] getParameterValues( String name ) ;
    獲得請(qǐng)求中指定參數(shù)的所有值。

25. String getQueryString() ;
    返回get方法傳遞的參數(shù)字符串,該方法不分解出單獨(dú)的參數(shù)。

26. String getPathInfo() ;
    取出請(qǐng)求中處于ServletPath和QueryString之間的額外信息。

27. String getPathTranslated() ;
    返回用getPathInfo()方法取得的路徑信息的實(shí)際路徑。

28. String getProtocol() ;
    返回請(qǐng)求使用的協(xié)議。可以是HTTP1.1或者HTTP1.0。

29. BufferedReader getReader() ;
    返回請(qǐng)求的輸入流對(duì)應(yīng)的Reader對(duì)象,該方法和getInputStream()方法在一個(gè)頁面中只能調(diào)用一個(gè)。

30. String getRemoteAddr() ;
    獲取發(fā)出請(qǐng)求的客戶端IP地址。

31. String getRemoteHost() ;
    獲取發(fā)出請(qǐng)求的客戶端主機(jī)名

32. String getRemoteUser() ;
    返回經(jīng)過客戶端驗(yàn)證的用戶名,未經(jīng)驗(yàn)證返回null。

33. int getRemotePort() ;
    返回發(fā)出請(qǐng)求的客戶端主機(jī)端口。

34. String getRealPath( String path ) ;
    返回給定虛擬路徑的物理路徑。

35. RequestDispatcher getRequestDispatcher( String path ) ;
    按給定的路徑生成資源轉(zhuǎn)向處理適配器對(duì)象。

36. String getRequestedSessionId() ;
    返回請(qǐng)求的session的標(biāo)識(shí)。

37. String RequestURI() ;
    返回發(fā)出請(qǐng)求的客戶端地址,但是不包括請(qǐng)求的參數(shù)字符串。

38. StringBuffer getRequestURI() ;
    返回響應(yīng)請(qǐng)求的服務(wù)器端地址

39. String getScheme() ;
    獲取協(xié)議名稱,缺省值為HTTP協(xié)議。

40. String getServerName() ;
    返回響應(yīng)請(qǐng)求的服務(wù)器名稱。

41. String getServletPath() ;
    獲取客戶端所請(qǐng)求的腳本文件的文件路徑。

42. int getServerPort() ;
    獲取響應(yīng)請(qǐng)求的服務(wù)器端主機(jī)端口號(hào)。

43. void removeAttribute( String name ) ;
    在屬性列表中刪除指定名稱的屬性。

44. void setAttribute( String name, Object value ) ;
    在屬性列表中添加/刪除指定的屬性。

45. void setCharacterEncoding( String name ) ;
    設(shè)置請(qǐng)求的字符編碼格式。

46. HttpSession getSession() ;
    HttpSession getSession( boolean create ) ;
    獲取session,如果create為true,在無session的情況下創(chuàng)建一個(gè)。
   
47. boolean isRequestedSessionIdFromCookie() ;
    檢查請(qǐng)求的會(huì)話ID是否為通過Cookie傳入。

48. boolean isRequestedSessionIdFromURL() ;
    檢查請(qǐng)求的會(huì)話ID是否為通過URL傳入。

49. boolean isRequestedSessionIdValid() ;
    檢查請(qǐng)求的會(huì)話ID是否仍然有效。

50. boolean isSecure() ;
    檢查請(qǐng)求是否使用安全鏈接,如果HTTPS等。

51. boolean isUserInRole( String role ) ;
    檢查已經(jīng)通過驗(yàn)證的用戶是否在是role所指定的角色。

52. Principal getUserPrincipal() ;
    返回包含用戶登陸名的一個(gè)java.security.Principal對(duì)象。

成員:
String BASIC_AUTH = "BASIC"             -
String CLIENT_CERT_AUTH = "CLIENT_CERT" -
String DIGEST_AUTH = "DIGEST"           -
String FORM_AUTH = "FORM"               -


③ response - javax.servlet.http.HttpServletResponse
   response對(duì)象主要將JSP容器處理后的結(jié)果傳回到客戶端。

方法:
1. void addCookie( Cookie cookie ) ;
   添加一個(gè)Cookie對(duì)象,保存客戶端信息。

2. void addDateHeader( String name, long value ) ;
   添加一個(gè)日期類型的HTTP頭信息,覆蓋同名的HTTP頭信息。

3. void addHeader( String name, String value ) ;
   添加一個(gè)HTTP頭,覆蓋同名的舊HTTP頭。

4. void addIntHeader( String name, int value ) ;
   添加一個(gè)整型的HTTP頭,覆蓋同名的舊HTTP頭。

5. boolean containsHeader( String name ) ;
   判斷指定的HTTP頭是否存在。

6. String encodeRedirectURL( String url ) ;
   對(duì)sendRedirect()方法使用的URL進(jìn)行編碼。

7. String encodeURL( String url ) ;
   將URL予以編碼,回傳包含session ID的URL。
  
8. void flushBuffer() ;
   強(qiáng)制把當(dāng)前緩沖區(qū)的內(nèi)容發(fā)送到客戶端。

9. int getBufferSize() ;
   取得以kb為單位的緩沖區(qū)大小。

10. String getCharacterEncoding() ;
    獲取響應(yīng)的字符編碼格式。

11. String getContentType() ;
    獲取響應(yīng)的類型。

12. Locale getLocale() ;
    獲取響應(yīng)的Locale對(duì)象。

13. ServletOutputStream getOutputStream() ;
    返回客戶端的輸出流對(duì)象。

14. PrintWriter getWriter() ;
    獲取輸出流對(duì)應(yīng)的writer對(duì)象。

15. boolean isCommitted() ;
    判斷服務(wù)器端是否已經(jīng)將數(shù)據(jù)輸出到客戶端。

16. void reset() ;
    清空buffer中的所有內(nèi)容。

17. void resetBuffer() ;
    情況buffer中所有的內(nèi)容,但是保留HTTP頭和狀態(tài)信息。

18. void sendError( int xc, String msg ) ;
    void sendError( int xc ) ;
    發(fā)送錯(cuò)誤,包括狀態(tài)碼和錯(cuò)誤信息。

19. void sendRedirect( String locationg ) ;
    把響應(yīng)發(fā)送到另外一個(gè)位置進(jìn)行處理。

20. void setBufferSize( int size ) ;
    設(shè)置以kb為單位的緩沖區(qū)大小。

21. void setCharacterEncoding( String charset ) ;
    設(shè)置響應(yīng)使用的字符編碼格式。

22. void setContentLength( int length ) ;
    設(shè)置響應(yīng)的BODY長度。

23. void setContentType( String type ) ;
    設(shè)置響應(yīng)的類型。

24. void setDateHeader( String name, long value ) ;
    設(shè)置指定名稱的Data類型的HTTP頭的值。

25. void setHeader( String name, String value ) ;
    設(shè)置指定名稱的HTTP頭的值。

26. void setIntHeader( String name, int value ) ;
    設(shè)置指定名稱的int類型的HTTP頭的值。

27. void setStatus( int xc ) ;
    設(shè)置響應(yīng)狀態(tài)碼,新值會(huì)覆蓋當(dāng)前值。

成員(HTTP狀態(tài)碼):
int SC_CONTINUE = 100                      int SC_SWITCHING_PROTOCOLS = 101
int SC_OK = 200                            int SC_NON_AUTHORITATIVE_INFORMATION = 203
int SC_ACCEPTED = 202                      int SC_CREATED = 201
int SC_NO_CONTENT = 204                    int SC_RESET_CONTENT = 205
int SC_PARTIAL_CONTENT = 206               int SC_MULTIPLE_CHOICES = 300
int SC_MOVED_PERMANENTLY = 301             int SC_MOVED_TEMPORARILY = 302
int SC_FOUND = 302                         int SC_SEE_OTHER = 303
int SC_NOT_MODIFIED = 304                  int SC_USE_PROXY = 305
int SC_TEMPORARY_REDIRECT = 307            int SC_BAD_REQUEST = 400
int SC_UNAUTHORIZED = 401                  int SC_PAYMENT_REQUIRED = 402
int SC_FORBIDDEN = 403                     int SC_NOT_FOUND = 404
int SC_METHOD_NOT_ALLOWED = 405            int SC_NOT_ACCEPTABLE = 406
int SC_PROXY_AUTHENTICATION_REQUIRED = 407 int SC_REQUEST_TIMEOUT = 408
int SC_CONFLICT = 409                      int SC_GONE = 410
int SC_LENGTH_REQUIRED = 411               int SC_PRECONDITION_FAILED = 412
int SC_REQUEST_ENTITY_TOO_LARGE = 413      int SC_REQUEST_URI_TOO_LONG = 414
int SC_UNSUPPORTED_MEDIA_TYPE = 415        int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416
int SC_EXPECTATION_FAILED = 417            int SC_INTERNAL_SERVER_ERROR = 500
int SC_NOT_IMPLEMENTED = 501               int SC_BAD_GATEWAY = 502
int SC_SERVICE_UNAVAILABLE = 503           int SC_GATEWAY_TIMEOUT = 504
int SC_HTTP_VERSION_NOT_SUPPORTED = 505


④ session - javax.servlet.http.HttpSession
   session對(duì)象表示目前個(gè)別用戶的會(huì)話狀態(tài),用來識(shí)別每個(gè)用戶。

方法:
1. Object getAttribute( String name ) ;
   獲取與指定名字相關(guān)聯(lián)的session屬性值。

2. Enumeration getAttributeNames() ;
   取得session內(nèi)所有屬性的集合。

3. long getCreationTime() ;
   返回session的創(chuàng)建時(shí)間,最小單位千分之一秒。

4. String getId() ;
   取得session標(biāo)識(shí)。

5. long getLastAccessedTime() ;
   返回與當(dāng)前session相關(guān)的客戶端最后一次訪問的時(shí)間,由1970-01-01算起,單位毫秒。

6. int getMaxInactiveInterval( int interval ) ;
   返回總時(shí)間,以秒為單位,表示session的有效時(shí)間(session不活動(dòng)時(shí)間)。-1為永不過期。

7. ServletContext getServletContext() ;
   返回一個(gè)該JSP頁面對(duì)應(yīng)的ServletContext對(duì)象實(shí)例。

8. HttpSessionContext getSessionContext() ;
  

9. Object getValue( String name ) ;
   取得指定名稱的session變量值,不推薦使用。

10. String[] getValueNames() ;
    取得所有session變量的名稱的集合,不推薦使用。

11. void invalidate() ;
    銷毀這個(gè)session對(duì)象。

12. boolean isNew() ;
    判斷一個(gè)session是否由服務(wù)器產(chǎn)生,但是客戶端并沒有使用。

13. void pubValue( String name, Object value ) ;
    添加一個(gè)session變量,不推薦使用。

14. void removeValue( String name ) ;
    移除一個(gè)session變量的值,不推薦使用。

15. void setAttribute( String name, String value ) ;
    設(shè)置指定名稱的session屬性值。

16. void setMaxInactiveInterval( int interval ) ;
    設(shè)置session的有效期。

17. void removeAttribute( String name ) ;
    移除指定名稱的session屬性。


⑤ pageContext - javax.servlet.jsp.PageContext
   pageContext對(duì)象存儲(chǔ)本JSP頁面相關(guān)信息,如屬性、內(nèi)建對(duì)象等。

方法:
1. void setAttribute( String name, Object value, int scope ) ;
   void setAttribute( String name, Object value ) ;
   在指定的共享范圍內(nèi)設(shè)置屬性。

2. Object getAttribute( String name, int scope ) ;
   Object getAttribute( String name ) ;
   取得指定共享范圍內(nèi)以name為名字的屬性值。

3. Object findAttribute( String name ) ;
   按頁面、請(qǐng)求、會(huì)話和應(yīng)用程序共享范圍搜索已命名的屬性。

4. void removeAttribute( String name, int scope ) ;
   void removeAttribute( String name ) ;
   移除指定名稱和共享范圍的屬性。

5. void forward( String url ) ;
   將頁面導(dǎo)航到指定的URL。

6. Enumeration getAttributeNamesScope( int scope ) ;
   取得指定共享范圍內(nèi)的所有屬性名稱的集合。

7. int getAttributeScope( String name ) ;
   取得指定屬性的共享范圍。

8. ErrorData getErrorDate() ;
   取得頁面的errorData對(duì)象。

9. Exception getException() ;
   取得頁面的exception對(duì)象。

10. ExpressionEvaluator getExpressionEvaluator() ;
    取得頁面的expressionEvaluator對(duì)象。

11. JspWriter getOut() ;
    取得頁面的out對(duì)象。

12. Object getPage() ;
    取得頁面的page對(duì)象。

13. ServletRequest getRequest() ;
    取得頁面的request對(duì)象。

14. ServletResponse getResponse() ;
    取得頁面的response對(duì)象。

15. ServletConfig getConfig() ;
    取得頁面的config對(duì)象。

16. ServletContext getServletContext() ;
    取得頁面的servletContext對(duì)象。

17. HttpSession getSession() ;
    取得頁面的session對(duì)象。

18. VariableResolver getVariableResolver() ;
    取得頁面的variableResolver對(duì)象。

19. void include( String url, boolean flush ) ;
    void include( String url ) ;
    包含其他的資源,并指定是否自動(dòng)刷新。

20. void release() ;
    重置pageContext內(nèi)部狀態(tài),釋放所有內(nèi)部引用。

21. void initialize( Servlet servlet, ServletRequest request, ServletResponse response,
                     String errorPageURL, boolean needSession, int bufferSize, boolean autoFlush ) ;
    初始化未經(jīng)初始化的pageContext對(duì)象。

22. BodyContext pushBody() ;
    BodyContext pushBody( Writer writer ) ;
    保存當(dāng)前的out對(duì)象,并更新pageContext中page范圍內(nèi)的out對(duì)象。

23. JspWrite popBody() ;
    取出由pushBody()方法保存的out對(duì)象。

24. void handlePageException( Exception e ) ;
    void handlePageException( Thrwoable t ) ;
   

成員:
int PAGE_SCOPE = 1        - 頁面共享范圍
int REQUEST_SCOPE = 2     - 請(qǐng)求共享范圍
int SESSION_SCOPE = 3     - 會(huì)話共享范圍
int APPLICATION_SCOPE = 4 - 應(yīng)用程序共享范圍
String PAGE = "javax.servlet.jsp.jspPage"
String PAGECONTEXT = "javax.servlet.jsp.jspPageContext"
String REQUEST = "javax.servlet.jsp.jspRequest"
String RESPONSE = "javax.servlet.jsp.jspResponse"
String CONFIG = "javax.servlet.jsp.jspConfig"
String SESSION = "javax.servlet.jsp.jspSession"
String OUT = "javax.servlet.jsp.jspOut"
String APPLICATION = "javax.servlet.jsp.jspApplication"
String EXCEPTION = "javax.servlet.jsp.jspException"


⑥ application - javax.servlet.ServletContext
   application主要功用在于取得或更改Servlet的設(shè)定。

方法:
1. Object getAttribute( String name ) ;
   返回由name指定的application屬性。

2. Enumeration getAttributes() ;
   返回所有的application屬性。

3. ServletContext getContext( String uripath ) ;
   取得當(dāng)前應(yīng)用的ServletContext對(duì)象。

4. String getInitParameter( String name ) ;
   返回由name指定的application屬性的初始值。

5. Enumeration getInitParameters() ;
   返回所有的application屬性的初始值的集合。

6. int getMajorVersion() ;
   返回servlet容器支持的Servlet API的版本號(hào)。

7. String getMimeType( String file ) ;
   返回指定文件的類型,未知類型返回null。一般為"text/html"和"image/gif"。

8. int getMinorVersion() ;
   返回servlet容器支持的Servlet API的副版本號(hào)。

9. String getRealPath( String path ) ;
   返回給定虛擬路徑所對(duì)應(yīng)物理路徑。

10. RequestDispatcher getNamedDispatcher( String name ) ;
    為指定名字的Servlet對(duì)象返回一個(gè)RequestDispatcher對(duì)象的實(shí)例。

11. RequestDispatcher getRequestDispatcher( String path ) ;
    返回一個(gè)RequestDispatcher對(duì)象的實(shí)例。

12. URL getResource( String path ) ;
    返回指定的資源路徑對(duì)應(yīng)的一個(gè)URL對(duì)象實(shí)例,參數(shù)要以"/"開頭。

13. InputStream getResourceAsStream( String path ) ;
    返回一個(gè)由path指定位置的資源的InputStream對(duì)象實(shí)例。

14. Set getResourcePaths( String path ) ;
    返回存儲(chǔ)在web-app中所有資源路徑的集合。

15. String getServerInfo() ;
    取得應(yīng)用服務(wù)器版本信息。

16. Servlet getServlet( String name ) ;
    在ServletContext中檢索指定名稱的servlet。

17. Enumeration getServlets() ;
    返回ServletContext中所有servlet的集合。

18. String getServletContextName() ;
    返回本web應(yīng)用的名稱。

19. Enumeration getServletContextNames() ;
    返回ServletContext中所有servlet的名稱集合。

20. void log( Exception ex, String msg ) ;
    void log( String msg, Throwable t ) ;
    void log( String msg ) ;
    把指定的信息寫入servlet log文件。

21. void removeAttribute( String name ) ;
    移除指定名稱的application屬性。

22. void setAttribute( String name, Object value ) ;
    設(shè)定指定的application屬性的值。


⑦ config - javax.servlet.ServletConfig
   config對(duì)象用來存放Servlet初始的數(shù)據(jù)結(jié)構(gòu)。

方法:
1. String getInitParameter( String name ) ;
   返回名稱為name的促使參數(shù)的值。

2. Enumeration getInitParameters() ;
   返回這個(gè)JSP所有的促使參數(shù)的名稱集合。

3. ServletContext getContext() ;
   返回執(zhí)行者的servlet上下文。

4. String getServletName() ;
   返回servlet的名稱。


⑧ exception - java.lang.Throwable
   錯(cuò)誤對(duì)象,只有在JSP頁面的page指令中指定isErrorPage="true"后,才可以在本頁面使用exception對(duì)象。

方法:
1. Throwable fillInStackTrace() ;
   將當(dāng)前stack信息記錄到exception對(duì)象中。

2. String getLocalizedMessage() ;
   取得本地語系的錯(cuò)誤提示信息。

3. String getMessage()
   取得錯(cuò)誤提示信息。

4. StackTrackElement[] getStackTrace() ;
   返回對(duì)象中記錄的call stack track信息。

5. Throwable initCause( Throwable cause ) ;
   將另外一個(gè)異常對(duì)象嵌套進(jìn)當(dāng)前異常對(duì)象中。
  
6. Throwable getCause() ;
   取出嵌套在當(dāng)前異常對(duì)象中的異常。

7. void printStackTrace() ;
   void printStackTrace( printStream s ) ;
   void printStackTrace( printWriter s ) ;
   打印出Throwable及其call stack trace信息。

8. void setStackTrace( StackTraceElement[] stackTrace )
   設(shè)置對(duì)象的call stack trace信息。


⑨ page - javax.servlet.jsp.HttpJspPage
   page對(duì)象代表JSP對(duì)象本身,或者說代表編譯后的servlet對(duì)象,
   可以用( (javax.servlet.jsp.HttpJspPage)page )來取用它的方法和屬性。



liaojiyong 2006-05-24 19:24 發(fā)表評(píng)論
]]>
在struts1.1框架下,利用smartupload實(shí)現(xiàn)文件的上傳(可以是多個(gè)文件)(轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47686.htmlliaojiyongliaojiyongTue, 23 May 2006 09:49:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47686.htmlhttp://www.aygfsteel.com/liaojiyong/comments/47686.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47686.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/47686.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/47686.html1、前端頁面upload.jsp,后臺(tái)處理程序UplodAction.java
2、struts.config的配置參數(shù)如下(沒有設(shè)置ActionForm):
<action input="/upload.jsp"? path="/save" scope="request" type="yhp.test.web.UploadAction" validate="false">
????? <forward name="success" path="/list.do" />
??? </action>
3、upload.jsp頁面中主要部分代碼
<%@ page contentType="text/html; charset=GBK"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html:html>
<head>
<title>?測試Struts利用SmartUpload上傳文件 </title>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
</head>
<body>
<html:form action="/save.do" styleId="formItem" method="post"? enctype="multipart/form-data">
<html:hidden property="id"/>
<html:file property="serverpath" styleClass="input-text"></html:file>
</html:form>
</body>
</html:html>
4、UploadAction.java
import com.jspsmart.upload.File;
import com.jspsmart.upload.Files;
import com.jspsmart.upload.SmartUpload;

public ActionForward doBatchsave(ActionMapping actionMapping,
???ActionForm actionForm, HttpServletRequest httpServletRequest,
???HttpServletResponse httpServletResponse) throws Exception {
SmartUpload mySmartUpload = new SmartUpload();
??mySmartUpload.initialize(getServlet().getServletConfig(),httpServletRequest, httpServletResponse);??
??mySmartUpload.upload();
??//獲取除文件以外的相關(guān)信息,例如upload.jsp中隱藏控件id的值
??String strId=(String)mySmartUpload.getRequest().getParameter("id");
??Files files=mySmartUpload.getFiles();
??Collection col=files.getCollection();
??Iterator it=col.iterator();
??while(it.hasNext()){
??? File file=(File)it.next();????
????String oldFileName=file.getFileName();?????
????String extname=file.getFileExt();
????String fileName=Sequence.getSequence()+"."+extname;//產(chǎn)生一個(gè)唯一的文件名
????file.saveAs("c:\\temp\"+fileName);????
??}
??return (actionMapping.findForward("success"));


liaojiyong 2006-05-23 17:49 發(fā)表評(píng)論
]]>
forward,include,redirect 區(qū)別(轉(zhuǎn))http://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47673.htmlliaojiyongliaojiyongTue, 23 May 2006 09:03:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47673.htmlhttp://www.aygfsteel.com/liaojiyong/comments/47673.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47673.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/47673.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/47673.htmlforward,include,redirect是jsp中web頁面(jsp或servelt)的三種不同的路由關(guān)系,三個(gè)貌似相同,其實(shí)還是有許多差別的,而了解這些細(xì)微的差別,在web開發(fā)中是很重要的。
說明:
一、forward、include由javax.servlet.RequestDispatcher來封裝,由包容器container提供RequestDispatcher接口的實(shí)現(xiàn),其中聲明如下:
void forward(ServletRequest req,ServletResponse res)
void include(ServeltRequest req,ServletResponse res)
可以通過兩種方式得到RequestDispatcher:
1、ServletContext.getRequestDispatcher(String path);
其中這里的path必須開始為"/",即這里的path必須相對(duì)于context的root.
2、ServeltRequest.getRequestDispatcher(String path)
這里的path可以為相對(duì)路徑,如果path開始為"/",則也認(rèn)為是從context的root開始的。
二、Redirect由HttpServletResponse.sendRedirect(String location)來支持
差別:
三個(gè)都可以對(duì)用戶的request進(jìn)行轉(zhuǎn)發(fā),但是還是有許多的不同,差別最主要集中在如下幾個(gè)方面:
1、forward與include共亨Request范圍內(nèi)的對(duì)象,而redirect則不行,即:如果一個(gè)javabean被聲明為request范圍的話,則被forward到的資源也可以訪問這個(gè)javabean,而redriect則不行。
2、forward與include基本上都是轉(zhuǎn)發(fā)到context內(nèi)部的資源,而redirect可以重定向到外部的資源,如: req.sendRedriect("http://www.mocuai.com");

Forward功能的實(shí)現(xiàn),這樣
private void setForward(String url,ServletRequest request, ServletResponse response)throws Exception {??
??????? HttpServletRequest hreq = (HttpServletRequest) request;
??????? RequestDispatcher dispatcher =? hreq.getSession().getServletContext().getRequestDispatcher(url);
??????? dispatcher.forward(request,response);
}

liaojiyong 2006-05-23 17:03 發(fā)表評(píng)論
]]>
jsp頁面,以excel的方式輸出http://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47667.htmlliaojiyongliaojiyongTue, 23 May 2006 08:36:00 GMThttp://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47667.htmlhttp://www.aygfsteel.com/liaojiyong/comments/47667.htmlhttp://www.aygfsteel.com/liaojiyong/archive/2006/05/23/47667.html#Feedback0http://www.aygfsteel.com/liaojiyong/comments/commentRss/47667.htmlhttp://www.aygfsteel.com/liaojiyong/services/trackbacks/47667.html在jsp頁面中加入以下的語句,就可以使jsp以excel的形式輸出。
response.setHeader("Content-Type", "application/vnd.ms-excel;charset=GBK");
response.setContentType("application/vnd.ms-excel;charset=GBK");

liaojiyong 2006-05-23 16:36 發(fā)表評(píng)論
]]>
主站蜘蛛池模板: 南和县| 宝山区| 孝昌县| 忻州市| 漠河县| 定兴县| 新安县| 临西县| 湖南省| 花莲县| 喀喇沁旗| 邯郸县| 兖州市| 抚顺县| 龙游县| 亚东县| 普兰县| 萝北县| 京山县| 禹城市| 开阳县| 青川县| 资中县| 成武县| 平阳县| 华安县| 永济市| 庆城县| 监利县| 咸丰县| 凌源市| 瑞丽市| 界首市| 岳西县| 洛浦县| 乌拉特中旗| 漳平市| 徐闻县| 长岭县| 清丰县| 红河县|