kapok

          垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            455 隨筆 :: 0 文章 :: 76 評論 :: 0 Trackbacks

          http://dev.csdn.net/article/48/48512.shtm

           

          帶屬性的標(biāo)簽

          在標(biāo)簽handler中定義屬性

          對于每一個(gè)標(biāo)簽屬性,都必須在標(biāo)簽handler中定義一個(gè)屬性以及符合JavaBean結(jié)構(gòu)規(guī)范的get和set方法。例如,logic:present標(biāo)簽的標(biāo)簽handler

          <logic:present parameter="Clear">

          包含下列聲明和方法:

          protected String parameter = null;
          public String getParameter() {
            return (this.parameter);
          }
          public void setParameter(String parameter) {
            this.parameter = parameter;
          }


          注意,如果屬性命名為id并且標(biāo)簽handler繼承自TagSupport類,那么就不需要定義屬性和set和get方法,因?yàn)樗鼈円呀?jīng)由TagSupport定義了。


          值為String的標(biāo)簽屬性可以指定標(biāo)簽handler可用的隱式對象的一個(gè)屬性。通過向隱式對象的[set|get]Attribute方法傳遞標(biāo)簽屬性值可以訪問一個(gè)隱式對象屬性。這是將腳本變量名傳遞給標(biāo)簽handler的好方式,在這里腳本變量與儲(chǔ)存在頁面上下文中的對象相關(guān)聯(lián)(見隱式對象)。

          attribute元素

          對于每一個(gè)標(biāo)簽屬性,都必須在attribute元素中指定這個(gè)屬性是否是必需的、其值是否可以由表達(dá)式確定、還可能指定屬性的類型。對于靜態(tài)值,類型總是java.lang.String。如果rtexprvalue元素是true或者yes,那么type元素定義會(huì)將任何指定的表達(dá)式的預(yù)期返回類型指定為屬性的值。

          <attribute>
            <name>attr1</name>
            <required>true|false|yes|no</required>
            <rtexprvalue>true|false|yes|no</rtexprvalue>
            <type>fully_qualified_type</type>
          </attribute>

          如果tag屬性不是必需的,那么標(biāo)簽handler應(yīng)該提供一個(gè)默認(rèn)值。

          logic:present標(biāo)簽的tag元素聲明parameter屬性不是必需的(因?yàn)闃?biāo)簽還可以測試是否存在其它實(shí)體,如bean屬性)以及其值可以由運(yùn)行時(shí)表達(dá)式設(shè)置。

          <tag>
            <name>present</name>
            <tag-class>org.apache.struts.taglib.
              logic.PresentTag</tag-class>
            <body-content>JSP</body-content>
            ...
            <attribute>
              <name>parameter</name>
              <required>false</required>
              <rtexprvalue>true</rtexprvalue>
            </attribute>
            ...
          </tag>

          屬性驗(yàn)證

          標(biāo)簽庫的文檔應(yīng)該描述標(biāo)簽屬性的有效值。在轉(zhuǎn)換JSP頁面時(shí),Web容器將強(qiáng)制應(yīng)用每一個(gè)屬性的TLD元素中包含的限制。

          在轉(zhuǎn)換時(shí)還用從TagExtraInfo派生的類的isValid方法驗(yàn)證傳遞給標(biāo)簽的屬性。這個(gè)類也用于提供有關(guān)標(biāo)簽定義的腳本變量的信息(見提供有關(guān)腳本變量的信息)。

          用TagData對象向isValid方法傳遞屬性信息,它包含每一個(gè)標(biāo)簽屬性的屬性-值元組。因?yàn)轵?yàn)證在轉(zhuǎn)換時(shí)發(fā)生,所以在請求時(shí)計(jì)算的屬性值將設(shè)置為TagData.REQUEST_TIME_VALUE。

          <tt:twa attr1="value1"/>標(biāo)簽有下列TLD attribute元素:

          <attribute>
            <name>attr1</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
          </attribute>

          這個(gè)聲明表明attr1的值可以在運(yùn)行時(shí)確定。

          下面的isValid方法檢查attr1的值是否為有效的布爾值。注意由于的attr1值可以在運(yùn)行時(shí)計(jì)算,所以isValid必須檢查標(biāo)簽用戶是否選擇了提供運(yùn)行時(shí)值。

          public class TwaTEI extends TagExtraInfo {
            public boolean isValid(Tagdata data) {
              Object o = data.getAttribute("attr1");
              if (o != null && o != TagData.REQUEST_TIME_VALUE) {
                if (((String)o).toLowerCase().equals("true") ||
                  ((String)o).toLowerCase().equals("false") )
                  return true;
                else
                  return false;
              }
              else
                return true;   }
          }

          帶正文的標(biāo)簽

          標(biāo)簽handler

          帶正文的標(biāo)簽的標(biāo)簽handler根據(jù)標(biāo)簽handler是否需要與正文交互而有不同的實(shí)現(xiàn)。我們說的交互的意思是標(biāo)簽handler讀取或者修改正文的內(nèi)容。

          標(biāo)簽handler不與正文交互

          如果標(biāo)簽handler不需要與正文交互,那么標(biāo)簽handler應(yīng)該實(shí)現(xiàn)Tag接口(或者從TagSupport派生)。如果需要對標(biāo)簽的正文進(jìn)行判斷,那么doStartTag方法就需要返回EVAL_BODY_INCLUDE,否則,它應(yīng)該返回SKIP_BODY。

          如果標(biāo)簽handler需要反復(fù)地判斷正文,那么它就應(yīng)該實(shí)現(xiàn)IterationTag接口或者從TagSupport派生。如果它確定需要再次評估正文,那么它應(yīng)該從doStartTag和doAfterBody方法返回EVAL_BODY_AGAIN。

          標(biāo)簽handler與正文交互

          如果標(biāo)簽handler需要與正文交互,那么標(biāo)簽handler必須實(shí)現(xiàn)BodyTag (或者從BodyTagSupport派生)。這種處理器通常實(shí)現(xiàn)doInitBody和doAfterBody方法。這些方法與由JSP頁面的servlet傳遞給tag handler的正文內(nèi)容交互。

          正文內(nèi)容支持幾種讀取和寫入其內(nèi)容的方法。標(biāo)簽handler可以用正文內(nèi)容的getString或者getReader方法從正文中提取信息,用writeOut(out)方法將正文內(nèi)容寫入一個(gè)輸出流。為writeOut方法提供的writer是用標(biāo)簽handler的getPreviousOut方法得到的。用這個(gè)方法保證標(biāo)簽handler的結(jié)果對于其外圍標(biāo)簽handler是可用的。

          如果需要對標(biāo)簽的正文進(jìn)行判斷,那么doStartTag方法需要返回EVAL_BODY_BUFFERED,否則它就應(yīng)該返回SKIP_BODY。

          doInitBody 方法

          在已經(jīng)設(shè)置正文內(nèi)容之后、但是對它進(jìn)行判斷之前調(diào)用doInitBody方法。一般用這個(gè)方法執(zhí)行所有依賴于正文內(nèi)容的初始化。

          doAfterBody方法

          doAfterBody方法在判斷了正文內(nèi)容之后調(diào)用。

          像doStartTag方法一樣,doAfterBody必須返回指明是否繼續(xù)判斷正文的指示。因此,如果應(yīng)該再次判斷正文,就像實(shí)現(xiàn)枚舉標(biāo)簽的情況,那么doAfterBody應(yīng)該返回EVAL_BODY_BUFFERED,否則doAfterBody應(yīng)該返回SKIP_BODY。

          Release方法

          標(biāo)簽handler應(yīng)該在release方法中重新設(shè)置其狀態(tài)并釋放所有私有資源。

          下面的例子讀取正文的內(nèi)容(它包含一個(gè)SQL查詢)并將它傳遞給一個(gè)執(zhí)行這個(gè)查詢的對象。因?yàn)椴恍枰獙φ脑俅闻袛啵詃oAfterBody返回SKIP_BODY。

          public class QueryTag extends BodyTagSupport {
            public int doAfterBody()
          throws JspTagException {
              BodyContent bc = getBodyContent();
              // get the bc as string
              String query = bc.getString();
              // clean up     bc.clearBody();
              try {
                Statement stmt = connection.createStatement();
                result = stmt.executeQuery(query);
              } catch (SQLException e) {
                throw new JspTagException("QueryTag: " +
                   e.getMessage());
              }
              return SKIP_BODY;
            }
          }

          body-content元素

          對于有正文的標(biāo)簽,必須用body-content元素指定正文內(nèi)容的類型:

          <body-content>JSP|tagdependent</body-content>

          正文內(nèi)容包含自定義和核心標(biāo)簽、腳本元素以及屬于JSP的HTML文字。這是為Struts logic:present標(biāo)簽聲明的值。所有其它類型的正文內(nèi)容——如傳遞給查詢標(biāo)簽的SQL語句,都標(biāo)記為tagdependent。

          注意body-content元素的值不影響標(biāo)簽handler對正文的解讀,這個(gè)元素只是由編寫工具用于呈現(xiàn)正文內(nèi)容。

          定義腳本變量的標(biāo)簽

          標(biāo)簽handler

          標(biāo)簽handler負(fù)責(zé)創(chuàng)建腳本變量引用的對象并設(shè)置到頁面可以訪問的上下文中。它是用pageContext.setAttribute(name, value, scope)或者pageContext.setAttribute(name, value)方法完成這項(xiàng)工作的。通常傳遞給自定義標(biāo)簽的屬性指定腳本變量對象的名字,通過調(diào)用在使用范圍對象中描述的屬性的get方法可以提取這個(gè)名字。

          如果腳本變量的值依賴于在標(biāo)簽handler上下文中出現(xiàn)的一個(gè)對象,那么它可以用pageContext.getAttribute(name, scope)方法提取這個(gè)對象。

          一般的通常過程是標(biāo)簽handler提取腳本變量、對對象執(zhí)行一些處理、再用pageContext.setAttribute(name, object)方法設(shè)置腳本變量的值。

          表16-4總結(jié)了對象可以有的作用域。作用域限制了對象的可訪問性和壽命。

          16-4 對象范圍

          名字

          可訪問性

          壽命

          page

          當(dāng)前頁面

          直到響應(yīng)被返回到用戶或者請求被傳遞給一個(gè)新頁面

          request

          當(dāng)前頁面及所有包含或者轉(zhuǎn)發(fā)頁面

          直到響應(yīng)被返回到用戶

          session

          當(dāng)前請求和所有從同一個(gè)瀏覽器發(fā)出的后續(xù)請求(取決于會(huì)話壽命)

          用戶會(huì)話的壽命

          application

          同一Web應(yīng)用程序的當(dāng)前和所有未來請求

          應(yīng)用程序的壽命

           

          提供有關(guān)腳本變量的信息

          定義腳本變量的標(biāo)簽中描述的例子定義了用于訪問圖書信息的腳本變量:book

          <bean:define id="book"
          name="bookDB" property="bookDetails"
            type="database.BookDetails"/>
          <font color="red" size="+2">
            <%=messages.getString("CartRemoved")%>
            <strong><jsp:getProperty name="book"
                property="title"/></strong>
          <br>&nbsp;<br>
          </font>

          在轉(zhuǎn)換包含這個(gè)標(biāo)簽的JSP頁面時(shí),Web容器會(huì)生成同步腳本變量與由變量引用的對象的代碼。要生成這些代碼,Web容器需要關(guān)于腳本變量的一些信息:

          ·  變量名

          ·  變量類

          ·  變量是否引用新的對象或者是現(xiàn)有對象

          ·  變量的可用性

          有兩種方法提供這種信息:指定variable TLD子元素或者定義tag extra info類并在TLD中包含tei-class元素。用variable元素更簡單,但是靈活性要差一些。

          variable 元素

          variable元素有下列子元素:

          ·  name-given:變量名為常量

          ·  name-from-attribute:一個(gè)屬性的名字,其轉(zhuǎn)換時(shí)(translation-time)值將給出屬性的名字

          必須有name-given或者name-from-attribute之中的一個(gè)。下列子元素是可選的:

          ·  variable-class—變量的完全限定名。默認(rèn)為java.lang.String。

          ·  declare—變量是否引用新對象。默認(rèn)為True。

          ·  scope—定義的腳本變量的作用域。默認(rèn)為NESTED。表16-5描述了腳本變量的可用性以及必須設(shè)置或者重新設(shè)置變量值的方法。

          16-5 腳本變量可用性 

          可用性

          方法

          NESTED

          開始和結(jié)束標(biāo)簽之間

          在實(shí)現(xiàn)BodyTag的標(biāo)簽handler的doInitBody 和doAfterBody方法中,否則,在 doStartTag中

          AT_BEGIN

          從開始標(biāo)簽到頁面的結(jié)束

          在實(shí)現(xiàn)BodyTag的標(biāo)簽handler的doInitBody 和doAfterBody方法中,否則,在 doStartTag和doEndTag中

          AT_END

          在結(jié)束標(biāo)簽之后直到頁面的結(jié)束

          在doEndTag中

          Struts bean:define標(biāo)簽的實(shí)現(xiàn)符合JSP規(guī)范版本1.1,它要求定義tag extra info類。JSP規(guī)范版本1.2增加了variable元素。可以為bean:define標(biāo)簽定義下面的variable元素:

          <tag>
            <variable>
              <name-from-attribute>id</name-from-attribute>
              <variable-class>database.BookDetails</variable-class>
              <declare>true</declare>
              <scope>AT_BEGIN</scope>
            </variable>
          </tag>

          TagExtraInfo

          通過擴(kuò)展類javax.servlet.jsp.TagExtraInfo定義tag extra info類。TagExtraInfo. A TagExtraInfo必須實(shí)現(xiàn)getVariableInfo方法以返回包含下列信息的VariableInfo對象數(shù)組:

          ·  變量名

          ·  變量類

          ·  變量是否引用新對象

          ·  變量可用性

          Web容器向getVariableInfo方法傳遞包含每一個(gè)標(biāo)簽屬性的屬性-值元組的名為data的參數(shù)。這些屬性可以用于為VariableInfo對象提供腳本變量名和類。

          Struts標(biāo)簽庫提供有關(guān)由DefineTei tag extra info類中的bean:define標(biāo)簽創(chuàng)建的腳本變量的信息。由于腳本變量的name (book)和class (database.BookDetails)作為標(biāo)簽屬性傳遞,所以可以用data.getAttributeString方法提取它們,并用于填充VariableInfo構(gòu)造函數(shù)。要使腳本變量book用于頁面的其他地方,book的作用域設(shè)置為AT_BEGIN。

          public class DefineTei extends TagExtraInfo {
            public VariableInfo[] getVariableInfo(TagData data) {
            String type = data.getAttributeString("type");
              if (type == null)
                type = "java.lang.Object";
              return new VariableInfo[] {
                new VariableInfo(data.getAttributeString("id"),
                  type,
                  true,
                  VariableInfo.AT_BEGIN)
              };
            }
          }

          為腳本變量定義的tag extra info類的完全限定名必須在tag元素的tei-class子元素的TLD中聲明。因此,DefineTei的tei-class元素像下面這樣:

          <tei-class>
            org.apache.struts.taglib.bean.DefineTagTei
          </tei-class>

          標(biāo)簽協(xié)同操作

          標(biāo)簽通過共享對象實(shí)現(xiàn)合作。JSP技術(shù)支持兩種類型的對象共享。

          第一種類型要求在頁面上下文中命名和儲(chǔ)存共享的對象(JSP頁面和標(biāo)簽handler都可以訪問的一種隱式對象)。要訪問由另一個(gè)標(biāo)簽創(chuàng)建和命名的對象,標(biāo)簽handler使用pageContext.getAttribute(name, scope)方法。

          在第二種對象共享類型中,由一組嵌入標(biāo)簽中的外圍標(biāo)簽handler創(chuàng)建的對象可以被所有內(nèi)部標(biāo)簽handler訪問。這種形式的對象共享的優(yōu)點(diǎn)是它對對象使用私有命名空間,因此減少了潛在的命名沖突。

          要訪問由外圍標(biāo)簽創(chuàng)建的對象,標(biāo)簽handler必須首先用靜態(tài)方法TagSupport.findAncestorWithClass(from, class)或者TagSupport.getParent方法獲得其外圍標(biāo)簽。在不能保證有特定的嵌入標(biāo)簽handler時(shí)應(yīng)該使用前一個(gè)方法。一旦獲取了上級,那么標(biāo)簽handler就可以訪問所有靜態(tài)或動(dòng)態(tài)創(chuàng)建的對象了。靜態(tài)創(chuàng)建的對象是父標(biāo)簽的成員。私有對象也可以動(dòng)態(tài)創(chuàng)建。這種對象可以用setValue方法儲(chǔ)存在標(biāo)簽 handler中,并用getValue方法獲取它。

          下面的例子展示了同時(shí)支持命名的和私有對象方式共享對象的標(biāo)簽handler。在這個(gè)例子中,查詢標(biāo)簽的handler檢查名為connection的屬性是否已在doStartTag方法中設(shè)置。如果屬性已經(jīng)設(shè)置,那么handler就從頁面上下文中獲取連接對象。否則,標(biāo)簽handler首先獲取外圍標(biāo)簽的標(biāo)簽handler,然后從那個(gè)handler中獲取連接對象。

          public class QueryTag extends BodyTagSupport {
            private String connectionId;
            public int doStartTag()
          throws JspException {
              String cid = getConnection();
              if (cid != null) {
              // there is a connection id, use it
                connection =(Connection)pageContext.
                  getAttribute(cid);
              } else {
                ConnectionTag ancestorTag =
                  (ConnectionTag)findAncestorWithClass(this,
                    ConnectionTag.class);
                if (ancestorTag == null) {
                  throw new JspTagException("A query without
                    a connection attribute must be nested
                    within a connection tag.");
                }
                connection = ancestorTag.getConnection();
              }
            }
          }

          由這個(gè)標(biāo)簽 handler實(shí)現(xiàn)的查詢標(biāo)簽可以以下面任何一種方式使用:

          <tt:connection id="con01" ....>
          ...
          </tt:connection>
          <tt:query id="balances" connection="con01">
            SELECT account, balance FROM acct_table
              where customer_number = <%= request.getCustno()%>
          </tt:query>
            <tt:connection ...>
            <x:query id="balances">
              SELECT account, balance FROM acct_table
                where customer_number = <%= request.getCustno()%>
            </x:query>
          </tt:connection>

          標(biāo)簽handler的TLD必須用下面聲明指明connection屬性是可選的:

          <tag>
            ...
            <attribute>
              <name>connection</name>
              <required>false</required>
            </attribute>
          </tag>

          示例

          本節(jié)中描述的自定義標(biāo)簽展示了在開發(fā)JSP應(yīng)用程序時(shí)會(huì)經(jīng)常遇到的兩個(gè)問題的解決方法:盡可能減少JSP頁面中的Java編程以及保證整個(gè)應(yīng)用程序的共同外觀。在這個(gè)過程中,展示了本章前面討論過的許多類型的標(biāo)簽。

          迭代(Iteration)標(biāo)簽

          構(gòu)建依賴于動(dòng)態(tài)生成的數(shù)據(jù)的頁面內(nèi)容通常需要使用流控制腳本語句。通過將流控制邏輯轉(zhuǎn)換到標(biāo)簽handler中,流控制標(biāo)簽減少了在JSP頁面中需要的腳本量。

          Struts logic:iterate標(biāo)簽從儲(chǔ)存在JavaBeans組件中的集合中獲取對象并將它們指定給腳本變量。標(biāo)簽的正文從腳本變量中提取信息。如果集合中仍有元素,則iterate標(biāo)簽會(huì)再次對正文進(jìn)行判斷。

          JSP頁面

          兩個(gè)Duke's Bookstore應(yīng)用程序頁面catalog.jspshowcart.jsp使用了logic:iterate標(biāo)簽以迭代對象的集合。下面展示了catalog.jsp的一部分。JSP頁面用bookDB bean集合(由property屬性命名)初始化iterate標(biāo)簽。iterate標(biāo)簽在對集合上的每一次迭代中設(shè)置book腳本變量。book變量的bookId屬性作為另一個(gè)腳本變量公開。兩個(gè)變量的屬性都用于動(dòng)態(tài)生成一個(gè)包含到其他頁面的圖書目錄信息的鏈接的表。

          <logic:iterate name="bookDB" property="books"
            id="book" type="database.BookDetails">
            <bean:define id="bookId" name="book" property="bookId"
              type="java.lang.String"/>

              <tr>
            <td bgcolor="#ffffaa">
            <a href="<%=request.getContextPath()%>
              /bookdetails?bookId=<%=bookId%>">
              <strong><jsp:getProperty name="book"
              property="title"/>&nbsp;</strong></a></td>

              <td bgcolor="#ffffaa" rowspan=2>
            <jsp:setProperty name="currency" property="amount"
              value="<%=book.getPrice()%>"/>
            <jsp:getProperty name="currency" property="format"/>
            &nbsp;</td>     <td bgcolor="#ffffaa" rowspan=2>
            <a href="<%=request.getContextPath()%>
              /catalog?Add=<%=bookId%>">
              &nbsp;<%=messages.getString("CartAdd")%>
              &nbsp;</a></td></tr>

              <tr>
            <td bgcolor="#ffffff">
            &nbsp;&nbsp;<%=messages.getString("By")%> <em>
              <jsp:getProperty name="book"
                property="firstName"/>&nbsp;
              <jsp:getProperty name="book"
                property="surname"/> </em> </td> </tr>
          </logic:iterate>

          標(biāo)簽handler

          Struts logic:iterate標(biāo)簽的實(shí)現(xiàn)符合JSP版本1.1規(guī)范的要求,它需要擴(kuò)展BodyTagSupport類。JSP版本1.2規(guī)范添加了簡化迭代性地對正文判斷的編程標(biāo)簽的功能(在不與正文交互的標(biāo)簽handler中描述)。下面的討論是使用這些功能的實(shí)現(xiàn)。

          logic:iterate標(biāo)簽以幾種方式支持集合初始化:用作為標(biāo)簽屬性而提供的集合,或者用作為bean或者bean屬性集合而提供的集合。我們的例子使用后一種方法。doStartTag中的大多數(shù)代碼是關(guān)于構(gòu)建對于一個(gè)對象集合的迭代器的。方法首先檢查是否設(shè)置了handler的集合屬性,如果沒有,則進(jìn)一步檢查bean和property屬性。如果name和property屬性都設(shè)置了,則doStartTag調(diào)用使用JavaBean自省方法的工具方法來獲取集合。一旦確定了集合對象,方法就構(gòu)建迭代器。

          如果迭代器中還有元素,那么doStartTag就設(shè)置腳本變量的值為下一個(gè)元素,然后表明要對這個(gè)正文進(jìn)行判斷,否則就返回SKIP_BODY結(jié)束迭代。

          在判斷完正文后,doAfterBody方法提取正文內(nèi)容并將它寫入輸出流。然后清除正文內(nèi)容對象以便為另一次正文判斷作準(zhǔn)備。如果迭代器還包含元素,那么doAfterBody就再次設(shè)置腳本變量的值為下一個(gè)元素并返回EVAL_BODY_AGAIN以表明應(yīng)該再次對正文進(jìn)行判斷。這樣會(huì)再次執(zhí)行doAfterBody。如果沒有剩余元素了,那么就返回SKIP_BODY終止這個(gè)過程。

          public class IterateTag extends TagSupport {
            protected Iterator iterator = null;
            protected Object collection = null;
            protected String id = null;
            protected String name = null;
            protected String property = null;
            protected String type = null;
            public int doStartTag() throws JspException {
              Object collection = this.collection;
              if (collection == null) {
                try {
                  Object bean = pageContext.findAttribute(name);
                  if (bean == null) {
                    ... throw an exception
                  }
                  if (property == null)
                    collection = bean;
                  else
                    collection =
                      PropertyUtils.
                        getProperty(bean, property);
                  if (collection == null) {
                    ... throw an exception
                  }
                } catch
                  ... catch exceptions thrown
                    by PropertyUtils.getProperty
                }
              }
              // Construct an iterator for this collection
              if (collection instanceof Collection)
                iterator = ((Collection) collection).iterator();
              else if (collection instanceof Iterator)
              iterator = (Iterator) collection;
              ...
              }
              // Store the first value and evaluate,
              // or skip the body if none
              if (iterator.hasNext()) {
                Object element = iterator.next();
                pageContext.setAttribute(id, element);
                return (EVAL_BODY_AGAIN);
              } else
                return (SKIP_BODY);   
          }
            public int doAfterBody() throws JspException {  
             if (bodyContent != null) {
                try {
                  JspWriter out = getPreviousOut();
                  out.print(bodyContent.getString());
                  bodyContent.clearBody();
                } catch (IOException e) {
                  ...
                }
              }
              if (iterator.hasNext()) {
                Object element = iterator.next();
                pageContext.setAttribute(id, element);
                return (EVAL_BODY_AGAIN);
              } else
                return (SKIP_BODY);
              }
            }
          }

          標(biāo)簽額外信息類

          有關(guān)腳本變量的信息是在IterateTei標(biāo)簽額外信息類中提供的。腳本變量的名字和類以標(biāo)簽屬性的形式傳入,并用于加入VariableInfo構(gòu)造函數(shù)。

          public class IterateTei extends TagExtraInfo {
            public VariableInfo[] getVariableInfo(TagData data) {
            String type = data.getAttributeString("type");
            if (type == null)
              type = "java.lang.Object";

              return new VariableInfo[] {
              new VariableInfo(data.getAttributeString("id"),
                type,
                true,
                VariableInfo.AT_BEGIN)     };
            }
          }

          模板標(biāo)簽庫

          模板提供了一種將應(yīng)用程序中每一屏幕都會(huì)出現(xiàn)的共用元素與每一屏幕都會(huì)改變的元素分離開來的方法。將所有公共元素一起放到一個(gè)文件中更容易進(jìn)行維護(hù),并可以加強(qiáng)所有屏幕的外觀一致性。它還使每一屏幕的開發(fā)更容易了,因?yàn)殚_發(fā)者只要注重于該屏幕特定的那部分內(nèi)容就可以了,模板會(huì)負(fù)責(zé)公共部分。

          模板是JSP頁面,在每一屏幕需要改變的地方有占位符。每一個(gè)占位符稱為模板的參數(shù)。例如,一個(gè)簡單的模板可能包含在生成的屏幕頂部的一個(gè)標(biāo)題參數(shù)和JSP頁面的正文參數(shù)以設(shè)定屏幕的定制內(nèi)容。

          模板使用嵌入的標(biāo)簽——definition、screen和parameter——定義屏幕定義表并使用標(biāo)簽將屏幕定義插入到特定應(yīng)用程序屏幕。

          JSP頁面

          下面展示Duke's Bookstore例子的模板template.jsp。這一頁面包括一個(gè)創(chuàng)建屏幕定義、并用insert標(biāo)簽將定義中的參數(shù)插入應(yīng)用程序屏幕的JSP頁面。

          <%@ taglib uri="/tutorial-template.tld" prefix="tt" %>
          <%@ page errorPage="errorpage.jsp" %>
          <%@ include file="screendefinitions.jsp" %><html>
            <head>
              <title>
                <tt:insert definition="bookstore"
                  parameter="title"/>
              </title>   </head>
              <tt:insert definition="bookstore"
                parameter="banner"/>
              <tt:insert definition="bookstore"
                parameter="body"/>
            </body>
          </html>

          screendefinitions.jsp根據(jù)請求屬性selectedScreen創(chuàng)建屏幕定義:

          <tt:definition name="bookstore"
            screen="<%= (String)request.
              getAttribute(\"selectedScreen\") %>">
            <tt:screen id="/enter">
              <tt:parameter name="title"
                value="Duke's Bookstore" direct="true"/>
              <tt:parameter name="banner"
                value="/banner.jsp" direct="false"/>
              <tt:parameter name="body"
                value="/bookstore.jsp" direct="false"/>
            </tt:screen>
            <tt:screen id="/catalog">
              <tt:parameter name="title"
              value="<%=messages.getString("TitleBookCatalog")%>"
              direct="true"/>
              ...
          </tt:definition>

          模板由Dispatcher servlet實(shí)例化。Dispatcher首先得到所請求的屏幕并將它儲(chǔ)存為請求的屬性。這是必要的,因?yàn)樵谙騮emplate.jsp轉(zhuǎn)發(fā)請求時(shí),請求URL不包含原來的請求(如/bookstore3/catalog),而是反映轉(zhuǎn)發(fā)布頁面的路徑(/bookstore3/template.jsp)。最后,servlet將請求分發(fā)給template.jsp:

          public class Dispatcher extends HttpServlet {
            public void doGet(HttpServletRequest request,
                HttpServletResponse response) {
              request.setAttribute("selectedScreen",
                request.getServletPath());
              RequestDispatcher dispatcher =
                request.getRequestDispatcher("/template.jsp");
              if (dispatcher != null)
                dispatcher.forward(request, response);
            }   public void doPost(HttpServletRequest request,
                  HttpServletResponse response) {
              request.setAttribute("selectedScreen",
                request.getServletPath());
              RequestDispatcher dispatcher =
                request.getRequestDispatcher("/template.jsp");
              if (dispatcher != null)
                dispatcher.forward(request, response);
            }
          }

          標(biāo)簽handler

          模板標(biāo)簽庫包含四個(gè)標(biāo)簽handler——DefinitionTag、ScreenTag、ParameterTag和InsertTag,它們展示了協(xié)同操作標(biāo)簽的使用。DefinitionTag、ScreenTag和ParameterTag組成了一組嵌入的標(biāo)簽handler,它們共享公共(public)和私有(private)對象。DefinitionTag創(chuàng)建由InsertTag使用的名為definition的公共對象,

          在doStartTag中,DefinitionTag創(chuàng)建一個(gè)名為screens的公共對象,它包含屏幕定義的一個(gè)哈希表。屏幕定義包含屏幕標(biāo)識(shí)符和一組與該屏幕相關(guān)聯(lián)的參數(shù)。

          public int doStartTag() {
            HashMap screens = null;
            screens = (HashMap) pageContext.getAttribute("screens",
              pageContext.APPLICATION_SCOPE);
            if (screens == null)
              pageContext.setAttribute("screens", new HashMap(),
                pageContext.APPLICATION_SCOPE);
            return EVAL_BODY_INCLUDE; }

          ScreenTag和ParameterTag用作為這些標(biāo)簽屬性提供的文字填充屏幕定義表。

          16-6 屏幕定義

          屏幕Id

          標(biāo)題

          橫幅

          正文

          /enter

          Duke's Bookstore

          /banner.jsp

          /bookstore.jsp

          /catalog

          Book Catalog

          /banner.jsp

          /catalog.jsp

          /bookdetails

          Book Description

          /banner.jsp

          /bookdetails.jsp

          /showcart

          Shopping Cart

          /banner.jsp

          /showcart.jsp

          /cashier

          Cashier

          /banner.jsp

          /cashier.jsp

          /receipt

          Receipt

          /banner.jsp

          /receipt.jsp

          .

          在doEndTag中,DefinitionTag創(chuàng)建Definition類的一個(gè)公共對象,根據(jù)在請求中傳遞的URL從screens對象中選擇一個(gè)屏幕定義,并用它初始化Definition對象。

          public int doEndTag()throws JspTagException {
            try {
              Definition definition = new Definition();
              HashMap screens = null;
              ArrayList params = null;
              TagSupport screen = null;
              screens = (HashMap)
                pageContext.getAttribute("screens",
                  pageContext.APPLICATION_SCOPE);
              if (screens != null)
                params = (ArrayList) screens.get(screenId);
              else
                ...
              if (params == null)
                ...
              Iterator ir = null;
              if (params != null)
                ir = params.iterator();
              while ((ir != null) && ir.hasNext())
                definition.setParam((Parameter) ir.next());
                // put the definition in the page context
              pageContext.setAttribute(
                definitionName, definition);
            } catch (Exception ex) {
              ex.printStackTrace();
            }   return EVAL_PAGE;
          }

          如果在請求中傳遞的URL是/enter,那么Definition包含表16-6中第一行的項(xiàng)目:

          標(biāo)題

          橫幅

          正文

          Duke's Bookstore

          /banner.jsp

          /bookstore.jsp

          URL /enter的定義如

          16-7 URL /enter 的屏幕定義

          參數(shù)名

          參數(shù)值

          isDirect

          title

          Duke's Bookstore

          true

          banner

          /banner.jsp

          false

          body

          /bookstore.jsp

          false

          InsertTag使用Definition將屏幕定義的參數(shù)插入響應(yīng)中。在doStartTag方法中,它從頁面上下文中獲取定義對象。

          public int doStartTag() {
            // get the definition from the page context
            definition = (Definition) pageContext.
              getAttribute(definitionName);
            // get the parameter
            if (parameterName != null && definition != null)
              parameter = (Parameter)definition.
                getParam(parameterName);
            if (parameter != null)
              directInclude = parameter.isDirect();
            return SKIP_BODY;
          }

          doEndTag方法插入?yún)?shù)值。如果參數(shù)是直接的,那么就直接將它插入響應(yīng)中,否則,請求就被發(fā)送給參數(shù),而其響應(yīng)則被動(dòng)態(tài)地包含進(jìn)整個(gè)響應(yīng)中。

          public int doEndTag()throws JspTagException {
            try {
              if (directInclude && parameter != null)
                pageContext.getOut().print(parameter.getValue());
              else {
                if ((parameter != null) &&
                  (parameter.getValue() != null))
                  pageContext.include(parameter.getValue());
              }
            } catch (Exception ex) {
              throw new JspTagException(ex.getMessage());
            }
            return EVAL_PAGE;
          }

          如何調(diào)用標(biāo)簽handler?

          Tag接口定義了標(biāo)簽handler與JSP頁面的servlet之間的基本協(xié)議。它定義了生命周期以及在遇到開始和結(jié)束標(biāo)簽時(shí)要調(diào)用的方法。

          JSP頁面的servlet在調(diào)用doStartTag之前調(diào)用setPageContext、setParent和屬性設(shè)置方法。JSP頁面的servlet還保證在結(jié)束頁面之前調(diào)用標(biāo)簽handler的release。

          下面是典型的標(biāo)簽handler方法調(diào)用順序:

          A Tag t = new ATag();
          t.setPageContext(...);
          t.setParent(...);
          t.setAttribute1(value1);
          t.setAttribute2(value2);
          t.doStartTag();
          t.doEndTag();
          t.release();

          BodyTag接口通過定義讓標(biāo)簽handler訪問其正文的其他方法擴(kuò)展Tag。這個(gè)接口提供三個(gè)新方法:

          ·  setBodyContent—?jiǎng)?chuàng)建正文內(nèi)容并添加給tag handler

          ·  doInitBody—在評估標(biāo)簽正文之前調(diào)用

          ·  doAfterBody—在評估標(biāo)簽正文之后調(diào)用

          典型的調(diào)用順序?yàn)椋?

          t.doStartTag();
          out = pageContext.pushBody();
          t.setBodyContent(out);
          // perform any initialization needed after body content is set t.doInitBody();
          t.doAfterBody();
          // while doAfterBody returns EVAL_BODY_BUFFERED we
          // iterate body evaluation
          ...
          t.doAfterBody();
          t.doEndTag();
          t.pageContext.popBody();
          t.release();

          posted on 2005-04-13 16:09 笨笨 閱讀(1349) 評論(0)  編輯  收藏 所屬分類: J2EEALLJ2SE
          主站蜘蛛池模板: 冕宁县| 绥滨县| 长武县| 武冈市| 龙游县| 曲松县| 隆化县| 黄浦区| 灵石县| 始兴县| 资源县| 湟源县| 怀远县| 台北县| 进贤县| 哈尔滨市| 贞丰县| 鲁山县| 襄汾县| 五家渠市| 益阳市| 万宁市| 谷城县| 嘉祥县| 乌苏市| 板桥市| 竹溪县| 乐陵市| 杭州市| 弥勒县| 南和县| 稷山县| 鄯善县| 潞西市| 廉江市| 阿克苏市| 大兴区| 台州市| 修武县| 新泰市| 呼伦贝尔市|