隨筆-26  評論-13  文章-46  trackbacks-0

          學(xué)習(xí)如何使用簡單標(biāo)記 API 和構(gòu)建用于求解 JSP 表達(dá)式的定制標(biāo)記,如何控制 JSP 頁面中的流以及如何創(chuàng)建 Java 集合。

          本文相關(guān)下載:
          · 示例代碼
          · OC4J 10g 開發(fā)人員預(yù)覽版 2
          · JSTL 1.1

          JavaServer Pages (JSP) 和 JSP 標(biāo)準(zhǔn)標(biāo)記庫 (JSTL) 為 Web 開發(fā)人員提供了許多有用的標(biāo)記(也稱作操作)。此外,JSP 2.0 還提供兩個(gè) API,即標(biāo)準(zhǔn)標(biāo)記 API 和簡單標(biāo)記 API,用于構(gòu)建定制標(biāo)記/操作。前一個(gè) API 繼承自 JSP 1.x,并由于歷史原因而由 JSTL 使用。(由于 JSTL 1.0 的開發(fā)在 JSP 2.0 之前,因此新 API 不包含 JSTL 1.1。)此外,JSTL 也不使用 JSP 片段和動態(tài)屬性等 JSP 新特性。本文使用 JSP 2.0 的新 API 和特性構(gòu)建定制標(biāo)記擴(kuò)展 JSTL。本文提供 API 概述并演示如何開發(fā)

          • 導(dǎo)出變量的標(biāo)記
          • 條件標(biāo)記
          • 迭代標(biāo)記
          • 具有動態(tài)屬性的標(biāo)記
          • 協(xié)調(diào)標(biāo)記

          簡單標(biāo)記 API 概述

          在 JSP 頁面中使用定制標(biāo)記時(shí),應(yīng)用服務(wù)器的 JSP 容器將 <prefix:customTag> ...</prefix:customTag> 轉(zhuǎn)換為調(diào)用稱為標(biāo)記處理類的方法的 Java 代碼。因此,如果要開發(fā)定制標(biāo)記,必須提供一個(gè)標(biāo)記處理類,此類必須使用 JSP 1.x 標(biāo)準(zhǔn)標(biāo)記 API 或 JSP 2.0 簡單標(biāo)記 API。比較一下這兩個(gè) API,就會發(fā)現(xiàn)新 API 更易于使用。簡單標(biāo)記 API 只有一個(gè)接口 (javax.servlet.jsp.tagext.SimpleTag),它定義了處理定制標(biāo)記的方法。通常從 JSP 容器從 JSP 頁面中自動生成的 Java Servlet 中調(diào)用這些方法。

          javax.servlet.jsp.tagext.SimpleTagSupport 類實(shí)現(xiàn)了 SimpleTag 接口,因此當(dāng)標(biāo)記處理類擴(kuò)展 SimpleTagSupport 時(shí)只須編寫 doTag() 方法即可。以下步驟介紹了如何開發(fā)一個(gè)簡單的標(biāo)記處理類:

          第 1 步:設(shè)計(jì)定制標(biāo)記
          首先,必須為標(biāo)記選擇一個(gè)名稱并設(shè)置它的屬性。然后,創(chuàng)建一個(gè)標(biāo)記庫描述符 (TLD) 文件(采用由 JSP 規(guī)范定義的 XML 格式),以告知 JSP 容器如何處理和驗(yàn)證定制標(biāo)記。文本提供了一個(gè)名為 util.tld 的示例 TLD 文件。

          第 2 步:創(chuàng)建標(biāo)記處理類
          必須提供一個(gè)用于實(shí)現(xiàn) SimpleTag 接口的 Java 類。最簡單的方法是擴(kuò)展 SimpleTagSupport 或它的某個(gè)子類。本文中的 VarTagSupport、IfTagWhileTag 類用于擴(kuò)展 SimpleTagSupport。其他標(biāo)記處理類示例擴(kuò)展 VarTagSupport

          如果要使用未在 TLD 文件中指定的屬性,則標(biāo)記處理類必須實(shí)現(xiàn) javax.servlet.jsp.tagext.DynamicAttributes 接口(如“具有動態(tài)屬性的標(biāo)記”部分中介紹的 MapTag 示例所示)。

          第 3 步:初始化標(biāo)記處理類實(shí)例
          每個(gè)標(biāo)記處理類都必須包含一個(gè)不帶參數(shù)的公共構(gòu)造函數(shù),用于放置初始化代碼。本文中的某些標(biāo)記處理類(EvalTag、ListTagMapTag)包含一個(gè)無參數(shù)的公共構(gòu)造函數(shù),它使用默認(rèn)值初始化實(shí)例變量。其他類(IfTag、WhileTagItemTag)沒有構(gòu)造函數(shù)。請注意,Java 編譯器在類不包含任何構(gòu)造函數(shù)的情況下自動生成一個(gè)無參數(shù)的公共構(gòu)造函數(shù),該函數(shù)不執(zhí)行任何操作。

          第 4 步:提供屬性設(shè)置方法
          JSP 頁面中的標(biāo)記屬性值通過 setAttribute() 方法傳遞給標(biāo)記處理類。例如,本文中的 <u:eval> 標(biāo)記包含四個(gè)屬性:var、scope、exprtypeEvalTag 處理類實(shí)現(xiàn) setExpr()setType() 方法,并從 VarTagSupport 繼承 setVar()setScope()

          動態(tài)屬性通過 DynamicAttributes 接口定義的 setDynamicAttribute() 方法傳遞。

          第 5 步:實(shí)現(xiàn) doTag() 方法
          該方法用于實(shí)現(xiàn)定制標(biāo)記的邏輯。doTag() 方法由 JSP 容器繼所有屬性設(shè)置方法之后調(diào)用。此處可以使用 getJspContext() 獲得一個(gè) javax.servlet.jsp.JspContext 對象來訪問 JSP 環(huán)境。可以調(diào)用 getJspBody(),它返回 javax.servlet.jsp.tagext.JspFragment 的實(shí)例,該實(shí)例表示位于 <prefix:customTag></prefix:customTag> 之間的 JSP 主體。如果要開發(fā)協(xié)同工作的標(biāo)記,如 <u:list><u:item>(本文的最后一部分將對其進(jìn)行介紹),則還可以使用 getParent()findAncestorWithClass() 方法。

          第 6 步:測試定制標(biāo)記
          使用定制標(biāo)記的 JSP 頁面必須使用 <%@taglib%> 指令導(dǎo)入該標(biāo)記的標(biāo)記庫。當(dāng)定制標(biāo)記出現(xiàn)在 JSP 頁面中時(shí),JSP 容器將生成創(chuàng)建標(biāo)記處理類實(shí)例、調(diào)用屬性設(shè)置方法和調(diào)用 doTag() 方法的代碼。因此,在使用定制標(biāo)記的 JSP 頁面的執(zhí)行過程中將調(diào)用標(biāo)記處理類方法。

          限制和變通方法

          為簡化標(biāo)記處理 API,JSP 2.0 采取了一個(gè)限制:如果定制標(biāo)記的處理類是基于簡單標(biāo)記 API 的,則頁面作者不得在 <prefix:customTag></prefix:customTag> 之間使用 JSP 1.x 聲明 (<%!...%>)、JSP 1.x 表達(dá)式 (<%=...%>) 和 scriptlet (<%...%>)。大多數(shù)情況下,您可以將 JSP 頁面中的 Java 代碼移動到標(biāo)記處理類中,或在 JSP 2.0 表達(dá)式 (${...})(可以在定制標(biāo)記的主體中使用)中使用 JSTL。請注意,JSP 2.0 允許您在基于標(biāo)準(zhǔn)標(biāo)記 API 的定制標(biāo)記主體中使用 scriptlet。然而,由于不使用腳本的 JSP 頁面更易于維護(hù),因此最好避免在 Web 頁中使用 Java 代碼。

          我的上一篇 Oracle 技術(shù)網(wǎng) (OTN) 文章“使用 JSP 2.0 EL API”介紹了簡單標(biāo)記 API 的另一個(gè)限制并提供了變通方法。JspContext 類未提供對 JSP 隱式對象(如application、session、requestresponse)的訪問。大多數(shù)應(yīng)用服務(wù)器(包括 Oracle Application Server Containers for J2EE (OC4J) 10g)允許將 JSP 上下文轉(zhuǎn)換為 PageContext

          標(biāo)記處理類不適用于使用 println() 語句生成大量可重用的 HTML 代碼。JSP 2.0 為此工作提供了一個(gè)更好的方法。所謂的標(biāo)記文件使用 JSP 語法并由 JSP 容器自動轉(zhuǎn)換為基于簡單標(biāo)記 API 的標(biāo)記處理類。我的另一篇 OTN 文章“創(chuàng)建 JSP 2.0 標(biāo)記文件”介紹了這個(gè) JSP 新特性。

          導(dǎo)出變量的標(biāo)記

          許多 JSTL 標(biāo)記實(shí)現(xiàn)某個(gè)邏輯并導(dǎo)出 JSP 變量以報(bào)告結(jié)果。例如,<sql:query> 包含一個(gè) var 屬性,該屬性必須指定用于保存 SQL 結(jié)果集的 JSP 變量的名稱。var 屬性對其他 JSTL 標(biāo)記(如 <fmt:formatNumber><fmt:formatDate>)來說是可選的。如果 var 屬性不存在,則這些標(biāo)記將輸出它們的結(jié)果。所有包含 var 屬性的標(biāo)記還包含一個(gè) scope 屬性,該屬性可用于指示以下 JSP 變量的作用域:page、request、sessionapplication

          VarTagSupport 類(它是為本文開發(fā)的一個(gè)示例)擴(kuò)展 SimpleTagSupport 并為 varscope 屬性提供設(shè)置方法。VarTagSupport 包含用于導(dǎo)出 JSP 變量、獲取主體內(nèi)容和輸出內(nèi)容的實(shí)用方法,而不是實(shí)現(xiàn) doTag() 方法。這些方法由 VarTagSupport 的子類在 doTag()使用。本文包含四個(gè)用于擴(kuò)展 VarTagSupport 的標(biāo)記處理類(EvalTag、MapTag、ListTagItemTag)。

          請注意,JSP 變量在 JSTL 規(guī)范中稱作范圍變量,而在 JSP 規(guī)范中稱作具名變量或范圍屬性。這些變量通過 JspContext 類的 setAttribute() 方法創(chuàng)建/導(dǎo)出。您可以在 JSP 頁面中使用 ${varName},以及在 Java 代碼中使用 JspContextgetAttribute()findAttribute() 方法取得它們的值。不要混淆 JSP 變量與標(biāo)記屬性。

          實(shí)現(xiàn)屬性設(shè)置方法

          JSP 容器調(diào)用屬性設(shè)置方法,將標(biāo)記屬性的值傳遞給定制標(biāo)記處理類。VarTagSupportsetVar() 方法將 var 屬性的值存儲在受保護(hù)的實(shí)例變量 (varName) 中。setScope() 方法將它的參數(shù)轉(zhuǎn)換為整數(shù)常數(shù)。如果該參數(shù)包含有效值(page、request、session application),則將此整數(shù)常數(shù)存儲在另一受保護(hù)的實(shí)例變量 (varScope) 中。否則,setScope() 將拋出 JspException

          package jsputils.tags;
          
          import javax.servlet.jsp.JspException;
          import javax.servlet.jsp.PageContext;
          import javax.servlet.jsp.tagext.SimpleTagSupport;
          ...
          
          public class VarTagSupport extends SimpleTagSupport {
          protected String varName;
          protected int varScope;
          
          protected VarTagSupport() {
          varScope = PageContext.PAGE_SCOPE;
              }
          
          public void setVar(String name) throws JspException {
          varName = name;
              }
          
          public void setScope(String scope) throws JspException {
          if (scope.equalsIgnoreCase("page"))
          varScope = PageContext.PAGE_SCOPE;
          else if (scope.equalsIgnoreCase("request"))
          varScope = PageContext.REQUEST_SCOPE;
          else if (scope.equalsIgnoreCase("session"))
          varScope = PageContext.SESSION_SCOPE;
          else if (scope.equalsIgnoreCase("application"))
          varScope = PageContext.APPLICATION_SCOPE;
          else
          throw new JspException("Invalid scope:" + scope);
              }
              ...
          }
          

          將變量導(dǎo)出到 JSP 環(huán)境

          如果 var 屬性存在,并具有非 null 值 (varName != null),則 export() 方法使用 getJspContext() 取得 JSP 上下文。隨后,如果 value 參數(shù)不為 null,則 export() 將使用 JSP 上下文的 setAttribute() 方法設(shè)置 JSP 變量。可以在 JSP 頁面中使用 ${varName} 取得變量值。如果 value 參數(shù)為 null,則 export() 將調(diào)用 removeAttribute(),后者從給定的范圍中刪除任何具有給定名稱的現(xiàn)有變量。

          如果 var 屬性不存在或具有 null 值,則 export() 方法將返回 false。否則,export() 將返回 true

          package jsputils.tags;
          
          import javax.servlet.jsp.JspContext;
          import javax.servlet.jsp.tagext.SimpleTagSupport;
          ...
          
          public class VarTagSupport extends SimpleTagSupport {
              ...
          protected boolean export(Object value) {
          if (varName == null)
          return false;
          JspContext jspContext = getJspContext();
          if (value != null)
          jspContext.setAttribute(varName, value, varScope);
          else
          jspContext.removeAttribute(varName, varScope);
          return true;
              }
              ...
          }
          

          取得由標(biāo)記主體生成的內(nèi)容

          標(biāo)記處理類可以使用從 SimpleTagSupport 繼承的 SimpleTagSupport 方法取得表示所處理 JSP 標(biāo)記主體的 JspFragment。然后,標(biāo)記處理類可以使用 invoke() 方法執(zhí)行 JSP 片段;如果要捕獲由 JSP 主體生成的內(nèi)容,則該方法需要 java.io.Writer 參數(shù)。invokeBody() 方法將這些操作分組,并返回 String 類型的主體內(nèi)容:

          package jsputils.tags;
          
          import javax.servlet.jsp.JspException;
          import javax.servlet.jsp.tagext.JspFragment;
          import javax.servlet.jsp.tagext.SimpleTagSupport;
          ...
          import java.io.StringWriter;
          import java.io.IOException;
          
          public class VarTagSupport extends SimpleTagSupport {
              ...
          protected String invokeBody() throws JspException {
          JspFragment body = getJspBody();
          StringWriter buffer = new StringWriter();
          try {
          body.invoke(buffer);
          } catch (IOException x) {
          throw new JspException(x);
                  }
          return buffer.toString();
              }
              ...
          }
          

          請注意,如果只想輸出由 JSP 主體生成的內(nèi)容,則可以使用 null 參數(shù)調(diào)用 invoke() 方法。如果不調(diào)用 invoke(),則不執(zhí)行定制標(biāo)記的 JSP 主體。

          在標(biāo)記執(zhí)行過程中生成內(nèi)容

          標(biāo)記處理類可以使用由 JSP 上下文的 getOut() 方法返回的 JspWriter 輸出內(nèi)容:

          package jsputils.tags;
          
          import javax.servlet.jsp.JspContext;
          import javax.servlet.jsp.JspException;
          import javax.servlet.jsp.JspWriter;
          import javax.servlet.jsp.tagext.SimpleTagSupport;
          ...
          import java.io.IOException;
          
          public class VarTagSupport extends SimpleTagSupport {
              ...
          protected void write(String str) throws JspException {
          JspContext jspContext = getJspContext();
          JspWriter out = jspContext.getOut();
          try {
          out.write(str);
          } catch (IOException x) {
          throw new JspException(x);
                  }
              }
          
          }
          

          開發(fā)導(dǎo)出變量的定制標(biāo)記

          “使用 JSP 2.0 EL API”介紹了名為 ELUtils 的類的開發(fā),該類的方法在 Java 代碼中求解 JSP 表達(dá)式。當(dāng)您要在 JSP 頁面外使用 EL時(shí)(如在 XML 文件中使用),EL API 將很有幫助。在“使用 JSP 2.0 EL API”中,我們將 ELUtils 的靜態(tài)方法映射為 EL 函數(shù)。這次,我們將構(gòu)建一個(gè)定制標(biāo)記 (<u:eval>),它調(diào)用 ELUtils 的某個(gè) evaluate() 方法。<u:eval> 標(biāo)記由名為 EvalTag 的類處理,該類為 <u:eval> 的屬性實(shí)現(xiàn)兩個(gè)設(shè)置方法(setExpr()setType())。屬性 exprtype 的值被傳遞給 evaluate() 方法,該方法返回表達(dá)式的值。

          如果 expr 屬性不存在,則 doTag() 方法將調(diào)用從 VarTagSupport 類繼承的 invokeBody() 方法以取得主體內(nèi)容(應(yīng)為表達(dá)式)。因此,調(diào)用 <u:eval> 標(biāo)記的 JSP 頁面可以將表達(dá)式指定為 expr 屬性的值或置于 <u:eval></u:eval>之間。

          EvalTag 類擴(kuò)展了 VarTagSupport,這是因?yàn)樗枰?export(),以便使用 var 屬性指定的名稱和由 evaluate() 返回的值創(chuàng)建 JSP 變量。如果 var 屬性不存在,則 export() 無法設(shè)置變量并返回 false。這種情況下,EvalTag 使用從 VarTagSupport 繼承的 write() 方法輸出所求解表達(dá)式的值。

          EvalTag 處理類的源代碼如下所示:

          package jsputils.tags;
          
          import jsputils.el.ELUtils;
          
          import javax.servlet.jsp.JspException;
          
          public class EvalTag extends VarTagSupport {
          private String strExpr;
          private Object varType;
          
          public EvalTag() {
          varType = Object.class;
              }
          
          public void setExpr(String expr) throws JspException {
          strExpr = expr;
              }
          
          public void setType(Object type) throws JspException {
          varType = type;
              }
          
          protected Object evaluate(String expression,
          Object expectedType) throws JspException {
          return ELUtils.evaluate(
          expression, expectedType, getJspContext());
              }
          
          public void doTag() throws JspException {
          if (strExpr == null)
          strExpr = invokeBody();
          Object value = evaluate(strExpr, varType);
          boolean exported = export(value);
          if (!exported && value != null)
          write(value.toString());
              }
          
          }
          

          在庫描述符中定義定制標(biāo)記

          <u:eval> 標(biāo)記定義在名為 util.tld 的 XML 文件中。JSP 容器使用此文件將定制標(biāo)記映射為它的處理類 (EvalTag)。除標(biāo)記的名稱和標(biāo)記處理類外,該描述符還包含有關(guān)標(biāo)記主體和屬性的信息。

          主體內(nèi)容被聲明為 scriptless,這意味著不能在 <u:eval></u:eval> 之間使用 Java 代碼 (scriptlet)。如果標(biāo)記不使用它的主體內(nèi)容,則應(yīng)指定 empty 而非 scriptless。請注意,對于標(biāo)準(zhǔn)標(biāo)記,還可以指定 JSP,它允許在標(biāo)記的主體中使用 Java scriptlet。基于簡單標(biāo)記 API 開發(fā)處理類時(shí),必須將所有 Java 代碼置于 Java 類中。

          util.tld 描述符為 <u:eval> 標(biāo)記定義了四個(gè)屬性:expr、type、varscope。所有屬性都被聲明為可選(requiredfalse)。expr 和 type 的值可以包含 JSP 表達(dá)式(rtexprvaluetrue),但 varscope 屬性必須具有固定值(rtexprvaluefalse)。

          定制標(biāo)記在 <taglib> 元素中描述,該元素包含版本號、短名稱(前綴)和統(tǒng)一資源標(biāo)識符 (URI)(不一定指示現(xiàn)有 Web 資源):

          <?xml version="1.0" encoding="UTF-8" ?>
          
          <taglib 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-jsptaglibrary_2_0.xsd"
          version="2.0">
          
          <tlib-version>1.0</tlib-version>
          <short-name>u</short-name>
          <uri>http://otn.oracle.com/jsp/taglib/util.tld</uri>
          
          <tag>
          <name>eval</name>
          <tag-class>jsputils.tags.EvalTag</tag-class>
          <body-content>scriptless</body-content>
          <attribute>
          <name>expr</name>
          <required>false</required>
          <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
          <name>type</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          <attribute>
          <name>var</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          <attribute>
          <name>scope</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          </tag>
              ...
          </taglib>
          

          在 JSP 頁面中使用定制標(biāo)記

          示例 Web 應(yīng)用程序的 web.xml 描述符定義了兩個(gè)參數(shù):debug_modetags_db_dataSourcedebug_mode 參數(shù)指示應(yīng)用程序是運(yùn)行在測試環(huán)境中還是運(yùn)行在生產(chǎn)環(huán)境中。tags_db_dataSource 參數(shù)使用 EL 根據(jù) debug_mode 的值選擇數(shù)據(jù)源名稱:

          <?xml version="1.0" encoding="ISO-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">
          
          <context-param>
          <param-name>debug_mode</param-name>
          <param-value>true</param-value>
          </context-param>
          
          <context-param>
          <param-name>tags_db_dataSource</param-name>
          <param-value>jdbc/${
          initParam.debug_mode ?"dbtags" :"production"
          }</param-value>
          </context-param>
          
          </web-app>
          

          使用 <%@taglib%> 導(dǎo)入本文的標(biāo)記庫后,EvalTest.jsp 頁面將使用 <u:eval> 標(biāo)記求解 web.xml 文件中的表達(dá)式:

          <!-- EvalTest.jsp -->
          
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <u:eval expr="${initParam.tags_db_dataSource}" var="db"/>
          ${db}
          
          <u:eval expr="${initParam.tags_db_dataSource}"/>
          
          <u:eval>${initParam.tags_db_dataSource}</u:eval>
          

          該 JSP 頁面測試兩種指定表達(dá)式的方法:使用 expr 屬性以及置于 <u:eval></u:eval> 之間。var 屬性用于創(chuàng)建名為 db 的 JSP 變量,它的值使用 ${db} 輸出。如果 var 屬性不存在,則 <u:eval> 標(biāo)記輸出所求解表達(dá)式的值。以下是 EvalTest.jsp 生成的輸出:

          jdbc/dbtags jdbc/dbtags jdbc/dbtags 
          

          條件標(biāo)記

          JSTL 提供了幾個(gè)條件標(biāo)記(<c:if>、<c:choose>、<c:when><c:otherwise>)以及一個(gè)用于捕獲 JSP 頁面中異常的標(biāo)記 (<c:catch>)。這些標(biāo)記雖然簡單、有用,但并非得益于 JSP 2.0 的片段屬性特性,該特性允許單個(gè)標(biāo)記處理多個(gè) JSP 片段。本文的此部分使用片段屬性構(gòu)建一個(gè)更復(fù)雜的名為 <u:if> 并由 IfTag 類處理的條件標(biāo)記。IfTag 示例還演示了如何捕獲在 JSP 片段執(zhí)行過程中可能發(fā)生的任何異常。

          使用片段屬性

          假設(shè)有一個(gè)包含兩個(gè)文本域(unitPricequantity)的表單,需要計(jì)算總價(jià)。還需要處理用戶未填寫表單或提供非數(shù)字值(可能生成 NumberFormatException)的情況。在實(shí)際應(yīng)用程序中,可能會使用框架(如 JavaServer Faces (JSF))生成 HTML 表單和驗(yàn)證用戶輸入。但為了測試本部分中開發(fā)的條件標(biāo)記,假設(shè)要創(chuàng)建不使用專用標(biāo)記庫的表單。以下是要使用的代碼:

           
          <!-- IfTest.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <html>
          <body>
          <form method="post">
          
          <c:set var="paramsProvided"
          value="${!empty param.unitPrice and !empty param.quantity}"/>
          ...
          
          <p> Unit Price:
          <input type="text" name="unitPrice" size="10"
          value="<c:out value='${param.unitPrice}'/>">
          <p> Quantity:
          <input type="text" name="quantity" size="10"
          value="<c:out value='${param.quantity}'/>">
          <p> <input type="submit" value="Calculate Price">
          
          </form>
          </body>
          </html>
          

          以下代碼演示了如何使用 JSTL 的 <c:if><c:catch> 標(biāo)記驗(yàn)證表單數(shù)據(jù):

          <c:if test="${paramsProvided}">
          <c:catch var="error">
          <c:set var="price"
          value="${param.unitPrice * param.quantity}"/>
          <p> Price:${price}
          </c:catch>
          </c:if>
          <c:if test="${not paramsProvided}">
          <p> Please fill out the form
          </c:if>
          <c:if test="${error != null}">
          <p> Number format error
          </c:if>
          

          前面的代碼段不是 IfTest.jsp 的一部分。該頁面使用定制標(biāo)記 <u:if>(包含 test 屬性,如 <c:if>)而不是使用 JSTL 驗(yàn)證表單數(shù)據(jù)。<u:if> 標(biāo)記包含三個(gè)條件屬性,即 TRUE、FALSEERROR。這些屬性的值是由 <jsp:attribute> 標(biāo)準(zhǔn)操作包含的 JSP 片段:

          <u:if test="${paramsProvided}">
          <jsp:attribute name="TRUE">
          <c:set var="price"
          value="${param.unitPrice * param.quantity}"/>
          <p> Price:${price}
          </jsp:attribute>
          <jsp:attribute name="FALSE">
          <p> Please fill out the form
          </jsp:attribute>
          <jsp:attribute name="ERROR">
          <p> Number format error
          </jsp:attribute>
          </u:if>
          

          聲明片段屬性

          必須使用 <fragment>true</fragment> 在描述符文件中聲明片段屬性:

          <taglib ...>
              ...
          <tag>
          <name>if</name>
          <tag-class>jsputils.tags.IfTag</tag-class>
          <body-content>empty</body-content>
          <attribute>
          <name>test</name>
          <required>true</required>
          <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
          <name>TRUE</name>
          <required>true</required>
          <fragment>true</fragment>
          </attribute>
          <attribute>
          <name>FALSE</name>
          <required>false</required>
          <fragment>true</fragment>
          </attribute>
          <attribute>
          <name>ERROR</name>
          <required>false</required>
          <fragment>true</fragment>
          </attribute>
          </tag>
              ...
          </taglib>
          

          處理片段屬性

          IfTag 處理類具有 <u:if> 的常規(guī) test 屬性以及 TRUE、FALSEERROR 片段屬性的設(shè)置方法。doTag() 方法使用 JspFragment 類的 invoke() 方法執(zhí)行 JSP 片段:

          package jsputils.tags;
          
          import javax.servlet.jsp.JspException;
          import javax.servlet.jsp.tagext.JspFragment;
          import javax.servlet.jsp.tagext.SimpleTagSupport;
          
          import java.io.IOException;
          
          public class IfTag extends SimpleTagSupport {
          private boolean testAttr;
          private JspFragment trueAttr;
          private JspFragment falseAttr;
          private JspFragment errorAttr;
          
          public void setTest(boolean test) {
          testAttr = test;
              }
          
          public void setTRUE(JspFragment fragment) {
          trueAttr = fragment;
              }
          
          public void setFALSE(JspFragment fragment) {
          falseAttr = fragment;
              }
          
          public void setERROR(JspFragment fragment) {
          errorAttr = fragment;
              }
          
          public void doTag() throws JspException, IOException {
          try {
          if (testAttr) {
          if (trueAttr != null)
          trueAttr.invoke(null);
          } else {
          if (falseAttr != null)
          falseAttr.invoke(null);
                      }
          } catch (Exception x) {
          if (errorAttr != null)
          errorAttr.invoke(null);
          else
          throw new JspException(x);
                  }
              }
          
          }
          

          迭代標(biāo)記

          JSTL 具有三個(gè)迭代標(biāo)記(<c:forEach>、<c:forTokens><x:forEach>)。本部分演示了如何實(shí)現(xiàn)在我的上篇文章中介紹的 <u:while> 標(biāo)記(在每次迭代前使用 EL API 判斷其條件)。

          在定制標(biāo)記中使用 JSTL 函數(shù)庫

          JSTL 1.1 提供了一個(gè)函數(shù)庫來實(shí)現(xiàn)許多有用的字符串操作。以下代碼嘗試使用 JSTL 的 fn:split() 函數(shù)將字符串 (a1/a2//b//c1/c2/c3) 拆分為三個(gè)標(biāo)記(a1/a2、bc1/c2/c3):

          <!-- SplitTest.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
          
          <p>fn:split -
          <c:set var="str" value="a1/a2//b//c1/c2/c3"/>
          <c:set var="delim" value="http://"/>
          <c:set var="array" value="${fn:split(str, delim)}"/>
          <c:forEach var="token" items="${array}">
          [<c:out value="${token}"/>]
          </c:forEach>
          

          上面的代碼未生成所要的結(jié)果,這是因?yàn)?fn:split() 是基于 java.util.StringTokenizer 的,后者將 delim 參數(shù)作為一組分隔字符處理。以下是 SplitTest.jsp 生成的輸出:

          fn:split - [a1] [a2] [b] [c1] [c2] [c3] 
          

          JSTL 提供了其他字符串函數(shù)(如 fn:contains()、fn:substringBefore()fn:substringAfter()),可以通過循環(huán)使用這些函數(shù)將 a1/a2//b//c1/c2/c3 拆分為 a1/a2、bc1/c2/c3。該循環(huán)由 <u:while> 標(biāo)記控制:

           
          <!-- WhileTest.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <p>u:while -
          <c:set var="str" value="a1/a2//b//c1/c2/c3"/>
          <c:set var="delim" value="http://"/>
          <u:while test="\${fn:contains(str, delim)}">
          [<c:out value="${fn:substringBefore(str, delim)}"/>]
          <c:set var="str" value="${fn:substringAfter(str, delim)}"/>
          </u:while>
          [<c:out value="${str}"/>]
          

          請注意,$ 字符在 test 條件中使用反斜杠進(jìn)行了轉(zhuǎn)義。因此,JSP 容器將 test 屬性的值作為文本處理,而不求解 JSP 表達(dá)式的值。<u:while> 標(biāo)記由 WhileTag 類處理,該類在每此迭代前求解 ${fn:contains(str, delim)} 表達(dá)式。${fn:substringBefore(str, delim)} 表達(dá)式返回字符串的第一個(gè)標(biāo)記,而 ${fn:substringAfter(str, delim)} 返回剩余標(biāo)記。WhileTest.jsp 頁面生成所要的輸出:

          u:while - [a1/a2] [b] [c1/c2/c3] 
          

          多次求解同一 JSP 表達(dá)式

          標(biāo)記處理類可以使用 invoke() 方法多次調(diào)用定制標(biāo)記的主體。還可以使用同一 invoke() 方法多次執(zhí)行片段屬性。但如果要對常規(guī)屬性重新求值,則必須使用 EL API。“使用 JSP 2.0 EL API”中的 PEWrapper 類使您能夠通過一次性分析 JSP 表達(dá)式來優(yōu)化此過程。請注意,此示例類只是標(biāo)準(zhǔn) EL API 的包裝類。WhileTag 處理類的 doTag() 方法創(chuàng)建一個(gè) PEWrapper 實(shí)例,該實(shí)例需要必須求解的表達(dá)式 (strTest)、預(yù)期的類型 (Boolean)、JSP 上下文和一個(gè)函數(shù)映射類(使您能夠在 JSP 表達(dá)式中使用 JSTL 函數(shù))。FNMapper 類(“使用 JSP 2.0 EL API”中提供了該類)將 JSTL 函數(shù)映射為一組由 JSTL 的 Apache 實(shí)現(xiàn)提供的靜態(tài) Java 方法。當(dāng) test 表達(dá)式為 true 時(shí),doTag() 方法執(zhí)行 <u:while> 標(biāo)記的 JSP 主體:

          package jsputils.tags;
          
          import jsputils.el.PEWrapper;
          import jsputils.el.FNMapper;
          
          import javax.servlet.jsp.JspException;
          import javax.servlet.jsp.tagext.SimpleTagSupport;
          
          import java.io.IOException;
          
          public class WhileTag extends SimpleTagSupport {
          private String strTest;
          
          public void setTest(String test) throws JspException {
          strTest = test;
              }
          
          public void doTag() throws JspException, IOException {
          PEWrapper parsedExpr = PEWrapper.getInstance(
          strTest, Boolean.class, getJspContext(),
          FNMapper.getInstance("fn"));
          while (((Boolean) parsedExpr.evaluate()).booleanValue())
          getJspBody().invoke(null);
              }
          
          }
          

          util.tld 文件中定義了 <u:while>WhileTag 類之間的映射:

          <taglib ...>
              ...
          <tag>
          <name>while</name>
          <tag-class>jsputils.tags.WhileTag</tag-class>
          <body-content>scriptless</body-content>
          <attribute>
          <name>test</name>
          <required>true</required>
          <rtexprvalue>true</rtexprvalue>
          </attribute>
          </tag>
              ...
          </taglib>
          

          具有動態(tài)屬性的標(biāo)記

          JSTL 提供對 Java 集合的支持。例如,可以使用 <c:set>java.util.Map 添加元素。但無法使用 JSTL 創(chuàng)建 Map 對象。本部分構(gòu)建了一個(gè)定制標(biāo)記,該標(biāo)記創(chuàng)建一個(gè)用于保存 java.util.LinkedHashMap 的 JSP 變量。您可以按以下示例所示在 JSP 頁面中創(chuàng)建 Map 對象:

          <u:map var="langMap" scope="application"
          en="English" de="Deutsch" fr="Fraais"
          it="Italiano" es="Espol"/>
          

          此 Map 對象使用標(biāo)記的動態(tài)屬性(en、de、fr、ites)進(jìn)行初始化。這些屬性之所以稱作動態(tài)屬性是因?yàn)樗鼈儾辉趲烀枋龇新暶鳌?/SPAN>

          處理動態(tài)屬性

          定制標(biāo)記可以通過實(shí)現(xiàn) DynamicAttributes 接口(它只有一個(gè)方法 setDynamicAttribute())處理動態(tài)屬性。JSP 容器對未在 TLD 文件中聲明的每個(gè)屬性調(diào)用此方法。

          MapTag 處理類擴(kuò)展了 VarTagSupport 并實(shí)現(xiàn)了 DynamicAttributesLinkedHashMap 實(shí)例在 MapTag() 構(gòu)造函數(shù)中創(chuàng)建。setDynamicAttribute() 方法通過將屬性名稱作為屬性值的鍵為 Map 對象中添加元素。doTag() 方法使用從 VarTagSupport 繼承的 export() 方法將 Map 對象導(dǎo)出為 JSP 變量:

          package jsputils.tags;
          
          import javax.servlet.jsp.JspException;
          import javax.servlet.jsp.tagext.DynamicAttributes;
          
          import java.util.LinkedHashMap;
          
          public class MapTag extends VarTagSupport
          implements DynamicAttributes {
          private LinkedHashMap map;
          
          public MapTag() {
          map = new LinkedHashMap();
              }
          
          public void setDynamicAttribute(String uri,
          String localName, Object value)
          throws JspException {
          map.put(localName, value);
              }
          
          public void doTag() throws JspException {
          export(map);
              }
          
          }
          

          請注意,LinkedHashMap 保留其元素的順序,這意味著由 iterator() 方法返回的 java.util.Iterator 按元素添加到 Map 對象的順序訪問這些元素。

          必須在 util.tld 文件中聲明對動態(tài)屬性以及 <u:map> 標(biāo)記的 varscope 屬性的支持:

          <taglib ...>
              ...
          <tag>
          <name>map</name>
          <tag-class>jsputils.tags.MapTag</tag-class>
          <body-content>empty</body-content>
          <attribute>
          <name>var</name>
          <required>true</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          <attribute>
          <name>scope</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          <dynamic-attributes>true</dynamic-attributes>
          </tag>
              ...
          </taglib>
          

          在 JSP 頁面中使用 Map 對象

          MapTest.jsp 頁面使用 <u:map> 標(biāo)記創(chuàng)建兩個(gè)包含某個(gè)虛擬網(wǎng)站所支持的語言和版本的 Map 對象(langMapversionMap)。然后,該頁面使用 JSTL 的 <c:redirect> 標(biāo)記將用戶重定向到 MapTest2.jsp

          <!-- MapTest.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <u:map var="langMap" scope="application"
          en="English" de="Deutsch" fr="Fraais"
          it="Italiano" es="Espol"/>
          <c:set var="defaultLang" scope="application" value="en"/>
          
          <u:map var="versionMap" scope="application"
          html="HTML" java="Java" flash="Flash"/>
          <c:set var="defaultVersion" scope="application" value="html"/>
          
          <c:redirect url="MapTest2.jsp"/>
          

          如果 session 范圍中尚未存在此 JSP 變量,則 MapTest2.jsp 頁面將再創(chuàng)建一個(gè) Map 對象 (prefMap)。這三個(gè) Map 對象(包含語言、版本和用戶首選項(xiàng))用于創(chuàng)建一個(gè)簡單的 HTML 表單,允許用戶更改他們的首選語言和站點(diǎn)版本:

          <!-- MapTest2.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <c:if test="${prefMap == null}">
          <u:map var="prefMap" scope="session"
          lang="${defaultLang}" version="${defaultVersion}"/>
          </c:if>
          
          <form method="post" action="MapTest3.jsp">
          
          <p>Language:<br>
          <select name="lang" size="1">
          <c:forEach var="lang" items="${langMap}">
          <c:set var="selected" value=""/>
          <c:if test="${lang.key == prefMap.lang}">
          <c:set var="selected" value="selected"/>
          </c:if>
          <option value="${lang.key}" ${selected}>
          ${lang.value}
          </option>
          </c:forEach>
          </select>
          
          <p>Version:<br>
          <c:forEach var="version" items="${versionMap}">
          <c:set var="checked" value=""/>
          <c:if test="${version.key == prefMap.version}">
          <c:set var="checked" value="checked"/>
          </c:if>
          <input type="radio" name="version" ${checked}
          value="${version.key}"> ${version.value} <br>
          </c:forEach>
          
          <p> <input type="submit" value="Save">
          
          </form>
          

          以下是由 MapTest2.jsp 生成的 HTML 表單:

          <form method="post" action="MapTest3.jsp">
          
          <p>Language:<br>
          <select name="lang" size="1">
          <option value="en" selected>
          English
          </option>
          <option value="de" >
          Deutsch
          </option>
          <option value="fr" >
          Fraais
          </option>
          <option value="it" >
          Italiano
          </option>
          <option value="es" >
          Espol
          </option>
          </select>
          
          <p>Version:<br>
          <input type="radio" name="version" checked
          value="html"> HTML <br>
          <input type="radio" name="version" 
          value="java"> Java <br>
          <input type="radio" name="version" 
          value="flash"> Flash <br>
          
          <p> <input type="submit" value="Save">
          
          </form>
          

          MapTest3.jsp 將用戶選擇的首選項(xiàng)保存到 prefMap 變量中并顯示用戶首選項(xiàng):

          <!-- MapTest3.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <u:map var="prefMap" scope="session"
          lang="${param.lang}" version="${param.version}"/>
          
          <p>User Preferences:
          <ul>
          <li>Language:${prefMap.lang}</li>
          <li>Version:${prefMap.version}</li>
          </ul>
          
          <form method="post" action="MapTest2.jsp">
          <p> <input type="submit" value="Change">
          </form>
          

          協(xié)調(diào)標(biāo)記

          JSTL 的 <sql:param> 標(biāo)記與 <sql:query><sql:update> 配合使用,來傳遞所執(zhí)行 SQL 語句的參數(shù)。本文使用了同一技巧來實(shí)現(xiàn)兩個(gè)定制標(biāo)記(<u:list><u:item>),它們協(xié)同在 JSP 頁面中創(chuàng)建一個(gè) java.util.ArrayList<u:list> 標(biāo)記可以是一個(gè)或多個(gè)包含此列表元素的 <u:item> 標(biāo)記的父標(biāo)記,如下例所示:

          <u:list var="services">
          <u:item> E-Mail </u:item>
          <u:item> Web Hosting </u:item>
          <u:item> E-Commerce </u:item>
          </u:list>
          

          <u:item> 標(biāo)記不需要直接包含在 <u:list> 中。您可以在 <u:list><u:item> 之間放置其他標(biāo)記,如 <c:forEach>。這使您能夠在循環(huán)中添加元素。如前一個(gè)代碼片段所示,可以在 <u:item></u:item> 之間指定這些元素的值,也可以使用 <u:item>value 屬性指定:

          <u:list var="selectedServices">
          <c:forEach var="index" items="${paramValues.selected}">
          <c:set var="paramName" value="service${index}"/>
          <u:item value="${param[paramName]}"/>
          </c:forEach>
          </u:list>
          

          這些代碼示例是 ListTest.jspListTest2.jsp 頁面的一部分,位于 ListTagItemTag 類之后。

          實(shí)現(xiàn)協(xié)同工作的標(biāo)記處理類

          ListTag 處理類在其構(gòu)造函數(shù)中創(chuàng)建 ArrayList 實(shí)例,并提供一個(gè)公共 add() 方法為列表添加元素。doTag() 方法調(diào)用所處理的 <u:list> 標(biāo)記的主體并將列表導(dǎo)出為 JSP 變量:

          package jsputils.tags;
          
          import javax.servlet.jsp.JspException;
          
          import java.util.ArrayList;
          
          import java.io.IOException;
          
          public class ListTag extends VarTagSupport {
          private ArrayList list;
          
          public ListTag() {
          list = new ArrayList();
              }
          
          public void add(Object item) {
          list.add(item);
              }
          
          public void doTag() throws JspException, IOException {
          getJspBody().invoke(null);
          export(list);
              }
          
          }
          

          <u:item> 標(biāo)記由 ItemTag 類處理,后者的 doTag() 方法使用 findAncestorWithClass() 定位 ListTag 實(shí)例 — 該實(shí)例處理最近的 <u:list> 祖先標(biāo)記。該列表元素被傳遞給祖先標(biāo)記的處理類的 add() 方法:

          package jsputils.tags;
          
          import javax.servlet.jsp.JspException;
          
          public class ItemTag extends VarTagSupport {
          private Object itemValue;
          
          public void setValue(Object value) throws JspException {
          itemValue = value;
              }
          
          public void doTag() throws JspException {
          ListTag ancestor = (ListTag) findAncestorWithClass(
          this, ListTag.class);
          if (ancestor == null)
          throw new JspException(
          "Couldn't find 'list' ancestor for 'item'");
          if (itemValue == null)
          itemValue = invokeBody();
          ancestor.add(itemValue);
              }
          
          }
          

          同其他常規(guī)標(biāo)記一樣,這兩個(gè)標(biāo)記在 TLD 文件中聲明:

          <taglib ...>
              ...
          <tag>
          <name>list</name>
          <tag-class>jsputils.tags.ListTag</tag-class>
          <body-content>scriptless</body-content>
          <attribute>
          <name>var</name>
          <required>true</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          <attribute>
          <name>scope</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          </tag>
          
          <tag>
          <name>item</name>
          <tag-class>jsputils.tags.ItemTag</tag-class>
          <body-content>scriptless</body-content>
          <attribute>
          <name>value</name>
          <required>false</required>
          <rtexprvalue>true</rtexprvalue>
          </attribute>
          </tag>
          
          </taglib>
          

          在 JSP 頁面中使用 List 對象

          ListTest.jsp 頁面創(chuàng)建一個(gè)包含服務(wù)的列表,并使用它生成一個(gè) HTML 表單,該表單允許用戶選擇一個(gè)或多個(gè)服務(wù):

          資源

          使用以下資源測試這些示例并了解有關(guān) JSP 2.0 簡單標(biāo)記 API 的更多信息。

          下載源代碼jsptags_src.zip 文件包含本文的示例:Java 類均位于 jsputils 目錄中;jspelapi 是一個(gè) Java Web 應(yīng)用程序。要運(yùn)行這些示例,需要 J2SE、J2EE 1.4 應(yīng)用服務(wù)器和 JSTL 1.1。

          閱讀“創(chuàng)建 JSP 2.0 標(biāo)記文件”Andrei Cioroianu 展示了如何創(chuàng)建和使用標(biāo)記文件,以及如何將現(xiàn)有頁面片段變換為標(biāo)記文件。他使用 JSTL 和幾個(gè)高級 JSP 特性構(gòu)建用于更新和查詢數(shù)據(jù)庫的標(biāo)記文件。

          閱讀《使用 JSP 2.0 EL API》Andrei Cioroianu 演示了如何動態(tài)求解 JSP 表達(dá)式、如何在 XML 配置文件中使用表達(dá)式語言以及如何在顯示 SQL 結(jié)果集時(shí)優(yōu)化 EL 的使用。

          下載 OC4J 10gOC4J 10g 開發(fā)人員預(yù)覽版 2 完全采用 J2EE 1.4 規(guī)范(包括 JSP 2.0)。可以使用 OC4J 10g (10.0.3) 來測試這些示例。

          下載 JSTL 1.1部署 jsptags Web 應(yīng)用程序之前,下載 JSTL 并將文件 jstl.jar 和 standard.jar 復(fù)制到 jsptags/WEB-INF/lib 目錄中。

          閱讀 JSP 2.0 規(guī)范JSP 2.0 規(guī)范有整個(gè)一章(“第 1 部分:第 JSP.7 章 - 標(biāo)記擴(kuò)展”)是專門為要構(gòu)建定制標(biāo)記庫的開發(fā)人員準(zhǔn)備的。簡單標(biāo)記 API 和標(biāo)準(zhǔn)標(biāo)記 API 在另一章(“第 2 部分:第 JSP.13 章 - 標(biāo)記擴(kuò)展 API”)中進(jìn)行了介紹。

          JSP 示例和教程JSP 示例代碼

          教程:了解 JSP 2.0 的新特性

          <!-- ListTest.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <u:list var="services">
          <u:item> E-Mail </u:item>
          <u:item> Web Hosting </u:item>
          <u:item> E-Commerce </u:item>
          </u:list>
          
          <form method="post" action="ListTest2.jsp">
          <p> Services:<br>
          <c:forEach var="index" begin="${0}"
          end="${fn:length(services)-1}">
          <input type="checkbox" checked
          name="selected" value="${index}">
          <c:out value="${services[index]}"/>
          <input type="hidden" name="service${index}"
          value="${services[index]}"> <br>
          </c:forEach>
          <p> <input type="submit" value="Select">
          </form>
          

          以下是由 ListTest.jsp 生成的 HTML 表單:

          <form method="post" action="ListTest2.jsp">
          <p> Services:<br>
              
          <input type="checkbox" checked
          name="selected" value="0">
          E-Mail 
          <input type="hidden" name="service0"
          value=" E-Mail "> <br>
              
          <input type="checkbox" checked
          name="selected" value="1">
          Web Hosting 
          <input type="hidden" name="service1"
          value=" Web Hosting "> <br>
              
          <input type="checkbox" checked
          name="selected" value="2">
          E-Commerce 
          <input type="hidden" name="service2"
          value=" E-Commerce "> <br>
              
          <p> <input type="submit" value="Select">
          </form>
          

          ListTest2.jsp 頁面處理用戶提交的表單數(shù)據(jù),創(chuàng)建并顯示選定服務(wù)的列表:

          <!-- ListTest2.jsp -->
          
          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
          <%@ taglib prefix="u" uri="/WEB-INF/util.tld" %>
          
          <u:list var="selectedServices">
          <c:forEach var="index" items="${paramValues.selected}">
          <c:set var="paramName" value="service${index}"/>
          <u:item value="${param[paramName]}"/>
          </c:forEach>
          </u:list>
          
          <p> Selected Services:<br>
          <ul>
          <c:forEach var="service" items="${selectedServices}">
          <li><c:out value="${service}"/></li>
          </c:forEach>
          </ul>
          

          總結(jié)

          無論 JSTL 和其他標(biāo)記庫提供了多少標(biāo)記,總會有一些情形需要開發(fā)自己的標(biāo)記。本文演示了如何使用簡單標(biāo)記 API 以及在開發(fā)定制標(biāo)記時(shí)所需的基本技巧。此外,還提供了幾個(gè)可以供您在 Web 應(yīng)用程序中重復(fù)使用的標(biāo)記。


          Andrei Cioroianu (devtools@devsphere.com) 是 Devsphere (www.devsphere.com) 的創(chuàng)始人,那是一家 Java 框架、XML 咨詢和 Web 開發(fā)服務(wù)的供應(yīng)商。Cioroianu 編寫了許多 Java 文章,這些文章由 ONJava (www.onjava.com)、JavaWorld (www.javaworld.com) 和 Java Developer's Journal 出版。他還與別人合著了 Java XML Programmer's Reference Professional Java XML 兩本書(均由 Wrox Press 出版)。
          posted on 2005-06-07 16:27 似水流年 閱讀(494) 評論(0)  編輯  收藏 所屬分類: JSP/Servlet
          主站蜘蛛池模板: 濉溪县| 武平县| 尉氏县| 华池县| 无为县| 沿河| 镇巴县| 彰化县| 瑞丽市| 永平县| 黔西县| 梅州市| 霍林郭勒市| 宁武县| 搜索| 青河县| 仙居县| 甘肃省| 石城县| 凤翔县| 永清县| 当涂县| 年辖:市辖区| 武宣县| 乌苏市| 兖州市| 中江县| 镇宁| 廊坊市| 西乌珠穆沁旗| 和田市| 龙江县| 扶余县| 姜堰市| 金川县| 邵阳县| 常宁市| 新乡市| 德庆县| 如皋市| 枣强县|