Java Tools

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            83 隨筆 :: 0 文章 :: 16 評論 :: 0 Trackbacks

          #

          Sun Microsystems 在 1997 年下半年推出了 Servlet API,將它定位為 CGI 開發人員使用的一種功能強大的工具,這些開發人員正在尋找比 CGI(通用網關接口)編程更高效和輕便的優秀解決方案。但是,開發人員很快就發現 Servlet API 有其自身的缺點,從代碼的可維護性和可擴展性方面來看,該解決方案難以實施。在某種程度上,這種缺點促使團隊開發一種允許在 HTML 中嵌入 Java 代碼的解決方案 — JavaServer Pages (JSP) 因此而出現。

          不久以后,開發人員意識到將表達與商務邏輯混合在一起的復雜 JSP 頁不易于理解和維護。不能編寫 scriplet 的頁面制作人員所面臨的另一個問題是由于標準標記集而帶來的 JSP 限制。這些限制使得難點變成利用 JSP 實施自定義標記的機制來創建 JSP 自定義標記。

          JSP 標準標記庫 (JSTL) 是自定義標記庫的集合,它將許多 JSP 應用程序通用的核心功能封裝為簡單的標記。它不再需要使用 JSP scriptlet
          和表達式,而使用表達式的更高級語法。它還實現了通用目的的功能,如迭代和條件化、數據管理格式化、XML 操作、數據庫訪問、國際化和對本地化信息敏感的格式化標記以及 SQL 標記。JSTL 1.0 推出了 EL 的概念,但只限于 JSTL 標記。在 JSP 2.0 中,您可以使用帶模板文本的 EL,甚至可以通過 javax.servlet.jsp.el 獲得編程方式的訪問。

          在我們了解 JSTL 如何適應環境以及與 JSTL 表達式語言相關的限制以后,我們來看 JSP 2.0 的重要優點之一 — JSP 表達式語言 (EL)。我們將特別涉及到以下內容:

          JSP 表達式語言定義
          在無腳本的 JSP 頁面中支持 EL 的機制
          表達式語言語法
          JSP EL 中有效的表達式
          使用 EL 表達式

          表達式語言的靈感來自于 ECMAScript 和 XPath 表達式語言,它提供了在 JSP 中簡化表達式的方法。它是一種簡單的語言,基于可用的命名空間(PageContext 屬性)、嵌套屬性和對集合、操作符(算術型、關系型和邏輯型)的訪問符、映射到 Java 類中靜態方法的可擴展函數以及一組隱式對象。

          EL 提供了在 JSP 腳本編制元素范圍外使用運行時表達式的功能。腳本編制元素是指頁面中能夠用于在 JSP 文件中嵌入 Java 代碼的元素。它們通常用于對象操作以及執行那些影響所生成內容的計算。JSP 2.0 將 EL 表達式添加為一種腳本編制元素。

          腳本編制元素具有三個從屬形式:

        1. 聲明
        2. Scriptlet
        3. 表達式。

          讓我們來看代碼中的這三種從屬形式:

           

           

          table.getColumn( )

          在將 EL 添加到 JSP 工具包以后,可以使用更簡單的語法來編寫以上的代碼,而獲得與以上 JSP 元素相同的結果。EL 表達式的另一個優勢是,可以在不允許使用上述任何腳本編制元素從屬形式的無腳本的 JSP 頁中使用它。但是必須注意,可以不使用三種腳本編制元素從屬形式中的任一種來編寫 JSP 頁,而對 JSP 頁是否應該為無腳本形式的選擇則完全基于應用程序的需求。如果您希望明確分開表達與商務邏輯,則還可以選擇將頁面強制為無腳本形式。通過強制成為無腳本頁面,必須通過其他元素(如 JavaBean、EL 表達式、自定義操作和標準標記庫)提供 JSP 頁的動態行為。

        4. 有兩種機制可以確保頁面不包含任何腳本編制元素。每種機制還提供在無腳本的 JSP 頁中支持 EL 的方法。

          • 使用頁面指示:

            在使用頁面指示時,您可以通過將 isELEnabled 指示的值相應地設為“true”或“false”,指定是否支持 EL,如下所示:


          • 使用部署描述符的元素:

            當使用部署描述符的元素時,您可以通過在 標記間包含布爾值“true”或“false”,指定是否支持 EL,如下所示:
            ...


            *.jsp
            true
            true


            ....

          JSP 表達式語言允許頁面制作人員使用簡單語法訪問組件,如:

             
          ${expr}

          在以上的語法中,expr 代表有效的表達式。必須注意,該表達式可以與靜態文本混合,還可以與其他表達式結合成更大的表達式。

          有效表達式可以包含文字、操作符、變量(對象引用)和函數調用。我們將分別了解這些有效表達式中的每一種:

          文字

          JSP 表達式語言定義可在表達式中使用的以下文字:

           

          文字 文字的值

          Boolean

          true 和 false

          Integer

          與 Java 類似。可以包含任何正數或負數,例如 24、-45、567

          Floating Point

          與 Java 類似。可以包含任何正的或負的浮點數,例如 -1.8E-45、4.567

          String

          任何由單引號或雙引號限定的字符串。對于單引號、雙引號和反斜杠,使用反斜杠字符作為轉義序列。必須注意,如果在字符串兩端使用雙引號,則單引號不需要轉義。

          Null null

          讓我們來看一些使用文字作為有效表達式的示例:

          ${false} 
          ${3*8)

          操作符

          JSP 表達式語言提供以下操作符,其中大部分是 Java 中常用的操作符:

           

          術語 定義

          算術型

          +、-(二元)、*、/、div、%、mod、-(一元)

          邏輯型

          and、&&、or、||、!、not

          關系型

          ==、eq、!=、ne、、gt、<=、le、>=、ge。可以與其他值進行比較,或與布爾型、字符串型、整型或浮點型文字進行比較。

          空操作符是前綴操作,可用于確定值是否為空。

          條件型 A ?B :C。根據 A 賦值的結果來賦值 B 或 C。

          讓我們來看一些使用操作符作為有效表達式的示例:

          ${ (6 * 5) + 5 } 
          ${empty name}

          隱式對象

          JSP 表達式語言定義了一組隱式對象,其中許多對象在 JSP scriplet 和表達式中可用:

          術語 定義

          pageContext

          JSP 頁的上下文。它可以用于訪問 JSP 隱式對象,如請求、響應、會話、輸出、servletContext 等。例如,${pageContext.response} 為頁面的響應對象賦值。

          此外,還提供幾個隱式對象,允許對以下對象進行簡易訪問:

           

          術語 定義

          param

          將 請求參數名稱映射到單個字符串參數值(通過調用 ServletRequest.getParameter (String name) 獲得)。getParameter (String) 方法返回帶有特定名稱的參數。表達式 $(param.name) 相當于 request.getParameter (name)。

          paramValues

          將 請求參數名稱映射到一個數值數組(通過調用 ServletRequest.getParameter (String name) 獲得)。它與 param 隱式對象非常類似,但它檢索一個字符串數組而不是單個值。表達式 ${paramvalues.name) 相當于 request.getParamterValues(name)。

          header

          將請求頭名稱映射到單個字符串頭值(通過調用 ServletRequest.getHeader(String name) 獲得)。表達式 ${header.name} 相當于 request.getHeader(name)。

          headerValues

          將 請求頭名稱映射到一個數值數組(通過調用 ServletRequest.getHeaders(String) 獲得)。它與頭隱式對象非常類似。表達式 ${headerValues.name} 相當于 request.getHeaderValues(name)。

          cookie 將 cookie 名稱映射到單個 cookie 對象。向服務器發出的客戶端請求可以獲得一個或多個 cookie。表達式 ${cookie.name.value} 返回帶有特定名稱的第一個 cookie 值。如果請求包含多個同名的 cookie,則應該使用 ${headerValues.name} 表達式。
          initParam 將上下文初始化參數名稱映射到單個值(通過調用 ServletContext.getInitparameter(String name) 獲得)。

          除了上述兩種類型的隱式對象之外,還有些對象允許訪問多種范圍的變量,如 Web 上下文、會話、請求、頁面:

           

          術語 定義

          pageScope

          將頁面范圍的變量名稱映射到其值。例如,EL 表達式可以使用 ${pageScope.objectName} 訪問一個 JSP 中頁面范圍的對象,還可以使用 ${pageScope.objectName.attributeName} 訪問對象的屬性。

          requestScope

          將 請求范圍的變量名稱映射到其值。該對象允許訪問請求對象的屬性。例如,EL 表達式可以使用 ${requestScope.objectName} 訪問一個 JSP 請求范圍的對象,還可以使用 ${requestScope.objectName.attributeName} 訪問對象的屬性。

          sessionScope

          將會話范圍的變量名稱映射到其值。該對象允許訪問會話對象的屬性。例如:


          $sessionScope.name}

          applicationScope

          將應用程序范圍的變量名稱映射到其值。該隱式對象允許訪問應用程序范圍的對象。

          必須注意,當表達式根據名稱引用這些對象之一時,返回的是相應的對象而不是相應的屬性。例如:即使現有的 pageContext 屬性包含某些其他值,${pageContext} 也返回 PageContext 對象。

           

          EL 表達式可用于兩種情況:

          • 作為標準操作和自定義操作中的屬性值

          • 在 JSP 文件的模板文本中,如 HTML 或非 JSP 元素 — 在這種情況下,模板文本中的表達式被賦值并插入到當前的輸出中。但是,必須注意,如果標記的主體被聲明為與標記相關,則不會對表達式賦值。

          posted @ 2007-07-02 12:54 和田雨 閱讀(669) | 評論 (0)編輯 收藏

          ServletJSP技術是用Java開發服務器端應用的主要技術,是開發商務應用表示端的標準。Java開發者喜歡使用它有多種原因,其一是對于已經熟悉Java語言的開發者來說這個技術容易學習;其二是Java把“一次編寫,到處運行”的理念帶入到Web應用中,實現了“一次編寫,到處實現”。而且更為重要的是,如果遵循一些良好的設計原則的話,就可以把表示和內容相分離,創造出高質量的、可以復用的、易于維護和修改的應用程序。比方說,在HTML文檔中如果嵌入過多的Java代碼(scriptlet),就會導致開發出來的應用非常復雜、難以閱讀、不容易復用,而且對以后的維護和修改也會造成困難。事實上,在CSDN的JSP/Servlet論壇中,經常可以看到一些提問,代碼很長,可以邏輯卻不是很清晰,大量的HTML和Java代碼混雜在一起,讓人看得一頭霧水。這就是隨意開發的弊端。

            如果你已經基本了解JSPServlet的各項技術(最好也開發過一些Web應用),那么我們可以一起探討一下如何開發“好”的應用的一些指導原則。我們首先對ServletJSP技術做一個瀏覽。

            ServletJSP概覽

            早期的動態網頁主要采用CGI(Common Gateway Interface,公共網關接口)技術,你可以使用不同的語言編寫CGI程序,如VB、C/C++Delphi等。雖然CGI技術發展成熟且功能強大,但由于編程困難、效率低下、修改復雜等缺點,所以有逐漸被取代的趨勢。在所有的新技術中,JSP/Servlet具備更高效、更容易編程、功能更強、更安全和具有良好的可移植性,因而被許多人認為是未來最有發展前途的動態網站技術。

            與CGI相似,Servlet支持請求/響應模型。當一個客戶向服務器遞交一個請求時,服務器把請求送給ServletServlet負責處理請求并生成響應,然后送給服務器,再由服務器發送給客戶。與CGI不同的是,Servlet沒有生成新的進程,而是與HTTP Server處于同一進程中。它通過使用線程技術,減小了服務器的開銷。Servlet處理請求的過程是這樣的:當收到來自客戶端的請求后,調用service方法,該方法中Servlet先判斷到來的請求是什么類型的(GET/POST/HEAD…),然后調用相應的處理方法(doGet/doPost/doHead…)并生成響應。

            別看這么復雜,其實簡單說來Servlet就是一個Java類。與一般類的不同之處是,這個類運行在一個Servlet容器內,可以提供session管理和對象生命周期管理。因而當你使用Servlet的時候,你可以得到Java平臺的所有好處,包括安全性管理、使用JDBC訪問數據庫以及跨平臺的能力。而且,Servlet使用線程,因而可以開發出效率更高的Web應用。

            JavaServer Pages (JSP)

            JSP技術是J2EE的一個關鍵技術,它在更高一級的層次上抽象Servlet。它可以讓常規靜態HTML與動態產生的內容相結合,看起來像一個HTML網頁,卻作為Servlet來運行。現在有許多商業應用服務器支持JSP技術,比如BEA WebLogic、IBM WebSphere、 JRun等等。使用JSP比用Servlet更簡單。如果你有一個支持JSP的Web服務器,并且有一個JSP文件,你可以把它放倒任何靜態HTML文件可以放置的位置,不用編譯,不用打包,也不用進行ClassPath的設置,就可以像訪問普通網頁那樣訪問它,服務器會自動幫你做好其他的工作。

            JSP工作原理

            JSP 文件看起來就像一個普通靜態HTML文件,只不過里面包含了一些Java代碼。它使用.jsp的后綴,用來告訴服務器這個文件需要特殊的處理。當我們訪問一個JSP頁面的時候,這個文件首先會被JSP引擎翻譯為一個Java源文件,其實就是一個Servlet,并進行編譯,然后像其他Servlet一樣,由Servlet引擎來處理。Servlet引擎裝載這個類,處理來自客戶的請求,并把結果返回給客戶,如下圖所示:


          圖1: 調用JSP頁面的流程

            以后再有客戶訪問這個頁面的時候,只要該文件沒有發生過更改,JSP引擎就直接調用已經裝載的Servlet。如果已經做過修改的話,那就會再次執行以上過程,翻譯、編譯并裝載。其實這就是所謂的“第一人懲罰”。因為首次訪問的時候要執行一系列以上的過程,所以會耗費一些時間;以后的訪問就不會這樣了。

          開發原則


            這一部分我們列出一些開發原則,重點是JSP頁面。關于如何分離表現和內容的MVC因為要涉及到JSPServlet的整合,我們稍候再談。

            不要在JSP頁面中嵌入過量的Java代碼:對于非常簡單或是測試性的代碼,把所有的Java 代碼直接放入JSP頁面內是沒有問題的。但是這種方法不應該被過度使用,否則就會產生一大堆HTML和Java混合起來的代碼,讓人難以閱讀和理解。解決方法是寫一個單獨的類,用來執行相關的計算。一旦這個類測試通過,就可以把它放在任何執行同樣計算的場合中。這樣可以促進代碼的復用。

            選擇合適的包含(include)機制: 如果一個應用中每個頁面有一樣的抬頭和底部,或者還有導航條,那么就應該把它們放到一個單獨的文件中,然后在每一個頁面中使用包含機制把它們加入到這個頁面中:

          Include 指令: <%@ include file="filename" %>或等效xml語法
          <jsp:directive.includefile=”filename” />

          Include 動作: <jsp:include page="page.jsp" flush="true" />

            Include指令是當JSP頁面翻譯為Servlet的時候包含另外一個文件,Include 動作是當請求時包含另外一個文件的輸出。如果被包含的文件不是經常改動的時候,我建議使用Include 指令,這樣速度更快。如果被包含的文件需要不時改動或者知道請求時才能決定需要包含的內容時,那么應該使用Include 動作。

            如果你使用JSP標準標記庫(JavaServer pages Standard Tag Library即JSTL)的話,那么還有第三中包含機制<c:import>,可以用來包含本地或者遠程的資源。例如:

          <c:import url="./copyright.html"/>
          <c:import url="http://www.somewhere.com/hello.xml"/>

            不要把業務邏輯和表示混合在一起: 復雜的應用涉及大量的代碼,因而把業務邏輯和前端的表示相分離就顯得格外重要,這種分離可以讓任何一方的變化不會影響到另外一方。所以,所有的JSP代碼都應該限制在表示層,可是如果這樣的話,你如何實現你的業務邏輯呢?這就是JavaBean所做的事情。JavaBean技術是一個獨立于平臺的組件模型,它讓開發者編寫、測試通過一個組件后,可以隨處使用,提高了復用性。在JSP技術中,JavaBean實現了業務邏輯部分,它把數據返回給JSP頁面,由JSP頁面負責格式化數據并輸出到客戶端的瀏覽器。在JSP頁面中使用JavaBean組件的好處是:

            產生了可以復用的組件:任何應用都可以使用這些組件

            可以把業務邏輯和表示相分離:你可以修改數據的顯示方式而不用考慮業務邏輯。這樣做的結果也可以明確工作中開發人員的分工,網頁開發人員可以把精力放到如何顯示數據上,Java開發者則更為關注業務邏輯的實現。

            對于JavaBean你不用提供源代碼,這樣你的代碼就不會被瀏覽器網頁的人輕易獲得,可以保護你的勞動成果。

            如果你的應用中使用了EJB組件,那么業務邏輯就應該放置在EJB中,因為EJB模型提供了生命周期管理、事務管理以及多客戶訪問域對象(Entity Beans)。你可以仔細看一下Enterprise BluePrints中的例子,它就是這么做的。

            使用定制的標記: 上面我們已經討論過,把所有Java代碼嵌入到JSP頁面內并不合適,因為網頁開發人員并不一定懂得Java語言,更難以理解Java語法。JavaBean可以封裝很多Java代碼,不過在JSP頁面內使用JavaBean仍然要求頁面開發人員了解一些Java語法。

            JSP技術中包含了定制標記庫的功能。Java開發人員可以生成自己的標記庫,這樣網頁設計人員就可以使用類似HTML的語法來使用這些標記。編寫和使用自己定制的標記庫可以在更大程度上促進業務邏輯和表示的分離。使用定制標記庫主要有以下好處:

            可以消除在JSP頁面中使用scriptlet 標記使用的任何參數都可以通過屬性傳入,從而不需要使用Java代碼就可以達到希望的目的。

            可以簡化使用 網頁設計人員不需要學會使用Java語法,他們可以用類似HTML語法就可以使用標記。
          不懂Java的網頁設計人員可以使用標記庫來完成單獨使用HTML不能完成的任務。

            提高了復用性 標記庫完全可以復用,這可以節省開發和測試的時間。Scriptlet代碼只能在“拷貝粘貼”級別上進行“復用”。

            簡單說來,你可以像用HTML構建表示層一樣使用標記庫完成非常復雜的任務。下面是表頁標記庫的一些注意事項:

            1. 保持簡潔性:如果一個標記需要好幾個屬性的話,那么盡可能把它分為幾個標記。

            2. 保持復用性:同標記的使用人員(網頁設計人員)多多交流,盡量開發出可以高度復用的標記庫。

            3. 不要一切都從頭開始:現在已經有一些可以免費使用的標記庫,比如Jakarta Taglibs。如果你要用到一個標記,先看看是不是已經有現成的可以使用。

            不要“重新發明輪子”,不要一切從頭開始: 通過定制組件可以提高復用性,不過定制組件仍然需要編寫、測試和調試程序。問題是這個事情別人可能已經實現了,而且你的實現方式并不一定比人家做得更好。這就是JSP標準標記庫(JavaServer Pages Standard Tag Library, JSTL)要做的事情(JSTL請參考JSTL官方網站)。JSTL提供了循環、讀屬性、遍歷各種數據結構、條件表達式求值等各種標記。它也提供了一些復雜的標記,甚至像解析XML文檔的標記它都有。所以如果你要用到一個標記的話,最好先看看有沒有別人已經實現的可以使用,而不要次次從頭開始,自己搞一套。

            使用JSTL表達使語言(JSTL Expression Language): 傳遞給JSP頁面的數據一般通過JSP作用域屬性或者請求參數來進行。專門為網頁開發者設計的表達式語言(Expression Language, EL)把使用作用域屬性傳遞信息作為從業務邏輯向JSP頁面傳遞信息的標準方式。這里要注意的是,EL只是JSP技術中關鍵的一個方面,并不是一種通用的程序設計語言。相反,它只是一種數據訪問語言,它可以簡化應用程序的數據的訪問,不用Scriptlet和請求時表達式求值就可以訪問數據。

            在JSP中,網頁設計師要使用表達式語法<%= name %>或JavaBean組件來取得某些變量或屬性的值,例如:

          <tagLib:tag attribute="<%=

          pageContext.getAttribute("name") %>">

            或

          <%= aCustomerBean.getAddress().getCountry() %>

            表達使語言讓網頁設計師可以使用簡化的語法來訪問信息。如果你只是要訪問一個簡單的變量,你可以使用這樣的語法:

          <tagLib:tag attribute="${name}">

            如果你要訪問一個嵌套JavaBean的屬性,你可以這樣:

          <tagLib:tag attribute ="${

          aCustomerBean.address.country}">

            表達式語言(EL)借用了JavaScript 的語法,所以如果你對JavaScript 很熟悉的話,你就會覺得巨爽。

            使用過濾器(filter): 過濾器是一個對象,可以傳輸請求或修改響應。它可以在請求到達Servlet/JSP之前對其進行預處理,而且能夠在響應離開Servlet/JSP之后對其進行后處理。所以如果你有幾個Servlet/JSP需要執行同樣的數據轉換或頁面處理的話,你就可以寫一個過濾器類,然后在部署描述文件(web.xml)中把該過濾器與對應的Servlet/JSP聯系起來。

            創建過濾器其實很容易,你只須實現javax.servlet.Filter接口及它的三個方法:

          public void init(FilterConfig config)

          public void doFilter(ServletRequest req, ServletResponse rep,

          FilterChain chain)

          public void destroy()

            這樣,你就可以完成你的過濾器。

          使用可移植的安全模型:大部分的應用服務器都提供了安全模型,不過一般它們都是針對某一個服務器或某一個廠商專有的。如果你的應用需要移植的話,那么你的應用最好使用可以移植的安全模型。如果你的應用有一些預先定義的固定用戶的話,那么你可以使用FROM驗證和BASIC驗證。可是如果你要動態生成客戶的話(一般都是這種情況),你可能就需要使用服務器特定的API來創建和管理用戶。這樣當你的應用移植到另外一個服務器時,你可能就會碰到API不兼容的問題。這種情況下,最好的解決方法是使用適配器(Adapter)模式(如果你對設計模式不熟悉的話,請參看GoF的《設計模式》一書)。

            用數據庫來保存持久性數據: Servlet/JSP中可以使用HttpSession對象也就是會話對象來保存用戶的臨時數據。不過如果你想保存持久性數據的時候,你應該使用數據庫,數據保存數據會更安全,而且對客戶所用的瀏覽器沒有什么要求。這樣即使你的應用服務器由于某種原因崩潰了,你的數據依然良好。

            高速緩存頁面: 應用程序中總有一些東西是相對固定的,而另外一些東西是經常變化的。你應該使用靜態的HTML文檔來存儲那些相對固定的內容,這樣客戶端就可以進行高速緩存,客戶每次訪問你的應用時,只需訪問已經改動的部分。這樣可以加快客戶的訪問速度。

            使用連接池: 如果你要自己寫數據庫訪問代碼的話,我覺得使用你應該學會如何使用數據庫連接池技術。每一個服務器都有針對數據庫連接池的配置文檔,你要學習一下如何使用。數據庫連接池可以加速你的應用的數據訪問的速度,而且由于服務器替你管理了數據庫連接,這可以節省你的很多工作。

            緩存數據庫的訪問結果: 如果你的應用要對數據庫進行頻繁訪問的話,你可以使用一個對象來緩存你的數據,這樣你就可以節省大量訪問數據庫的開銷。在《J2EE核心模式》和《實用J2EE設計模式編程指南》兩本書中都有關于值對象模式(Value Object Pattern)的詳細探討,你可以參考這兩本書來獲得相應的知識。

            使用數據訪問對象模式:如果你的應用需要訪問多個數據庫系統或者可能會移植到其它的存儲系統中,那么你針對特定廠商的優化代碼就可能會失效。使用通用的代碼存在執行效率的問題,而使用優化代碼又存在移植的問題。所以就產生了數據訪問對象模式(Data Access Object Pattern, DAO),該模式既提供了各數據庫廠商的適應性,又能利用到他們提供的獨特的好處。按照面向對象的分離任務的原則,該模式將與企業信息系統(Enterprise Information System, EIS)通訊需要的邏輯隔離到它自己的類中。這樣,事物對象,如Servlet/JSP組件、JavaBean就可以利用數據訪問對象(DAO)處理所有與EIS有關的事務。

            最好采用JSPXML語法: JSP技術中經常存在著兩種完成同一個任務的語法,一種是常規的JSP語法,一種是對應的XML語法。雖然兩種語法作用相同,你最好還是使用XML語法。存在兩種語法的原因是,JSP語法可以與以前的代碼兼容,而J2EE使用XML作為其交換數據的核心,所以同時提供了XML語法。隨著J2EE的發展,XML的作用會越來越大,所以我建議你使用XML語法。

            研究Sun提供的J2EE BluePrints: Sun的Enterprise BluePrints 提供了大量指導原則、設計模式和很好的例子(寵物店,Pet Store)。你可以好好研究一下這些內容,這樣可以提高你的設計和開發水平。

            整合ServletJSP

            JSP技術規范種給出了兩種使用JSP開發Web應用的方式,這兩種方式可以歸納為模型一和模型二,這兩種模型的主要差別在于它們處理業務的流程不同。模型一,如下圖所示,稱之為JSP+JavaBeans模型。在這一模型中,JSP頁面獨自響應請求并將處理結果返回給客戶,所有的數據通過JavaBean來處理,JSP實現頁面的表現。


          圖2: JSP模型一

            從上圖可以看出,模型一也實現了頁面表現和業務邏輯相分離。然而使用這種方式就要在JSP頁面使用大量的Java代碼,當需要處理的業務邏輯很復雜時,這種情況會變得非常糟糕。大量嵌入式代碼使整個頁面程序變得異常復雜。對于前端界面設計的網頁開發人員來說,這簡直是一場噩夢。所以,模型一不能滿足大型應用的需要,但是對于小型應用,因為該模型簡單,不用涉及諸多要素,從而可以很好地滿足小型應用的需要,所以在簡單應用中,可以考慮模型一。

            模型二,如下圖所示,稱之為JSP+Servlet+JavaBeans模型。這一模型結合了JSPServlet技術,充分利用了JSPServlet兩種技術原有的優勢。這個模型使用JSP技術來表現頁面,使用Servlet技術完成大量的事務處理,使用Bean來存儲數據。Servlet用來處理請求的事務,充當一個控制者的角色,并負責向客戶發送請求。它創建JSP需要的Bean和對象,然后根據用戶請求的行為,決定將哪個JSP頁面發送給客戶。


          圖3: JSP模型二

            從開發的觀點看,模型二具有更清晰的頁面表現,清楚的開發角色的劃分,可以充分利用開發團隊中的網頁設計人員和Java開發人員。這些優勢在大型項目中表現得尤為突出,網頁設計人員可以充分發揮自己的美術和設計才能來充分表現頁面,程序編寫人員可以充分發揮自己的業務邏輯處理思維,實現項目中的業務處理。

            另外,從設計結構來看,這種模型充分體現了模型視圖控制器(MVC)的設計架構。事實上,現存的很多開發框架都是基于這種模型的,充分實現了MVC ,例如Apache Struts框架和JavaServer Faces框架
          posted @ 2007-07-02 12:51 和田雨 閱讀(286) | 評論 (0)編輯 收藏

          最近整理以前寫的東東,發現2004年底的時候對比各類Java反編譯器時記下來的一篇心得,也不知道是不是有點兒過時了,僅供大家參考吧。

          =====================================================================

          JAVA語言是19955月由SUN公司發布的,由于其安全性高、代碼優化、跨平臺等特性,迅速取代了很多傳統高級語言,占據了企業級網絡應用開發等諸多領域的霸主地位。

          不過,JAVA最突出的跨平臺優勢使得它不能被編譯成本地代碼,而要以中間代碼的形式運行在虛擬機環境中,這使得JAVA的反編譯要比別的高級語言容易實現,并且反編譯的代碼經過優化后幾乎可以與源代碼相媲美。

          為了更好地保護知識產權,避免本公司的智力成果輕易被人竊取,開發者有必要對反編譯工具深入了解,以便有針對性地采取保護措施。

          目前,比較流行的JAVA反編譯工具超過30種,其中有三款堪稱精品:

          一、         應用廣泛的JAD

          在眾多的JAVA反編譯工具中,有幾種非常著名的工具使用了相同的核心引擎——JAD,其中主要包括:Front End PlusmDeJavaDecafe ProCavaj Java DecompilerDJ Java DecompilerNMI’s Java Class Viewer和國產的JAVA源代碼反編譯專家等等。

          JAD本身是一個命令行工具,沒有圖形界面,上述的這些工具大多是在JAD內核的基礎之上加了一個圖形界面而已。這么多種產品的共同選擇,足可證明JADJAVA反編譯領域中的尊貴地位。

          筆者用來測試的JAD版本是1.5.8f。

          JAD是使用Microsoft Visual C++開發的,運行速度非常快,可以處理很復雜的JAVA編譯文件。眾多的參數使JAD可以靈活應付多種加密手段,令反編譯的代碼更加優化和易讀。由于JAD參數太多,沒必要一一解釋,其中有幾個最常用的如下:

                   -d

          - 用于指定輸出文件的目錄

           

                   -s - 輸出文件擴展名(默認為: .jad),通常都會把輸出文件擴展名直接指定為.java,以方便修改的重新編譯。

                   -8       - Unicode字符轉換為ANSI字符串,如果輸出字符串是中文的話一定要加上這個參數才能正確顯示。

          最常用的反編譯指令如下所示:

          Jad –d c:\javasource –s .java -8 javatest.class

          這條指令將當前目錄下的javatest.class反編譯為javatest.java并保存在c:\javasource目錄里,其中的提示輸出為中文,而不是Unicode代碼。

          二、         源碼開放的JODE

          JODE是全球最大的開源項目網站Sourceforge.net的成員,不要以為源碼開放就小瞧它,在所有的JAVA反編譯器中,JODE的反編譯效果是最好的,尤其是對付一些常見的加密手段,例如混淆技術等,更是出類拔粹。

          JODE本身也是純JAVA開發的,最近越來越多的JAVA反編譯軟件也選擇JODE來做它們的核心引擎,例如JCavaj Java DecompilerBTJ (Back To Java)jEdit's JavaInsight plugin等。

          JODE是一個可運行的JAR文件,在windows環境下雙擊即可運行。

          需要特別說明的是,JODE不是通過常規的Open->File的方式來加載JAVA編譯后的類文件(*.class)或是類包(*.jar)的,而是通過在Options菜單中的Set Classpath來實現的,單獨的類文件可以將它的上一級目錄作為Classpath輸入,然后再選擇Reload Classpath即可。

            

          新加入的類包或是類的名字會在左側窗口出現,雙擊類包名可以展開目錄樹結構,雙擊需要反編譯的類名則在右上角的窗口中直接顯示反編譯后的源代碼。

           

          三、         獨樹一幟的DAVA

          DAVA不是一個獨立的JAVA反編譯器,而是JAVA代碼優化工具Soot的一部分。SootJODE一樣是純JAVA開發的,也是一個獨立的JAR包,但卻不能通過雙擊直接運行,而是象JAD一樣在命令行狀態運行。

          Soot對環境變量的配置要求非常嚴格,通常情況下要對CLASSPATH做如下設置:

          Set CLASSPATH=%CLASSPATH%;c:\sootdir\sootclasses-2.1.0.jar;.;

          其中的c:\sootdir\是下載的soot類包放置的路徑,CLASSPATH末尾的.;代表了當前目錄,如果不加上這個的話Soot經常會報一個找不到類的錯誤。

                DAVA是作為Soot的一個參數使用的,通常的用法如下:

          Java soot.Main –f dava –d c:\javasource javatest

          注意最后的類名不用帶.class后綴,因為它默認是處理class文件,這個操作與前述的JAD的參數效果相同。

          DAVA采取了流程優化的方式進行反編譯,與傳統反編譯思路不盡相同,但卻對改變流程類的加密方法有獨特的反編譯效果。

           

          上述的三種工具各有千秋,但效果都非常不錯。經測試,它們基本上都可以把JDK自帶的一些例程完全反編譯,然后不加任何修改可再編譯成功,并能正常運行!

          (文中工具均經過本人親手測試,當時用的是jdk1.4.2_03,現在離寫文章的時候過了一年多了,jdk都出到1.5了,怕是有些程序也不太好反編了)

          /*原創作品,轉載請注明出處*/

          posted @ 2007-07-02 12:50 和田雨 閱讀(2478) | 評論 (0)編輯 收藏

               摘要:   Apache Ant Project Ant 眾所周知,Ant(螞蟻)是一套基于java的程序...  閱讀全文
          posted @ 2007-07-02 12:49 和田雨 閱讀(261) | 評論 (0)編輯 收藏

           

          Java的線程調度操作在運行時是與平臺無關的。一個多任務系統需要在任務之間實現QoS(Quality of Service)管理時,如果CPU資源的分配基于Java線程的優先級,那么它在不同平臺上運行時的效果是很難預測的。本文利用協調式多任務模型,提出一個與平臺無關、并且能在任務間動態分配CPU資源的方案。
            現在,由于計算機系統已經從人機交互逐步向機機交互轉化,計算機和計算機之間的業務對于時間的要求非常高。軟件系統對于業務的支持已經不僅表現為對不同業務的邏輯和數據(算法+數據結構)支持,而且還表現為對同時處理不同任務的時效性(任務響應速度)支持。一般,任務響應的速度可以通過算法優化及并行運算分擔負載等手段來提高。但是,用戶業務邏輯的復雜度決定了算法優化的發揮空間,硬件規模決定了所能夠承擔負載的大小。我們利用Java平臺的特點,借鑒協調式多任務思想,使CPU資源能夠在任務間動態分配,從而為時間要求強的任務分配更多的CPU運行資源。這也可以充分利用現有硬件,為用戶業務提供最大的保障。

            用Java解決問題

            本著軟件系統結構和現實系統結構一致的思想,開發復雜業務服務的程序一般按照計算機任務和現實業務對應的思路,最終形成一個大規模的多任務系統。由于其跨平臺性,Java系統可以隨著業務的擴大,平滑地升級到各種硬件平臺上。由于Java自身的發展及其應用場合的不斷擴大,用它實現多任務系統已經成為當前的應用方向。在J2EE(Java2 Enterprise Edition)推出以后,Sun公司已經將Java的重心放在了服務器端(Server Side)系統的構造上。由于客戶/服務器模型固有的多對一的關系,服務器端程序也必然是一個多任務系統。

            在Java多任務應用中,動態地將CPU資源在任務間分配有很重要的意義。比如一個Inte.Net服務商的系統往往有多種任務同時運行,有HTTP、FTP、MAIL等協議的支持,也有商務、娛樂、生活、咨詢等業務的服務。在白天,網站希望系統的CPU資源盡量保障網上用戶的服務質量,提高電子商務等任務的響應速度;晚上則希望讓自己的娛樂服務和資料下載盡可能滿足下班后人們的需要。另外,在新興的網管(比如TMN, Telecommunication Management.Network)等應用領域中,服務程序往往需要支持成千上萬個并發響應事件的被管理對象(MO,Managed Object)。對于被管理對象執行的操作,不同用戶在不同時刻往往有不同的時間要求。

            方案選擇

            在考慮動態分配CPU資源的實施方案時,往往有以下兩點要求:

            1. 須充分利用現有硬件資源,在系統空閑時,讓低優先級任務也能夠得到系統所能給予的最快響應。

            2.當硬件資源超負荷運行時,雖然系統中有大規模、多數量的任務不能處理,但它不應受影響,而能夠順利處理那些能夠被處理的、最重要的高優先級任務。

            多任務系統要用多線程實現的最簡單方法就是將線程和任務一一對應,動態調整線程的優先級,利用線程調度來完成CPU資源在不同任務間動態分配。這種思路在以前使用本地化代碼(Native Code),充分利用特定硬件和操作系統技巧的基礎上是基本可行的。但在跨平臺的Java環境中,這個思路對僅有小規模任務數的簡單系統才可行,原因有以下兩點:

            1. Java的線程雖然在編程角度(API)是與平臺無關的,但它的運行效果卻和不同操作系統平臺密切相關。為了利用更多的CPU資源,Java中的一個線程(Thread)就對應著不同操作系統下的一個真實線程。因為Java虛擬機沒有實現線程的調度,所以這些Java的線程在不同操作系統調度下運行的差異性也就比較明顯。例如在Windows系統中,不僅線程的優先級少于Java API參數規定的十個優先級,而且微軟明確反對程序員動態調整線程優先級。即使在操作系統中有足夠的優先權,讓線程優先級的參數和真實線程的優先級對應,不同操作系統的調度方式也會有許多不同。這最終會造成代碼在不同平臺上的行為變得不可預測。這就很難滿足復雜的、大規模并發任務的眾多優先級需求,從而很難達到用戶業務需要達到的效果。

            2. 由于在Java系統中,線程被包裝在一個Java語言的對象類—Thread中,所以為了完成Java語言對象和操作系統線程的對應,Java線程的系統開銷還是比較大的(在NT 4.0中,平均每個線程大致占用30KB內存)。因此如果讓Thread對象個數和成千上萬的任務數同比例增長,就顯然是不合理的。

            綜上所述,根據并發多任務的大規模需求和Java平臺固有的特點,想要利用Java Thread對象的優先級調整CPU資源的分配是非常困難的,所以應該盡量避免讓線程和任務直接對應,也盡量避免使用操作系統線程優先級的調度機制。

            解決方案

            根據以上分析,問題的癥結在于:多任務系統中的任務在Java語言中的對應以及任務間的相互調度。

            從本質上看,一個任務就是一系列對象方法的調用序列,與Java的Thread對象或者別的類的對象沒有必然聯系。在避免使用不同操作系統線程調度且同時Java虛擬機又沒有線程調度能力的情況下,要想構造一個協調式多任務系統,讓各個任務相互配合就成了最直接的思路。協調式多任務系統一般有以下特點:

            1. 任務由消息驅動,消息的響應代碼完成任務邏輯的處理;

            2. 消息隊列完成消息的存儲和管理,從而利用消息處理的次序體現任務優先級的不同;

            3. 任務中耗時的消息響應邏輯能夠主動放棄CPU資源,讓別的任務執行(像Windows 3.1中的Yield函數、Visual Basic中的DoEvents語句)。

            可能出于巧合,Java語言具有構造協調式多任務系統天然的條件。Java對象的方法不僅是一個函數調用,它還是一個Java.lang.reflect.Method類的對象。而所有對象的方法都可以通過Method類的invoke方法調用。如果能使每個任務所對應的一系列方法全部以對象形式包裝成消息,放到消息隊列中,然后再按照自己的優先級算法將隊列中的消息取出,執行其Method對象的invoke調用,那么一個基本的協調式多任務系統就形成了。其中,任務的優先級和線程的優先級沒有綁定關系。該系統的主體調度函數可以設置成一個“死循環”,按照需要的優先級算法處理消息隊列。對于有多重循環、外設等待等耗時操作的消息響應函數,可以在響應函數內部遞歸調用主體調度函數,這一次調用把原來的“死循環”改成在消息隊列長度減少到一定程度(或者為空)后退出。退出后,函數返回,執行剛才沒有完成的消息響應邏輯,這樣就非常自然地實現了協調式系統中任務主動放棄CPU資源的要求。

            如果僅僅做到這一步,完成一個像Windows 3.1中的多任務系統,實際只用了一個線程,沒有利用Java多線程的特點。應該注意到,雖然Java系統中線程調度與平臺相關,但是相同優先級的線程之間分時運行的特點基本上是不受特定平臺影響的。各個相同優先級的線程共享CPU資源,而線程又被映射成了Java語言中的Thread對象。這些對象就可以被認為是CPU資源的代表。Thread與線程執行代碼主體的接口—Runnable之間是多對一的關系。一個Runnable可以被多個Thread執行。只要將Runnable的執行代碼設置成上述的消息調度函數,并和消息隊列對應上,那么就可以通過控制為它服務的Thread個數來決定消息隊列執行的快慢,并且在運行時可以動態地新增(new)和退出Thread對象。這樣就能任意調整不同消息隊列在執行時所占用CPU資源的多少。至此,任何一個Java調用都可以在Thread個數不同的消息隊列中選擇,并可以調整這些消息隊列服務的Thread個數,從而實現在運行時調整任務所占用的CPU資源。

            縱觀整個方案,由于僅僅基于Java語言固有的Method對象,不同任務間動態分配CPU資源并沒有對任務的性質及其處理流程有任何限制,那么在消息隊列中沒有高優先級消息時,低優先級消息的處理函數自然會全部占用CPU資源。在不同消息隊列處理速度任意設置時,并沒有將特定的消息限制在快的或者慢的消息隊列上。如果系統的負荷超出(比如消息隊列長度超過一定限制),只要將隊列中低優先級消息換出或者拒絕不能處理的消息進入,那么系統的運行就可以基本上不受負荷壓力的影響,從而最大保障用戶的關鍵業務需求。

            當然,協調式多任務的思想也有其局限性,主要就是它的調度粒度比較大。系統能夠保證的粒度是一次消息處理過程。如果消息處理邏輯非常費時,那么編程人員就必須再處理函數內部,讓系統主動讓出CPU資源。這雖然需要在處理消息響應邏輯時增加一個考慮因素,但是,在Windows系統盛行的今天,這是一個已經被普遍接受的思路。由于方案中并沒有局限為消息隊列服務的線程數目,所以一個長時間的消息響應只會影響一個線程,而不會對整個系統產生致命的影響。除了調度粒度的問題以外,還有訪問消息隊列操作在各個線程間互斥的問題。取出消息的過程是串行化的,因此對于這一瓶頸的解決方案就是:假設取出一條消息的操作相對于處理消息的消耗可以忽略不計,那么對于多次調用且僅有兩三行響應邏輯的消息,編程人員通過函數調用就可以直接執行。

            前面比較詳細地闡述了多任務系統中任務的劃分以及執行等內容。雖然這些是一個系統的核心,但是在一個實用的系統中,還需要任務間的同步、互斥等機制。在上述框架內,互斥可以簡單地用Java的Synchronized機制實現。由于任務可以主動讓出執行權限,要實現等待(Wait任務中止)和通知(Notify任務繼續),從而實現任務同步也就比較容易了。

          posted @ 2007-07-02 12:48 和田雨 閱讀(226) | 評論 (0)編輯 收藏

          SUN 的新版J2EE1.4提供了在J2EE中開發Web Service的基礎,對開發工具做了一些重要的增強,在應用程序部署和服務器管理方面也提供了新的標準,在集成性和安全性方面有所增強,提升了J2EE開發Web應用程序的能力;在編程模型方面的重要變化包括JSP表達式語言、簡化的標記庫等;EJB 2.1中提供了新的timer服務,查詢語言(QL)也有所增強;Jdbc3.0 API把通常的Jdbc API與擴充API結合起來;J2EE Connectors規范和獨立于消息類型的EJB提供了對雙向通信的支持。下面給大家重點介紹J2EE1.4中包含的JSP2.0、Servlet2.4、Jdbc3.0以及EJB2.1方面的新特性。

              JSP 2.0屬于J2EE 1.4平臺,它在JSP 1.2基礎之上增加了新的功能。它保證了向下兼容,原先使用的JSP技術在JSP 2.0中都可以支持。JSP 2.0的新功能主要包括下面幾部分:

          一)運行環境變化

          1、web.xml格式變化

          我們知道JSP 1.2可以在Java 2標準版1.3版本運行,而JSP 2.0要求使用Java 2標準版1.4或更新版本,JSP 2.0使用由Servlet 2.4規定的Web程序部署描述格式。

          在Web程序描述文件web.xml中需要使用xml schema打頭的格式。在web.xml中主要的變化是所有有關JSP的設置信息要放在<jsp-config>標記中。下面程序例1顯示了一個web.xml大致的樣子。

              例1:

              <?xml version="1.0" encoding="IS0-8859-1"?>

              <web-app xmlns="http://java.sun.com/xml/ns/j2ee"

              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

              xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"

              version="2.4">

              .......

              <jsp-config>

              <taglib>   

              <taglib-uri>

              http://www.icconcept.com/ics/sample-taglib

              </taglib-uri>

              <taglib-location>

              /WEB-INF/jsp/sample-taglib.tld

              </taglib-location>

              </taglib>

              ........

              <jsp-property-group>

              <description>

              For config the ICW sample application

              </description>

              <display-name>JSPConfiguration</display-name>

              <url-pattern>/jsp/datareset.jsp</url-pattern>

              <el-ignored>true</el-ignored>

              <page-encoding>ISO-8859-1</page-encoding>

              <scripting-invalid>true</scripting-invalid>

              <include-prelude>/jsp/prelude.jspf</include-prelude>

              <include-coda>/jsp/coda.jspf</include-coda>

              </jsp-property-group>

              </jsp-config>

              </web-app>

          2、JSP設置
             在<jsp-config>標記提供了Web程序中JSP程序的設置信息。<jsp-config>包括<taglib>和<jsp-property-group>兩類元素。<taglib>定義了Web程序使用的custom tag,它的用法和以前JSP 1.2中的用法相同。<jsp-property-group>定義了一組JSP的特性。這些特性實際上對應JSP的page directive定義的特性。通過<jsp-property-group>只不過可以方便地對多個具有相同屬性的JSP統一定義。
              <jsp-property-group>定義一個或多個URL樣式,在<jsp-property-group>中定義的屬性會適用于匹配這些URL樣式的所有JSP文件。在<jsp-property-group>中的屬性可以定義以下設置:
              (1)允許或禁止使用表達式語言(EL)
              在<jsp-property-group>中可以設定是否允許對應<url-pattern>的JSP使用JSTL表達式語言(EL)。如果<el-ignored>屬性標記被設定為false,JSP中的EL表達式會被處理;如果是true,Web容器會在轉換JSP時忽略EL表達式。
              (2)允許或禁止使用scripting
              <scripting-invalid>屬性可以允許或禁止使用JSP的腳本語言(scripting)。如果這個屬性標記對應為true,即scripting元素被禁止,則JSP中不能使用scriptlet,scripting表達式和declaration,否則會有轉換錯誤。當這個屬性標記為false時,JSP可以像在1.2版本之前那樣使用腳本語言。
              (3)聲明JSP編碼
              通過<page-encoding>標記可以設置對應<url-pattern>的JSP網頁的編碼。這個屬性對應每個JSP中的pageEncoding屬性,Web容器將根據這個屬性對JSP內容進行編碼。
              (4)對應隱含包括(Implicit Includes)
              在<jsp-property-group>中可以在對應JSP中加入抬頭(preludes)和結尾(coda),使用<include-prelude>和<include-coda>屬性可以設定在JSP網頁中包括的preludes和coda的jspf文件。這些文件的位置相對于當前Web程序的context。當有超過一個preludes或coda元素在<jsp-property-group>中時,JSP會按照其順序加入到內容中。
          二)引入表達式語言(EL)

          JSP 2.0的一個主要特點是它支持表達語言(expression language)。JSTL表達式語言可以使用標記格式方便地訪問JSP的隱含對象和JavaBeans組件,JSTL的核心標記提供了流程和循環控制功能。自制標記也有自定義函數的功能,因此基本上所有seriptlet能實現的功能都可以由JSP替代。在JSP 2.0中,建議盡量使用EL而使JSP的格式更一致。

          在web.xml的<jsp-property-group>中可以控制一組JSP是否使用EL,在每個JSP中也可以指定是否該JSP使用EL。在page directive中的isELIgnored屬性用來指定是否忽略。格式為:

            <%@ page isELIgnored="true|false"%>

          如果設定為真,那么JSP中的表達式被當成字符串處理。比如下面這個表達式<p>${2000 % 20}</p>在isELIgnored="true"時輸出為${2000 % 20},而isELIgnored="false"時輸出為100。Web容器默認isELIgnored="false"。

           雖然JSP 2.0可以使JSP中完全使用表達語言而避免scriptlet,在實際編程中,應該根據程序的功能要求和編程人員的自身條件選擇合適的方式。使用表達語言的JSP比較方便規整,但是由于需要將標記進行轉換,在第一次被調用時會比較慢;有些編程人員由于對Java比較了解,因而更習慣JSP 1.2之前的編程方式,因此,在使用中應因地制宜地選擇適用的編程方法。   
           
          三)SimpleTag

          JSP 2.0中加入了新的創建自制標記的API,javax.servlet.jsp.tagext.SimpleTag定義了用來實現簡單標記的接口。和JSP 1.2中的已有接口不同的是,SimpleTag接口不使用doStartTag()和doEndTag()方法,而提供了一個簡單的doTag()方法。這個方法在調用該標記時只被使用一次。而需要在一個自制標記中實現的所有邏輯過程、循環和對標記體的評估等都在這個方法中實現。從這個方面來講,SimpleTag和IterationTag可以達到同等的作用。但SimpleTag的方法和處理周期要簡單得多。在SimpleTag中還有用來設置JSP內容的seUspBody()和getJspBody()方法。Web容器會使用setJspBody()方法定義一個代表JSP內容的JspFragment對象。實現SimpleTag標記的程序可以在doTag方法中根據需要多次調用getJspBody().invoke()方法以處理JSP內容。

           例如,程序例2 SimpleTag根據指定的次數(times)進行循環并輸出當前序號(sequence)。程序的結構比較簡單,所有邏輯都在doTag方法中實現。

          例2:

            packageICW.taglib;

            importjavax.servlet.jsp.JspException;

            importjavax.servlet.jsp.tagext.SimpleTagSupport;

            importjava.util.HashMap;

            importjava.io.IOException;

            public class IterationSimpleTag extends SimpleTagSupport{

            privateint times;

          public void setTimes(int_times){

              this.times=_times;

                  }

              public void doTag() throws JspException,IOException{

              HashMapparams=new HashMap();

              for(inti=0; i<times;i++){

              params.put("sequence",String.valueOf(i+1));

              getJspBody().invoke(null,params);

                }

               }

              }
           
          這個標記的TLD文件內容如下,它使用了XML schcma定義標記的使用方法。

              程序例3如下:

              <?xml version="1.0" encoding="UTF-8" ?>

              <taglibxmlns="http://java.sun.com/xml/ns/i2ee"

              xmlns:xsi="http://WWW.w3.org/2001/XMLSchema-instance"

              xsl:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglihrary_2_0.xsd"

              version="2.0">

            <taglib>

              <tiib-version>1.0</tlib-version>

              <short-name>Jwad book simple tag</short-name>

              <uri>/JwadSimpleTag</uri>

              <description>Simple Tag Handler</description>

              <tag>

              <name>iteration</name>

              <tag-class>ICW.taglib.IterationSimpleTag</tag-class>

              <body-content>scriptless</body-content>

              <description>Iteration Tag</description>

              <variable>

              <description>Current iterationnumber</description>

              <name-given>sequence</name—given>

              </variable>

              <attribute>

              <name>times</name>

              <required>true</required>

              <rtexprvalue>true</rtexprvalue>

              </attribute>

              </tag>

             </taglib>
           

          程序例4中的JSP使用上面例3中定義的IterationSimpleTag,它根據Web請求參數中給定的“times”的值進行一定次數的循環。在每次循環中將輸出"sequence"的值。

              例4:

              <%@ taglib prefix="ictag" uri="/WEB-INF/ics-jsp2.tld" %>

              <HTML><HEAD><TITLE>Simple Tag Sample</TITLE></HEAD>

              <BODY>

              <CENTER>

              <FONT COLOR='#009999' SIZE='4' face='Arial'>

              <STRONG>Interation Simple Tag</STRONG>

              </FONT>

              </CENTER>

              <HR>

              <c:setvar="time" value="$"/>

              <p><B>Reminder:</B></p><br>

              <ictag:iteration times="$">

              This is the $ Of $ times of reminder<br>

              </ictag:iteration>

              </body>

              </html>
           
          四)使用JSP fragment

           JSP 2.0中的一個主要功能是JSP fragment,它的基本特點是可以使處理JSP的容器推遲評估JSP標記屬性。我們知道一般JSP是首先評估JSP標記的屬性,然后在處理JSP標記時使用這些屬性,而JSP fragment提供了動態的屬性。也就是說,這些屬性在JSP處理其標記體時是可以被改變的。JSP需要將這樣的屬性定義為javax.servlet.jsp.tagext.JspFragment類型。當JSP標記設置成這種形式時,這種標記屬性實際上的處理方法類似于標記體。在實現標記的程序中,標記屬性可以被反復評估多次。這種用法稱為JSP fragment。JSP fragment還可以定義在一個SimpleTag處理程序中使用的自制標記動作。像前面例子說明的,getJspBody返回一個JspFragment對象并可以在doTag方法中多次使用。需要注意的是,使用JSP fragment的JSP只能有一般的文本和JSP action,不能有scriptlet和scriptlet表達式。

            我們可以簡單地認為JSP fragment是一段可以重復使用的JSP。一段JSP fragment可以被傳遞到另一個JSP中并被使用。與JSP include概念不同的是,JSP fragment一般功能比較短小簡單而且重復使用率高。

            JSP fragment一般在<jsp:attribute>標記體內或<jspcbody>標記體內定義。每次當含有JSP fragment的標記被使用時,Web容器生成一個JspFragment對象,這個對象和當前JSP的page scope聯系起來。同時,這個JspFragment對象和包含它的父標記建立聯系。JspFragment對象可以有兩種調用方式:使用Java編寫的標記處理程序,或者使用標記文件(tag file)。標記文件可以使用<jsp:invoke>,或者<jsp:doBody>動作使用JSP fragment。  JSP標記文件可以和JSP fragment共同工作。CustomTag都是以編程方式實現的。JSP標記文件是用文本文件格式(JSP語法)實現自制標記,這也是JSP 2.0的一個主要新功能。一個標記文件可以對應一個標記,可以不需tld文件定義該標記的方法。這樣,即使編程人員不熟悉Java,也可以使用JSP語法定義自己的標記。標記文件一般使用.tag為后綴并放在Web程序的/WEB-INF目錄下。

            程序例5中的taskstatus.jsp使用了兩個JSP fragment。這個JSP的功能是顯示一組Task的名稱和完成日期,它通過<jsp:attribute name="...">定義了兩段JSPfragment(名稱為onSehedule和delayed)。在<jsp:attribute>標記內的JSP就是JSPfragment,而<jsp:attribute>標記被一個<ietag:listTasks>包圍。這個標記是一個通過標記文件定義的自制標記,它的定義文件在/WEB-INF/tags目錄下。標記文件的名稱和標記名稱一致為“listTasks.tag"。這個標記會使用到前面定義的兩個JSP fragment。
           
           例5:

            <%@ taglib prefix="ictag" tagdir="/WEB-INF/tags" %>

            <HTML><HEAD><TITLE>JSP Fragment Sample</TITLE></HEAD>

            <BODY>

              <CENTER>

              <FONT COLOR='#009999' SIZE='4' face='Arial'>

              <STRONG>JSP Fragment Sample Using Tag Files</STRONG>

              </FONT>

              </CENTER>

              <HR>

              <h2>Tasks</h2>

              <ietag:listTasks>

              <jsp:attribute name="onSchedule">

              <td>

              Name:$<br/>

              </td><td>

              Date:$

              </td>

              </jsp:attribute>

              <jsp:attribute name="delayed">

              <td>

              Name:$<br/>

              </td><td>

              <font color="red">Plan:<strike> $</strike></font><br/>

              <b>Actural:$</b>

              </td>

              </jsp:attribute>

              </ictag:listTasks>

              </BODY>

              </HTML>
           
          五)其他特性

           JSP2.0還有一些其他特性變化,比如嚴格修正了I18N的語法規則,改進JSP對應XML語法從而允許使用namespaces等。這些并不是核心功能,大家可以參照java.sun.com的有關資料了解功能的細節,這里就不再闡述。

          posted @ 2007-07-02 12:32 和田雨 閱讀(216) | 評論 (0)編輯 收藏

          標簽庫Taglib

          標簽被定義和分布在一個稱為標簽庫的結構中,一個標簽庫是由元信息和類組成的集合:

          1.標簽處理器:實現定制標簽功能的Java類。

          2.標簽附加信息(TEI):向JSP容器提供邊輯以確認標簽屬性和創建變量的類。

          3.標簽庫描述器(TLD):描述單個標簽和整個標簽庫屬性的XML文檔。

          標簽處理器和標簽附加信息需要定位在JSP容器類載入器可以找到的地方。標簽庫描述器可在URL指定的符意位置。JSP1.1規范要求JSP容器接受一個打包成因定結構的JAR文件的標簽庫。TLD必須是/META-INF目錄中名為taglib.tld的文件,JAR文件則復制到/WEB-INF/lib目錄下。

          一、標簽實現

          1.開發步驟

          a.定義標簽的名字、屬性、聲明的變量和標簽體的內容。

          b.編寫標簽庫描述器TLD。

          c.編寫標簽處理器。

          d.在JSP頁面中使用標簽。

          2.JSP頁面在JSP容器中的轉換步驟:

          JSP頁面存在三種形式:jsp文件、java文件和class文件。

          a.指令元素<%@page%>、<%@include%>和<%@taglib%>向JSP容器提供轉換時信息。

          b.HTML行在_jspService()方法中依順序轉換到out.print()語名中。

          c.腳本元素的聲明被原封不動地復制到_jspService()方法外的源碼中。

          d.腳本元素的表達式在_jspService()方法中依順序轉換到out.print()語名中。

          e.腳本元素的Scriptlet被原封不動地復制到_jspService()方法中。

          f.行為元素被轉換為執行其功能的運行時邏輯代碼。

          g.定制標簽被擴展到調用其相應標簽處理器中方法的Java語句中。

          3.標簽在JSP容器中的轉換步驟:

          a.JSP容器使用taglib指令元素定位標簽庫描述器,將頁面中用到的定制標簽和TLD相匹配。

          b.讀取標簽庫描述器的標簽列表和每一標簽相關的類名字。

          c.在頁面中遇到一個標簽時,查找與具有指定名字的標簽前綴相關的一個標簽庫。

          d.容器使用在TLD中找到的標簽結構信息生成一系列完成標簽功能的Java語句。

          二、標簽庫描述器(TLD)

          標簽庫描述器是一個描述整個標簽庫標記信息和庫中每個標簽處理器及其屬性的XML文檔。

          標簽庫描述器的DTD由一個簡單的元素組成,此元素包含下列一些子元素。

          整個標簽庫標記信息

          tlibversion標簽庫版本號。是一個點式十進制數,最多為4組小數點分隔的數字組成。

          jspversion標簽庫所需的JSP規范最低版本。例如JSP1.1

          shortname標簽庫的縮寫名。JSP可以使用該名字作為庫中標簽的缺省前綴。

          uri標簽庫唯一URI的元素。典型URL位置來自可下載taglib的位置。

          info標簽庫描述信息。

          每個標簽處理器及其屬性

          tag在TLD中加入標簽,描述組成庫的每個標簽。

          name與標簽庫的名字前綴一起使用的標簽的名字,是JSP容器唯一的標簽標識。

          tagclass實現標簽的標簽處理器類的全名。

          teiclass標簽附加信息(TEI)類的全名。TEI類給出關于標簽處理器創建變量及對標簽司性執行的任意有效性驗證的信息。

          bodycontent描述標簽處理器如何使用標簽體的內容。有三種取值:

          empty:表示標簽體必須為空;

          JSP:表示腳本元素和模板及其它標簽一樣被評估。

          tagdependent:體內容被原封不動寫入BodyContent,其它腳本元素以源碼形式出現,而不被JSP容器解釋。

          info標簽的人工可讀描述性信息。

          attribute使用標簽時被編碼的屬性信息。用于定義標簽的屬性。

          屬性名:屬性的名字。

          true|false:屬性在標簽用到的位置是否要被編碼。

          true|false:屬性值能否用表達式指定。

          三、標簽處理器

          標簽處理器是通過實現JSP容器調用的一系列預定義方法執行定制標簽行為的一個Java類。

          標簽處理器實現了標簽的行為,標簽處理器是Java類。

          1.標簽處理器的工作方式

          a.導入javax.servlet.jsp和javax.servlet.jsp.tagext包。

          b.實現javax.servlet.jsp.tagext包中的Tag接口或BodyTag接口。BodyTag是Tag的子接口。

          c.繼承TagSupport類或BodyTagSuppoert類。它們是上述接口的缺省實現。

          d.重載publicintdoStartTag()throwsJspException方法。

          2.標簽處理器的接口與實現

          javax.servlet.jsp.tagext.Tag是實現標簽的最基本的接口。

          javax.servlet.jsp.tagext.TagSupport是實現Tag接口的具體類。

          通常情況下繼承tagSupport類而不直接實現Tag接口通常是有益的。除了對所有必需方法提供了缺省實現外、還保存了pageContext對象及對嵌套標簽的支持。

          Tag接口包含4個常量,表示doStartTag()和doEndTag()方法可能的返回碼。

          EVAL_BODY_INCLUDE當doStartTag()返回時,指明servlet應對標簽體進行評估。

          SKIP_BODY當doStartTag()返回時,指明servlet應忽視標簽體。

          EVAL_PAGE當doEndTag()返回時,指明頁面其余部分應被評估。

          SKIP_PAGE當doEndTag()返回時,指明頁面其余部分就被跳過。

          Tag接口的方法

          publicvoidsetPageContext(PageContextctx)生成的servlet在請求處理器執行其它任務前首先調用此方法,實現類應保存上下文對象以便它可以在標簽生命期中使用。從頁面上下文中標簽處理器可以訪問所有JSP隱含對象。

          publicvoidsetParent(Tagp)使用一個標答可以找到操作棧中它上面的標簽。在setPageContext后立即調用。

          publicTaggetParent()返回父標簽。

          publicintdoStartTag()throwsJsp在設置了頁面上下文、父標簽和開始標記中編碼的屬性后調用。返回碼表明JSP實現servlet是否就評估標簽體。

          publicintdoEndTag()throwsJspException當遇到結否標記時調用。返回碼表明JSP是否就繼紐頁面的其余部份。

          publicvoidrelease()確保在頁面退出前被調用。釋放資源并重置標簽處理器狀態。

          TagSupport類的方法

          publicstaticTagfinAncestorWithClass(TagthisTag,Classcls)為所需的父標簽處理器查找運行時標簽棧。一個標簽處理器可以提供其范圍內子標簽調用的方法。

          publicvoidsetId(Stringid)保存和檢索在id屬性中指定的名字。

          publicvoidsetValue(Stringname,Objecto)在本地哈希表中設置指定名字的值。

          publicObjectgetValue(Stringname)從本地哈希表中獲取指定名稱的值。

          publicvoidremoveValue(Stringname)從本地哈希表中刪除指定名稱的值。

          publicEnumerationgetValues()返回哈希表中關鍵字的一個枚舉。

          3.標簽處理器的生命期

          a.生成servlet需要創建標簽處理器類的一個實例。實現方式通常是調用JSP容器的工廠類的一個方法,工廠類包含一個標簽處理器實例池以使其可重用不再處于激活狀態的對象。

          b.初始化標簽處理器,使servlet獲知其存在性。servlet通過調用標簽處理器的兩個方法實現此過程:setPageContext(PageContextctx)和setParent(Tagparent)。

          c.如果標簽具有屬性,屬性的取值通過處理器提供setter方法傳入到對象。屬性setter方法是一個標簽支持屬性所需的唯一方法。

          d.頁面的上下文和父標簽已被調置,并已具備屬性。此時調用標簽處理器的doStartTag()方法,該方法可以讀取這些變量并執行實現標答功能所需的計算和操作。doStartTag()方法必須返回一個整型數。返回EVAL_BODY_INCLUDE則正常處理標簽體,返回SKIP_BODY則從初始JSP頁面中直到此標簽結束標記處的內容均被忽略。

          e.標簽體被評估或忽視后調用標簽處理器的doEndTag()方法,返回EVAL_PAGE則頁面的其余部分被評估,返回SKIP_PAGE則servlet代碼立即從_jspService()中返回。

          4.體標簽處理器的接口與實現

          javax.servlet.jsp.tagext.BodyTag是Tag的子接口。

          javax.servlet.jsp.tagext.BodyTagSupport是實現BodyTag類。

          BodyContent是javax.servlet.jsp.JspWriter的子類,但與其父類有所區別。

          BodyContent對象的內容不自動寫了入servlet的輸出流,而是積累在一字符串緩存中。當標簽體完成后其對象仍可在doEndTag()方法中可以應用,由getString()或getReader()方法操作。并在必要時修改及寫入恢復的JspWriter輸出流。

          BodyContent類的方法

          publicvoidflush()throwsIOException復寫JspWrite.flush()方法以便它總是產生溢出。刷新寫入已失效,因為它沒有連接到將被寫入的實際輸出流中。

          publicvoidclearBody()重置BodyContent緩存為空。

          publicReadergetReader()返回Reader讀取體內容。

          publicStringgetString()返回包含體內容的一個字符串。

          publicvoidwriteOut(Writew)將體內容寫入指定輸出。

          publicJspWritegetEnclosingWrite()返回棧中下一個更高的寫入者對象(可能是另一個BodyContent對象)。

          BodyTag接口定義了一個新的整型常量

          EVAL_BODY_TAG當doStartTag()返回時,使得新的BodyContent對象被創建并與此標簽處理器相關聯。當doAfterBody()返回時,使得JSPservlet在修改完此標簽控制的任意變量后再次評估體。

          BodyTag接口的方法

          publicvoidsetBodyContern(BodyContentout)在當前JspWriter已被寫入,一個新的BodyContent在被創建后由Jspservlet調用,它發生在doStartTag()之后。

          publicvoiddoInitBody()throwsJspExceptionsetBodyContent()之后,體被評估前調用的生命期方法。如果多次評估體,此方法只調用一次。

          publicinitdoAfterBody()throwsJspException體被評估后,BodyContent寫入者仍處于激活狀態時調用的生命期方法。此方法必須返回EVAL_BODY_TAG或SKIP_BODY,若返回EVAL_BODY_TAG時體再次被評估。

          BodyTagSupport類的方法

          publicintdoStartTag()throwsJspException復寫TagSupport中的doStartTag()方法。

          publicintdoEndTag()throwsJspException調用TagSupport中的doEndTag()方法,返回結果。

          publicvoidsetBodyContent(BodyContentout)在一保護成員變量bodyContent中保存新的體內容對象,子類可直接訪問此對象。

          publicvoiddoInitBody()throwsJspException缺省什么都不做。被需要執行初始化的子類所復寫。

          publicintdoAfterBody()throwsJspException每次體被評估后由JSPservlet調用,體同容對象仍處于激活狀態。返回SKEP_BODY或EVAL_BODY_TAG則體再次被評估

          publicvoidrelease()設置bodyContent對象為null,然后調用super.release()。

          publicBodyContentgetBodyContent()返回bodyContent變量。子類已經可以訪問保護變量,但此方法允許無關的標簽處理類對此體內容發送輸出。

          publicJspWritergetPreviousOut()在bodyContent變量上調用getEnclosingWriter()并返回結果的簡便方法。

          5.體標簽處理器的生命期

          a.生成servlet需要創建標簽處理器類的一個實例。實現方式通常是調用JSP容器的工廠類的一個方法,工廠類包含一個標簽處理器實例池以使其可重用不再處于激活狀態的對象。

          b.初始化標簽處理器,使servlet獲知其存在性。servlet通過調用標簽處理器的兩個方法實現此過程:setPageContext(PageContextctx)和setParent(Tagparent)。

          c.如果標簽具有屬性,屬性的取值通過處理器提供setter方法傳入到對象。屬性setter方法是一個標簽支持屬性所需的唯一方法。

          d.頁面的上下文和父標簽已被調置,并已具備屬性。調用標簽處理器的doStartTag()方法,該方法可以讀取這些變量并執行實現標答功能所需的計算和操作。

          doStartTag()方法必須返回一個整型數。

          返回EVAL_BODY_TAG則正常處理標簽體(跳到e);

          返回SKIP_BODY則從初始JSP頁面中直到此標簽結束標記處的內容均被忽略。(跳到f)

          e.如果返回EVAL_BODY_TAG時,則正常處理標簽體。

          e1.在棧中保存當前的JspWriter對象,創建新的BodyContent對象,并將其置為JSP頁面的out對象保存在上下文范圍內名為name的屬性中。并調用它的setBodyContent()方法。

          e2.調用doInitBody()方法進行初始化。

          e3.處理標簽體。將輸出寫入BodyContent對象中,此過程依賴于TLD的標簽元素 ,有三種可能取值。

          e4.調用doAfterBody()方法,將體內體內容寫入JspWriter,可如下實現:

          JspWriterout=bodyContent.getEnclosingWriter();

          out.println(bodyContent.getString());//bodyContent.writeOut(out);

          bodyContent.clear();

          e5.doAfterBody()方法返回兩種可能:

          返回EVAL_BODY_TAG時,再對標簽體進行評估,這是數組和枚舉被循環處理的典型情況。

          返回SKIP_PAGE時,繼續頁面的其余部份。

          e6.體內容完成,因此創建它的過程被反向:

          調用pageContent.popBody()方法檢索前面的JspWriter對象。

          將寫入者設置回out隱含對象。

          f.標簽體被評估或忽視后調用doEndTag()方法,允許標簽處理器像輸出流發回內容。

          返回EVAL_PAGE則頁面的其余部分被評估;

          返回SKIP_PAGE則servlet代碼立即從_jspService()中返回。

          g.此時體的內容在受保護的bodyContent對象中仍然可用。

          可以將它寫入servlet輸出流中:

          JspWriterout=pageContext.getOut();

          out.println(bodyContent.getString());

          或者

          bodyContent.WriteOut(pageContext.getOut());

          6.標簽附加信息類

          四、標簽指令

          taglib指令元素的目的是指定TLD的位置,設置在頁面上與標簽區分開來的一個短別名。

          語法:<%@taglibprefix=”tagprefix”uri=”tagliburi”%>

          屬性:prefix:用于標識標簽庫的唯一標識。uri:標簽庫本身的URI。

          uri不必指向一個實際文件,它是JSP容器可以在web.xml中查找實際文件位置的唯一標識符。

          posted @ 2007-07-02 12:29 和田雨 閱讀(200) | 評論 (0)編輯 收藏

          Servlet API 很久以前就已成為企業應用開發的基石,而 Servlet 過濾器則是對 J2EE 家族的相對較新的補充。本文將向您介紹 Servlet 過濾器體系結構,定義過濾器的許多應用,并指導您完成典型過濾器實現的三個步驟。同時本文還會透露bean 的一些激動人心的變化,預計剛發布的 Java Servlet 2.4規范會引入這些變化。

            Servlet 過濾器是可插入的 Web 組件,它允許我們實現 Web 應用程序中的預處理和后期處理邏輯。過濾器支持 servlet 和 JSP 頁面的基本請求處理功能,比如日志記錄、性能、安全、會話處理、XSLT 轉換,等等。 過濾器最初是隨 Java Servlet 2.3 規范發布的,最近定稿的 2.4 規范對它進行了重大升級。在此我將向您介紹 Servlet 過濾器的基礎知識 ―― 比如總體的體系結構設計、實現細節,以及在 J2EE Web 應用程序中的典型應用,還會涉及一些預計最新的 Servlet 規范將會提供的擴展功能。

            Servlet 過濾器是什么?

            Servlet 過濾器是小型的 Web 組件,它們攔截請求和響應,以便查看、提取或以某種方式操作正在客戶機和服務器之間交換的數據。過濾器是通常封裝了一些功能的 Web 組件,這些功能雖然很重要,但是對于處理客戶機請求或發送響應來說不是決定性的。典型的例子包括記錄關于請求和響應的數據、處理安全協議、管理會話屬性,等等。過濾器提供一種面向對象的模塊化機制,用以將公共任務封裝到可插入的組件中,這些組件通過一個配置文件來聲明,并動態地處理。

            Servlet 過濾器中結合了許多元素,從而使得過濾器成為獨特、強大和模塊化的 Web 組件。也就是說,Servlet 過濾器是:

          • 聲明式的:過濾器通過 Web 部署描述符(web.xml)中的 XML 標簽來聲明。這樣允許添加和刪除過濾器,而無需改動任何應用程序代碼或 JSP 頁面。
          • 動態的:過濾器在運行時由 Servlet 容器調用來攔截和處理請求和響應。
          • 靈活的:過濾器在 Web 處理環境中的應用很廣泛,涵蓋諸如日志記錄和安全等許多最公共的輔助任務。過濾器還是靈活的,因為它們可用于對來自客戶機的直接調用執行預處理和后期處理,以及處理在防火墻之后的 Web 組件之間調度的請求。最后,可以將過濾器鏈接起來以提供必需的功能。
          • 模塊化的:通過把應用程序處理邏輯封裝到單個類文件中,過濾器從而定義了可容易地從請求/響應鏈中添加或刪除的模塊化單元。
          • 可移植的:與 Java 平臺的其他許多方面一樣,Servlet 過濾器是跨平臺和跨容器可移植的,從而進一步支持了 Servler 過濾器的模塊化和可重用本質。
          • 可重用的:歸功于過濾器實現類的模塊化設計,以及聲明式的過濾器配置方式,過濾器可以容易地跨越不同的項目和應用程序使用。
          • 透明的:在請求/響應鏈中包括過濾器,這種設計是為了補充(而不是以任何方式替代)servlet 或 JSP 頁面提供的核心處理。因而,過濾器可以根據需要添加或刪除,而不會破壞 servlet 或 JSP 頁面。

            所以 Servlet 過濾器是通過一個配置文件來靈活聲明的模塊化可重用組件。過濾器動態地處理傳入的請求和傳出的響應,并且無需修改應用程序代碼就可以透明地添加或刪除它們。最后,過濾器獨立于任何平臺或者 Servlet 容器,從而允許將它們容易地部署到任何相容的 J2EE 環境中。

            在接下來的幾小節中,我們將進一步考察 Servlet 過濾器機制的總體設計,以及實現、配置和部署過濾器所涉及的步驟。我們還將探討 Servlet 過濾器的一些實際應用,最后簡要考察一下模型-視圖-控制器(MVC)體系結構中包含的 Servlet 過濾器,從而結束本文的討論。

            Servlet 過濾器體系結構

            正如其名稱所暗示的, Servlet 過濾器用于攔截傳入的請求和/或傳出的響應,并監視、修改或以某種方式處理正在通過的數據流。過濾器是自包含、模塊化的組件,可以將它們添加到請求/響應鏈中,或者在無需影響應用程序中其他 Web 組件的情況下刪除它們。過濾器僅只是改動請求和響應的運行時處理,因而不應該將它們直接嵌入 Web 應用程序框架,除非是通過 Servlet API 中良好定義的標準接口來實現。

            Web 資源可以配置為沒有過濾器與之關聯(這是默認情況)、與單個過濾器關聯(這是典型情況),甚至是與一個過濾器鏈相關聯。那么過濾器究竟做什么呢? 像 servlet 一樣,它接受請求并響應對象。然后過濾器會檢查請求對象,并決定將該請求轉發給鏈中的下一個組件,或者中止該請求并直接向客戶機發回一個響應。如果請求被轉發了,它將被傳遞給鏈中的下一個資源(另一個過濾器、servlet 或 JSP 頁面)。在這個請求設法通過過濾器鏈并被服務器處理之后,一個響應將以相反的順序通過該鏈發送回去。這樣就給每個過濾器都提供了根據需要處理響應對象的機會。

            當過濾器在 Servlet 2.3 規范中首次引入時,它們只能過濾 Web 客戶機和客戶機所訪問的指定 Web 資源之間的內容。如果該資源然后將請求調度給其他 Web 資源,那就不能向幕后委托的任何請求應用過濾器。2.4 規范消除了這個限制。Servlet 過濾器現在可以應用于 J2EE Web 環境中存在請求和響應對象的任何地方。因此,Servlet 過濾器可以應用在客戶機和 servlet 之間、servlet 和 servlet 或 JSP 頁面之間,以及所包括的每個 JSP 頁面之間。這才是我所稱的強大能力和靈活性!

          posted @ 2007-07-02 12:28 和田雨 閱讀(194) | 評論 (0)編輯 收藏

          常用的設定,詳細請看:http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
          XML聲明,定義XML的版本、編碼格式。還有最重要的schema的來源
          <?xml version="1.0" encoding="UTF-8"?>
          <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
            .......
          </web-app>
           
          <description>
          當servlet的URL定義為其他文件類型的擴展名,該文件類型將不能訪問,而訪問了servlet
          <?xml version="1.0" encoding="UTF-8"?>
          <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
            <display-name>myweb</display-name><!--站點名稱-->
            <description>這里是站點描述</description>
            <icon>
              <small-icon>/images/small.gif</small-icon><!--小圖標的路徑16*16,必須為gif jpge格式-->
              <large-icon>/images/large.gif</large-icon><!--大圖標的路徑32*32,必須為gif jpge格式-->
            </icon>
            <!--如果存在<distributable/>則代表該站點能在多個JSP Container之間分散執行(分布式)-->
            <distributable/>




            <context-param><!--環境參數,設置常量,取得常量  this.getInitParameter("context");-->
              <param-name>context</param-name>
              <param-value>10000</param-value>
            </context-param>
            <filter><!--聲明filter-->

              <filter-name>filterName</filter-name>
              <filter-class>filter.filterName</filter-class>
              <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
              </init-param>
            </filter>
            <filter-mapping><!--定義filter所對應的URL-->
            <filter-name>filterName</filter-name>
            <url-pattern>/filterName</url-pattern>
            <dispatcher>REQUEST|INCLUDE|FORWARD|ERROR</dispatcher><!--filter對應的請求方式,有4種方式,默認REQUEST-->
            </filter-mapping>
            <listener><!--設定Listener接口-->
              <listener-class>listener.ListenerClassName</listener-class>
            </listener>
            <servlet><!--聲明servlet的數據-->
            <servlet-name>servletName</servlet-name>
            <servlet-class>servlet.servletName</servlet-class>
            <init-param><!--初始化參數,可以在init()中使用ServletConfig().getInitParamenter("name")取得-->
              <param-name>name</param-name>
              <param-value>123</param-value>
            </init-param>
            <load-on-startup>n</load-on-startup><!--站點啟動時,此servlet會被自動加載執行,1表示最早,2,3...-->

            </servlet>
            <servlet-mapping><!--定義servlet所對應的URL-->

              <servlet-name>name</servlet-name>
              <url-pattern>/name</url-pattern>
            </servlet-mapping>
            <session-config><!--設置session超時時間(20分鐘)默認按服務器配置-->
              <session-timeout>20</session-timeout>
            </session-config>
            <mime-mapping><!--定義某個擴展名和某個MIME Type做映射-->
              <extension>doc</extension>
              <mime-type>application/vnd.ms-word</mime-type>
            </mime-mapping>
            <welcome-file-list><!--設置首頁列表-->
            <welcome-file>index.jsp</welcome-file>
            </welcome-file-list>
            <error-page><!--將錯誤代碼對應到WEB站點的資源路徑-->
            <error-code>錯誤代碼</error-code>Exception
            <location>/路徑/</location>

            </error-page>
            <error-page><!--將異常的種類對應到WEB站點的資源路徑-->
            <exception-type>Exception</exception-type>
            <location>/路徑/</location>

            </error-page>

            <jsp-config><!--JSP的相關配置-->
              <taglib><!--JSP所用到的Tag Library-->
                <taglib-uri>URI</taglib-uri>
                <taglib-location>/WEB-INF/lib/xxx.tld</taglib-location>
              </taglib>
              <jsp-property-group>
                <description>此設定的說明</description>
                <display-name>Name</display-name>
                <url-pattern>URL</url-pattern><!--此設定影響的范圍-->
                <el-ignored>true|false</el-ignored><!--true表示不支持EL語法-->
                <scripting-invalid>encoding</scripting-invalid><!--jsp的編碼-->
                <include-coda>...jspf</include-coda><!--JSP的結尾,擴展名.jspf-->
              </jsp-property-group>
            </jsp-config>
            <resource-ref><!--利用JNDI取得站點可利用的資源-->
              <description>資源說明</description>
              <res-ref-name>資源名稱</res-ref-name>
              <res-type>資源種類</res-type>
              <res-auth>Application|Container</res-auth><!--資源經由什么許可-->
              <res-sharing-scope>Shareable|Unshareable</res-sharing-scope><!--資源是否可以共享,默認為Shareable-->
            </resource-ref>
          </web-app>
          posted @ 2007-07-02 12:22 和田雨 閱讀(4972) | 評論 (1)編輯 收藏

          2005年9月26日,Sun公司和JSR154的專家組發布Servlet API的一個新的版本。在一般情況下,一個JSR的新版本僅僅包括對以前少數有名無實的規范進行去除更新。但這次,新版本中增加新的特征和變化,他們對Servlets的產生重要影響,使得Servlet的版本升到了 2.5。
          在這篇文章里,我主要談談Servlet2.5版本中的新特征。描述每一個變化,闡述那些必要變化產生的背景,并展示如何在基于Servlet的項目中利用這些變化。 
          事實上,這是我為JavaWorld提供的第六篇關于Servlet API更新資料的文章。這篇文章意在兩個目的:從眼前來看,向你介紹 Servlet的新特征。從長遠來看,是展現Servlet變化的歷史概要,這樣當你基于老的Servlet API版本進行編碼的時候,你可以正確地決定哪些特征和功能你可以使用,而哪些特征和功能你不應該使用。你可以參考我先前寫的關于Servlet的文章。
          注意:當你想實踐這些Servlet的新特征和功能時,你要知道的是:并不是所有的Servlet容器和Java企業級應用服務器都能立即適用于最新版的Servlet API,寫這篇文章時(2006年1月2日),Jetty 6 server和Sun公司的GlassFish server是公認最好的支持Servlet2.5的容器,而Apache Tomcat5.5和Jboss 4.0目前只支持Servlet2.4。
          Servlet2.5一些變化的介紹:
          1)    基于最新的J2SE 5.0開發的。
          2)    支持注釋。
          3)    web.xml中的幾處配置更加方便。
          4)    去除了少數的限制。
          5)    優化了一些實例
          J2SE 5.0的產物:
          從一開始,Servlet 2.5 規范就列出J2SE 5.0 (JDK 1.5) 作為它最小的平臺要求。它使得Servlet2.5只能適用基于J2SE 5.0開發的平臺,這個變動意味著所有J2SE5.0的新特性可以保證對Servlet2.5程序員有用。
          傳統意義上,Servlet和JEE版本一直與JDK的版本保持同步發展,但是這次,Servlet的版本跳過1.4版本。專家組認為版本的加速增長是正當的,因為J2SE5.0提出一個引人注目的,Servlet和JEE規范都要利用的特征??注釋。
          注釋:
          注釋是作為JSR175的一部分提出的(一種為Java語言設計提供便利的Metadata)一種新的語言特色。它是利用Metadata為Java 編碼結構(類,方法,域等等)裝飾的一種機制。它不能像代碼那樣執行,但是可以用于標記代碼,這個過程是基于Metadata信息的代碼處理機,通過更新他們的事件行為來實現的。

          我們可以憑借不同的技巧來注釋類和方法,例如連續地標記接口或者是@deprecated Javadoc評論。這種新式的Metadata可以便利地提供了一種標準的機制來實現注釋功能,以及通過庫來創建用戶自己的注釋類型的變量。
          下面是一個簡單的Web service 注釋例子:
          import javax.jws.WebService;
          import javax.jws.WebMethod;
          @WebService
          public class HelloWorldService {
            @WebMethod
            public String helloWorld() {
              return "Hello World!";
            }
          }
          @WebService和@WebMethod這兩個注釋類型,在JSR181(為Java平臺提供的Web ServicesMetadata)有詳細說明,可以像類一樣的引用,標記這個類作為一個Web service并且標記它的helloWorld()方法做為一個Web service方法。對于他們本身來說,注釋只是寫在那里并沒有什么作用,好像在崗位上做記錄一樣,但是,一個容器一旦加載這個類并對那些注釋進行二進制編碼,就可以把這個類連到Web service上。
          注釋可以接受屬性/值這些參數。它保存著參數的信息并且可以利用這些參數來更改被請求的事件行為。例如下面更高級的注釋例子:
          @WebService(
           name = "PingService",
            targetNamespace=http://acme.com/ping
          )
          @SOAPBinding(
            style=SOAPBinding.Style.RPC,
            use=SOAPBinding.Use.LITERAL
          )
          public class Ping {
            @WebMethod(operationName = "Foo")
            public void foo() { }
          }
          一旦加載了這個類,一個正確配置的容器就會識別出注釋及其參數,并將這個做為一個PingService通過利用remote-procedure- call/literal的編碼方式與一個Foo operation相連。實際上,注釋便指明了類和類的容器之間的聯系。

          Java本身的規范(JSR175)僅僅有少量的注釋類型變量。而這些有趣的注釋類型變量主要來自于其他的JSRs:
          "JSR 250: Java平臺的公共注釋
          "JSR 220: 企業級JavaBeans 3.0 
          "JSR 224: 基于XML的Java API Web Services (JAX-WS) 2.0 
          "JSR 181: Java平臺的Web Services Metadata 
          Servlet2.5中的注釋:
          回到Servlet2.5上來,一種新的規范描述了幾種注釋在Servlet環境中是如何工作的。功能弱的Servlet容器忽略了這些規范,然而JEE容器中的Servlet卻嚴格遵守這些規范。

          有的注釋提供了在XML注冊的可選擇性,否則就要注冊在配置文件web.xml中。有的作為容器的請求來執行其任務,否則就由Servlet親自來執行。還有的注釋兩者都具備。

          注釋準確的定義不是完全固定的,因為Servlet本身并沒有定義注釋。它僅僅解釋了它們如何影響Servlet環境,下面是注釋的一個簡要的概述,你可以看到在JEE5中它們的用途:

          "@Resource and @Resources:@Resource位于類或變量中以對Servlet容器進行“資源注入”。當容器識別出這個注釋時,它會在獲得服務地位之前,用適當的值實現帶注釋的變量的重新注入。通過使用這種注釋,你不必利用JNDI來查找命令和在配置文件web.xml中手動聲明資源。服務器通過Servlet的自我調整來執行它的任務。變量的名稱和類型由映像機制自動確定,盡管你可以利用注釋的參數來超越這一限制。一個注入的資源可以是數據源,Java信息服務目的文件或者是環境設置的標量。下面是一個例子:
          @Resource javax.sql.DataSource catalog;
          public getData() {
            Connection con = catalog.getConnection();
          }
          現在,在這段Servlet代碼變成服務之前,容器會定位JNDI變量,并對于目錄變量進行手動分配。
          為了效率,僅僅某些類支持資源注入,這些類有:Servlets,Servlet過濾器,Servlet事件監聽器,JSP標簽操作器,JSP庫事件監聽器,用于處理beans的JSF,以及一些與Serlvets無關的類。
          "@Resources注釋與@Resource相似,但是它用于一組@Resource注釋。它們都來自JSR250,是Java平臺的公共注釋。
          "@PostConstruct and @PreDestroy:可以使方法成為帶有生命周期的方法。@PostConstruct方法用于資源注入初始化之后。@PreDestroy方法用于Servlet脫離服務并釋放注入的資源的時候。回收的方法必須是事實的方法,返回void并且不可以拋出任何異常。這些注釋本質上使得任何方法都成為init()和destroy()的子方法,這些特征也來自與JSR250。
          "@EJB:類似于@Resource,設計用于注入企業級的JavaBeans。比起@Resource,它略有不同,在于@EJB的參數特定設計用來定位EJB的參數。這個注釋來自EJB3.0的規范。
          "@WebServiceRef:與@Resource 和 @EJB相似,設計用于注入Web service參數。來自于JAX-WS2.0規范。
          "@PersistenceContext, @PersistenceContexts, @PersistenceUnit, and @PersistenceUnits:這些注釋來自EJB3.0規范來支持Java對象的持久化。
          "@DeclareRoles: 定義應用程序中安全角色的使用。當定義一個Servlet類時,在配置文件web.xml中<security-role>標簽中對它進行設置,來自JSR250。
          " @RunAs:用于聲明哪個類應該執行。當定義一個Servlet類時,在配置文件web.xml中<run-as>標簽中對它進行設置。來自于JSR250。

          注釋的執行:
          不論你使用注釋與否??尤其在你不使用時??它對于理解服務器上程序的執行有著重要意義。為了讓服務器識別類中的注釋,它必須加載這些類,這就意味著服務器必須是啟動著的,服務器通過WEB-INF/classes目錄下和WEB-INF/lib目錄下的所有類文件來查找注釋。(每個規范下,服務器不必查找這兩個目錄以外的目錄。)你可以通過下面的方法指明<web-app>根的屬性而不必使用如何進行注釋:
          <web-app xmlns="http://java.sun.com/xml/ns/javaee"
                       version="2.5" full="true">
          </web-app>
          web.xml的便利:
          Servlet2.5對于web.xml引入幾個小的變動,使得它更加方便。
          Servlet名稱的通配符化:
          首先,當你寫<filter-mapping>,你現在可以在<Servlet-name>標簽中使用*號來代表所有的Servlets。而以前,你必須一次把一個Servlet綁定到過濾器上,像這樣:

          <filter-mapping>
            <filter-name>Image Filter</filter-name>
            <Servlet-name>ImageServlet</Servlet-name>
          </filter-mapping> 

          現在,你可以一次綁定所有的Servlets:

          <filter-mapping>
            <filter-name>Image Filter</filter-name>
            <Servlet-name>*</Servlet-name>  <!?新特征 -->
          </filter-mapping>

          這有著很大用途,例如:

          <filter-mapping>
            <filter-name>Dispatch Filter</filter-name>
            <Servlet-name>*</Servlet-name>
            <dispatcher>FORWARD</dispatcher>
          </filter-mapping>

          映射的復合模式:
          其次,當我們寫<Servlet-mapping> 或者 <filter-mapping>時,你現在可以在同一的標簽中采用復合匹配的標準。以前一個<Servlet-mapping>只支持一個<url-pattern>元素,現在它不只支持一個,例如:
          <Servlet-mapping>
            <Servlet-name>color</Servlet-name>
            <url-pattern>/color/*</url-pattern>
            <url-pattern>/colour/*</url-pattern>
          </Servlet-mapping>

          同樣地,以前<filter-mapping>也是只支持一個<url-pattern> 或者一個 <Servlet-name>。現在它對于每個元素都可以支持任意多個:

          <filter-mapping>
            <filter-name>Multipe Mappings Filter</filter-name>
            <url-pattern>/foo/*</url-pattern>
            <Servlet-name>Servlet1</Servlet-name>
            <Servlet-name>Servlet2</Servlet-name>
            <url-pattern>/bar/*</url-pattern>
          </filter-mapping>

          HTTP方法名:

          最近,你可以將合法的HTTP/1.1方法名放進<http-method>元素中。當你使用這些方法時,<http- method>將指明<security-constraint>標記里的方法應該被應用。從以前來看,它僅限于HTTP/1.1的7 個標準方法:GET,POST,PUT,DELETE,HEAD,OPTIONS和TRACE。但是,HTTP/1.1允許對方法進行擴展,WebDAV 是用于這種擴展的普遍技術。在Servlet2.5中,你可以安全地約束任何可能的HTTP方法名,標準及擴展,包括WebDAV方法,例如:LOCK, UNLOCK,COPY及MOVE。
          如果你寫一個WebDAV的Servlet,你不必使用doLock()和doCopy()方法。你必須寫自己的service()方法及分派request.getMethod()方法。正由于這種變化,你不必管理系統的安全性。
          去除限制:

          Servlet2.5去除了關于錯誤處理和回話跟蹤的一些限制。對于錯誤處理,Servlet2.5之前,配置在<error- page>中的錯誤處理頁面不能通過調用setStatus()方法來修改觸發他們的錯誤代碼,而Servlet2.5減弱了這一規范。這樣的規范的產生于這樣的觀點,就是錯誤頁面的工作是指出每個錯誤而不是修改錯誤。但是,實際使用中,錯誤頁面不只是用于指出錯誤,而是還能做更多的事情,或許可以代替在線幫助來幫助用戶解決問題。這個規范將不再限制錯誤頁面所產生的反饋信息。

          對于會話跟蹤,Servlet2.5之前,調用RequestDispatcher.include()的Servlet不能設置響應的標題頭,而 Servlet2.5減弱了這一規范。原規范的目的是使內部的Servlets限制在自己的頁面空間中,不可以影響外部的頁面。現在這個規范已經減弱,允許在內部的Servlet中使用request.getSession()命令,這個命令可以悄悄地創建一個會話跟蹤cookie的標題頭。邏輯上要求限制內部的資源,但邏輯上也要求這些限制不應該取消其啟動session的這一功能。這個變動對于Portlet規范來說顯得尤其重要。作用是:如果響應已經有效,則getSession()命令就會拋出一個IllegalStateException(異常),而在此之前,就沒有這個功能。

          優化:
          最近,新的規范優化了一些實例,使得Servlets更加方便而且保證了更好地按要求工作。

          終止響應:
          第一處優化細小又深奧,但做為規范中的一個例子還有蠻有趣的。Servlet2.4規范規定響應在這幾種情況下應該是有效的,包括:在響應的 setContentLength方法中內容已經明確說明,以及內容已經寫進了響應中。這種情況只有你的代碼像下面這樣才可以使響應重新定向:

          response.setHeader("Host", "localhost");
          response.setHeader("Pragma", "no-cache");
          response.setHeader("Content-Length", "0");
          response.setHeader("Location", "http://www.apache.org");

          Servlet技術忽略特定區域的標題頭,因為內容滿足0字節長度,響應就會立即生效。而在它開始之前,響應就已失效了!Servlet容器通常拒絕執行這種行為,而Servlet2.5版本增加了“長度必須大于0”這個原則。
          實例編碼:

          Servlet2.4規范規定必須在調用request.getReader()方法之前調用 request.setCharacterEncoding()方法。但是,如果你忽略這個原則而在其之后去調用 request.setCharacterEncoding()方法,那么會產生什么后果,這個問題規范里并沒有說。為了簡便,現在消除這種情況!
          Cross-context sessions(不同上下文目錄間的會話):
          最近,關于Cross-context會話處理的規則已經明確說明。當Servlets指派從一個上下文到其他上下文的請求時,這個規則就發揮了作用??在目標調用過程中,包括哪些會話。這個版本的出現使得一個上下文目錄的主頁里的portlets可以通過幾種內部的命令來對別的上下文目錄里的 portlets起作用。Servlet2.5明確指出一個上下文目錄里的資源可以訪問其他上下文目錄的session(會話),而不用考慮這個請求從哪里開始的。這意味著portlets可以脫離主頁的范圍而在自己的范圍里運行,而且這個規范還會應用在不兼容的Serlvet容器中。
          期待:

          由于Servlet2.5版本要保持一些舊的性質,幾個大的概念不得不延后到下一個階段。它們包括:
          "新的輸入/輸出(NIO)支持:使NIO通道更有利于Servlets進行客戶端通信成為可能。
          "過濾器wrap-under或wrap-over語義:有時用過濾器包裝請求,和/或者響應對象去修改方法行為或者啟用新的方法。當把這種包裝和服務器對請求和響應的包裝結合起來時,又應該怎么包裝在一起?
          "用于歡迎的Servlets文件:做為索引應該充當歡迎作用的文件嗎?在此之前,這個回答是肯定的。但是規范沒有明確說明如何使用這個功能,尤其在沒有索引的情況下。
          "用于歡迎的文件的分派規則:如何分派歡迎文件,這個細節并沒有完全說明,而是遺留了一些開放的缺口來應對不兼容問題。
          "登陸后選擇默認頁面:如果用戶通過他們的書簽訪問Servlet的登陸頁面,那么在成功登陸后頁面應該轉向哪里呢?這個問題至今尚未明確說明。
          "用戶的主題日志:在通過網站正確地注冊之后,不通過傳統地登陸方式沒有辦法使Servlet信任用戶。
          結束語:
          如果拋開注釋來看Servlet2.5的變化,可見在配置文件web.xml中去除了一些限制,是有利的,同時又優化了實例行為使其更適合更便于開發Web系統(網頁)。
          Servlet2.5中注釋的作用更加戲劇化。Servlets本身不能聲明注釋類型的變量,甚至性能弱的Servlet容器都不支持注釋。然而在 JEE5環境下的Servlets編寫者可以看到,通過公共的注釋及EJB3.0和JAX-WS2.0規范而引入的注釋類型會對代碼產生很大變化,并且這也將對Servlet如何管理外部資源,對象的持久化及EJB的構成產生重大影響

          J2EE的兩種重要的表現層技術JSP和JSF發布了新技術規范的預覽版本,其中最重要的一點是兩者將表達式語言(Expression Language,EL)部分合二為一。在不久的將來,這兩種技術有可能更進一步地彼此融合,成為一種統一的表現層技術。然而在J2EE社群的普遍觀點中,如果單單作為一種視圖技術,JSP并不是最佳的選擇,Velocity和XSLT等基于模板的視圖技術通常比JSP更方便;而基于組件的JSF也面臨廣泛的信任危機。兩者的組合是否能得到業界的認可,還需要時間的檢驗。

          jsp 2.1


              我們很高興向大家宣告,JavaServer Pages、JSR-245下開發的Faces.JavaServer Pages(JSP)2.1和JSR-252下開發的JavaServer Faces(Faces)1.2的新版規范的Early Draft Review發布。

              JSP 2.1把Expression Language(EL)輸出到它自己各自分離的文檔中,在技術上,這些文檔是JSP規范的子文檔。這些統一的EL規范定義了一個更高層的java 包,javax.el。這個包與使用它的技術之間完全獨立,并且允許此技術將自身插入EL處理過程。更改的JSP規范遵從使用標準化EL的規范。

              對于前面提到的JSR-252,這個規范并沒什么新特性。Faces 1.2支持新的標準化EL,還包含一些bug修復的相關規范。

              Faces和JSP在JSRs下的結盟帶來了一些新功能,也為將來的發展打下了堅實的基礎。例如,在同時使用Faces和JSP的web應用中,網頁僅使用JSP(不包含任何faces內容)來訪問Managed Beans成為可能。在JSP規范的附錄E中和Faces規范的前言中都可以看到更改內容的細節。

          posted @ 2007-07-02 12:20 和田雨 閱讀(2301) | 評論 (0)編輯 收藏

          僅列出標題
          共9頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 
          主站蜘蛛池模板: 丰台区| 额济纳旗| 得荣县| 信丰县| 新民市| 绥芬河市| 青川县| 兴文县| 泸定县| 正镶白旗| 来凤县| 错那县| 清水县| 牙克石市| 太谷县| 阿合奇县| 吉木乃县| 水富县| 阳新县| 南丰县| 怀远县| 家居| 安岳县| 通州市| 宁强县| 龙口市| 泾源县| 耒阳市| 蛟河市| 岑溪市| 阿拉善右旗| 琼海市| 锡林郭勒盟| 读书| 凌源市| 来凤县| 德格县| 平昌县| 巴中市| 垫江县| 南宁市|