欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

簡化Ajax和Java開發

系統 1911 0
為了適應不同的應用程序需求和開發樣式,大部分 Web 框架都在盡力變得靈活和可擴展。不幸的是,這有時候會增加復雜性和處理開銷,還會產生很大的配置文件。本文將展示如何使用 JSP 標準標記庫(JSTL)和 JSP 標記文件實現數據綁定、頁面導航和樣式約定,從而簡化開發和維護。您將了解如何構建帶有動態屬性的定制 JSP 標記,使快速更改應用程序變得更加容易。此外,本文最后一節包含了一個使用 Ajax 提交 Web 表單的示例。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

首先,如果您希 望實現約定來最小化配置,則必須控制框架生成的 HTML,并調整 Web 組件使之適用于您的應用程序。已經有一些高度可定制的 Web 框架,比如 JavaServer Faces (JSF),但它們的組件有時不容易定制。例如,如果想要更改 JSF 組件生成的 HTML,通常情況下需要對組件的呈現程序進行重新編碼,并實現一個新的定制標記。如果只需在 JSP 文件中更改 HTML,則會簡單很多。本文將展示開發人員可以創建基于 JSP 的組件來管理框架。

使用 JSP 標記文件構建 Web 組件

JSP 標記文件是簡化 Web 組件開發的理想解決方案,因為它們允許使用 JSP 語法創建定制標記庫。此外,標記文件可以像 JSP 頁面一樣部署,而且不需要標記庫描述符(Tag Library Descriptor,TLD),因為它們使用由 JSP 標準定義的命名和設置約定,該標準還提供了在 JSP 標記文件中聲明標記屬性的指令。

更改時,應用服務器會重新編譯并加載一個 JSP 標記文件,而無需重新啟動應用程序,這使開發和測試都變得非常簡單。JSP 標記文件很快,因為它們受自動生成的 Java? 類支持,與將 JSP 頁面轉換為 Servlet 類很相似。

developerWorks Ajax 資源中心
請訪問 Ajax 資源中心 ,這是有關開發 Ajax 應用程序所需的免費工具、代碼和信息的一站式中心。由 Ajax 專家 Jack Herrington 主持的 活躍 Ajax 社區論壇 也許可以幫助您解答疑問。

本文將演示如何使用 JSP 標記文件和 JSTL 構建可定制 Web 組件,而無需使用 JSF。主要目標是使更改動態生成 HTML 的代碼更加容易,控制處理 HTTP(或 Ajax)請求的方式,并實現簡化開發的約定。

本 文提供的所有示例都可以組合到一個微型框架中,可以使用它代替 Struts 或 JSF 構建 Web 表單。如果您正開始使用 Java 開發 Web 應用程序,那么您會喜歡上它的簡單易用,而且無需學習任何新知識,因為這個框架的標記具有與 HTML 標記相同的名稱和屬性。

經 驗豐富的開發人員將會發現,這個框架對必須充分利用 Ajax 和 DHTML 的應用程序很有用。您無需局限于任何應用程序模型,可以更改框架的 250 行 JSP 代碼來生成在 Web 瀏覽器中產生最佳結果的 HTML,也能夠以適合應用程序的任何方式自由處理 HTTP 請求。

此 外,沒有需要管理的特定于框架的配置文件和額外的類。每個頁面都可以使用一個普通舊式 Java 對象(plain old Java object,POJO)作為一個數據模型,或者如果能夠用 JSP 代碼而不是 Java 代碼輕松完成數據處理的話,您甚至可以使用一個 Map 對象來代替 JavaBean 實例。

將表單元素綁定到 JavaBean 屬性

Web 框架必須提供的一個主要功能是將 UI 組件綁定到數據模型的屬性。這意味著當 Web 頁面被請求時,框架必須從 JavaBean 對象獲取數據并將其包含到 HTML 表單中。用戶提交表單時,框架必須獲取請求參數并將更新值回存到數據模型中。例如,JSF 框架會讓您使用 value 屬性指定輸入組件的數據綁定(如清單 1 所示):


清單 1. JSF 數據綁定
            
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
...
<h:inputTextarea value="#{dataModel.address}" rows="3" cols="30"/>

必須在一個 XML 文件中為 JSF 配置數據模型,如清單 2 所示:


清單 2. 數據模型的 JSF 配置
            
<managed-bean>
<managed-bean-name>dataModel</managed-bean-name>
<managed-bean-class>formsdemo.AddressBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

本節演示如何使用 JSTL 和 JSP 標記文件實現相同的輸入組件。您可能想知道為什么 JSF 框架中的組件可用時還要這樣做。如果將本文中的 textarea.tag 文件與 JSF 框架中實現等價組件的 Java 類的源代碼相比較,您就會完全了解 JSP 標記文件帶來的好處。然后,請考慮一下您需要在 JSF 框架或另一個第三方庫未提供的其他組件上投入多少工作吧。

使用 JSTL 處理 Web 表單

清單 3 展示了一個包含一個 <textarea> 元素的簡單 Web 表單,該元素的值是從一個 AddressBean 實例獲取的。 <jsp:useBean> 標記創建 JavaBean 對象并將其放到 JSP request 作用域中。 address 屬性的值被包含在帶有 JSTL 標記 <c:out> 的 Web 頁面中。


清單 3. JSP 頁面使用 JSTL 對數據綁定進行編碼
            
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<jsp:useBean id="dataModel" scope="request" class="formsdemo.AddressBean"/>

<form method="POST">
<c:if test="${pageContext.request.method == 'POST' && !empty param.address}">
<c:set target="${dataModel}" property="address" value="${param.address}"/>
</c:if>
<textarea name="address" rows="3" cols="30"
><c:out value="${dataModel.address}"/></textarea>
<br><input type="submit" value="Submit"/>
</form>

當用戶單擊 Submit 按鈕時,Web 瀏覽器將用戶的輸入發回給相同的頁面,因為 <form> 元素沒有 action 屬性。然后,應用服務器執行 JSP 頁面,該頁面使用 JSTL 標記 <c:set> address 參數的值存儲到 dataModel bean 中。

構建 <df:textarea> 組件

如果比較清單 1 和清單 3,您將會注意到,JSF 頁面僅使用了一行代碼來定義文本區域組件,而基于 JSTL 的頁面需要 5 行代碼來將 <textarea> 元素綁定到 JavaBean 屬性。通過將 JSTL 代碼移動到輸出 <textarea> 元素的可重用標記文件中,就可以 將此代碼片段縮減為一行。

textarea.tag 文件(見清單 4)僅聲明用于數據綁定約定的 name 屬性(表單元素和帶有該元素的值的 JavaBean 屬性必需具有相同的名稱)。任何其他屬性(比如 rows cols )都將存儲在一個 Map 對象中,該對象的 dynAttr 標識符由 <%@tag%> 指令的 dynamic-attributes 屬性來指定。這些屬性在一個受 JSTL 標記 <c:forEach> 控制的循環中輸出。任何 " 、 & < > 字符都被 JSTL 函數 fn:escapeXml() 使用 &quot; 、 &amp; 、 &lt; &gt; 替換。


清單 4. textarea.tag 文件
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ tag dynamic-attributes="dynAttr" body-content="scriptless" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<c:if test="${pageContext.request.method == 'POST' && !empty param[name]}">
<c:set target="${dataModel}" property="${name}" value="${param[name]}"/>
</c:if>

<textarea name="${name}"
<c:forEach var="attr" items="${dynAttr}">
${attr.key}="${fn:escapeXml(attr.value)}"
</c:forEach>
><c:out value="${dataModel[name]}"/></textarea>

清單 5 中顯示的 Web 頁面為包含標記文件的 JSP 庫聲明 df 前綴。然后,該頁面使用 <df:textarea> 組件生成 <textarea> 元素,該元素會讓用戶輸入 dataModel 對象的 address 屬性的值。


清單 5. 使用標記文件的 JSP 頁面
            
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="df" tagdir="/WEB-INF/tags/dynamic/forms" %>

<jsp:useBean id="dataModel" scope="request" class="formsdemo.AddressBean"/>

<form method="POST">
<df:textarea name="address" rows="3" cols="30"/>
<br><input type="submit" value="Submit"/>
</form>

使用外觀和樣式約定

在我以前的文章 “增強 JSF 頁面的外觀”(參見 參考資料 )中,我展示了一種設置標準 JSF 組件的默認屬性的技術。我使用了一個定制 JSF 組件來遍歷視圖樹并設置每個組件的 styleClass 屬性,這非常適合于呈現單個 HTML 元素的簡單 JSF 組件。

生 成較大的 HTML 片段(比如一個樹或表)的非標準 JSF 組件可能不允許設置任何 HTML 元素的樣式。假設 JSF 組件使用 Java 代碼生成 HTML,如果要更改 HTML 元素的樣式,您的惟一選擇就是對 JSF 組件的呈現程序進行重新編碼。但是,如果使用 JSP 標記文件和 JSTL,將能夠全權訪問輸出 HTML 的 JSP 代碼,這意味著您可以根據應用程序的需要對代碼進行更改和調整。

將可重用代碼片段移動到獨立的 JSP 標記文件中

前一節展示了 <df:textarea> 組件,該組件使用 JSTL 生成與 JavaBean 屬性綁定的 <textarea> 元素。如果想要構建額外的 Web 組件,最好把公共的代碼片段放到可重用的標記文件中。

輸出動態屬性的 <c:forEach> 循環可以移動到一個名為 attrList.tag 的獨立標記文件中(參見 清單 6 )。除了使代碼更加緊湊,此更改還允許您實現對所有組件都有用的特性,比如將默認樣式類添加到 HTML 標記。

attrList.tag 聲明一個名為 tag 的屬性,該屬性和 skin 參數結合起來構建包含在 class 屬性內部的類名稱。 <c:forEach> 屬性輸出給定的 map 包含的所有屬性,但 class 屬性除外,它是在循環之后添加。


清單 6. attrList.tag 文件
            
<%@ attribute name="tag" required="true" rtexprvalue="true" %>
<%@ attribute name="map" required="true" rtexprvalue="true"
type="java.util.Map" %>
<%@ tag body-content="empty" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<c:if test="${!empty initParam.skin}">
<c:set var="classAttr" value="${initParam.skin}_${tag}"/>
</c:if>

<c:forEach var="attr" items="${map}">
<c:if test="${attr.key != 'class'}">
${attr.key}="${fn:escapeXml(attr.value)}"
</c:if>
<c:if test="${attr.key == 'class'}">
<c:set var="classAttr" value="${classAttr} ${attr.value}"/>
</c:if>
</c:forEach>

<c:if test="${!empty classAttr}">
class="${fn:escapeXml(classAttr)}"
</c:if>

skin 參數在 Web 應用程序的 web.xml 文件中指定(參見清單 7):


清單 7. 在 web.xml 中配置外觀參數
            
<web-app ...>
<context-param>
<param-name>skin</param-name>
<param-value>default</param-value>
</context-param>
</web-app>

更新 <df:textarea> 組件

清單 8 展示了更改后的 textarea.tag 文件,它使用 <dfu:attrList> 輸出 <textarea> 元素的動態屬性:


清單 8. textarea.tag 的更新版本
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ tag dynamic-attributes="dynAttr" body-content="scriptless" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dfu" tagdir="/WEB-INF/tags/dynamic/forms/util" %>

<c:if test="${pageContext.request.method == 'POST' && !empty param[name]}">
<c:set target="${dataModel}" property="${name}" value="${param[name]}"/>
</c:if>

<textarea name="${name}" <dfu:attrList tag="textarea" map="${dynAttr}"/>
><c:out value="${dataModel[name]}"/></textarea>

樣式規則可以在 CSS 文件中定義。例如,如果想要更改 <df:textarea> 產生的每個 <textarea> 元素的邊框,只需編寫一個像清單 9 中那樣的樣式規則:


清單 9. 定義 <textarea> 元素的默認樣式
            
.default_textarea
{ border-color: #A0A0A0; border-style: solid; border-width: thin; }

編寫表單處理和頁面導航規則

JSF 框架有一個復雜的請求處理生命周期,它可以劃分為 6 個不同的階段。很少有開發人員能夠完全理解它并進行定制。對于高流量的 Ajax 應用程序,需要使用一種更簡單的 HTTP 請求處理機制,以避免過高的 CPU 開銷。本節將展示如何借助 JSTL 和 JSP 標記文件輕松實現這一點。

創建 <df:form> 組件

form.tag 文件(如清單 10 所示)生成一個 <form> 元素,并使用 JSTL 設置嵌套標記訪問的變量,在本文的后續內容中將會看到。無需像之前的 JSP 示例一樣使用 dataModel 對象,標記文件擁有一個 model 屬性,該屬性像 JSP 標記文件的其他任何屬性一樣被放置到 page 作用域中。

form.tag 文件使用 JSTL 標記 <c:set> 將它的一些屬性復制到 request 作用域中,以便其他標記文件可以使用 formName formModel formAction 變量獲取 name model action 屬性的值。此外, formPost 變量指示 HTTP 方法是否為 POST , <jsp:useBean> 是否創建一個 HashMap 實例來存儲任何處理錯誤。


清單 10. form.tag 文件
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="action" required="false" rtexprvalue="true" %>
<%@ attribute name="method" required="false" rtexprvalue="true" %>
<%@ attribute name="model" required="true" rtexprvalue="true"
type="java.lang.Object"%>
<%@ tag dynamic-attributes="dynAttr" body-content="scriptless" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dfu" tagdir="/WEB-INF/tags/dynamic/forms/util" %>

<c:set var="formName" scope="request" value="${name}"/>
<c:set var="formModel" scope="request" value="${model}"/>
<c:if test="${!empty action}">
<c:set var="formAction" scope="request" value="${action}"/>
</c:if>
<c:set var="formPost" scope="request"
value="${fn:toUpperCase(pageContext.request.method) == 'POST'}"/>
<jsp:useBean id="formErrors" scope="request" class="java.util.HashMap"/>

<form name="${name}" method="POST" <dfu:attrList tag="form" map="${dynAttr}"/>>
<jsp:doBody/>
</form>

<c:if test="${formPost && empty formErrors && !empty formAction}">
<c:set var="forwardURL" value="${formAction}"/>
</c:if>

<c:remove var="formName" scope="request"/>
<c:remove var="formModel" scope="request"/>
<c:remove var="formAction" scope="request"/>
<c:remove var="formPost" scope="request"/>
<c:remove var="formErrors" scope="request"/>

<c:if test="${!empty forwardURL}">
<jsp:forward page="${forwardURL}"/>
</c:if>

<form> 元素將擁有與 <df:form> 標記相同的 HTML 屬性,但 method (始終為 POST )和 action (省略以便將數據發送回相同的頁面)除外。 <form> 元素也會包含 <jsp:doBody> 生成的輸出,該元素執行 <df:form> </df:form> 之間的 JSP 代碼(參見清單 11)。如果 HTTP 方法為 POST 并且沒有出現錯誤, form.tag 文件將請求轉發到其 URL 在 action 屬性中指定的頁面,以供進一步處理。在這之前,標記文件使用 JSTL 標記 <c:remove> 將其變量從 request 作用域刪除。


清單 11. 在 JSP 頁面中使用 <df:form>
            
<df:form name="..." model="${...}" action="...">
...
<df:textarea .../>
...
</df:form>

處理用戶錯誤和應用程序異常

之前展示的 textarea.tag 文件不處理在設置與表單元素綁定的 JavaBean 屬性時可能發生的任何異常。這個問題可以使用 setProp.tag 文件解決(如清單 12 所示),如果出現轉換錯誤(比如 NumberFormatException ),該文件會使用 JSTL 標記 <c:catch> 捕捉 JavaBean 屬性的設置方法或者甚至是 <c:set> 標記可能拋出的任何異常:


清單 12. setProp.tag 文件
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="array" required="false" rtexprvalue="true"
type="java.lang.Boolean" %>
<%@ attribute name="bool" required="false" rtexprvalue="true"
type="java.lang.Boolean" %>
<%@ tag body-content="empty" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dfu" tagdir="/WEB-INF/tags/dynamic/forms/util" %>

<c:set var="propValue" value="${null}"/>
<c:if test="${formPost && empty formErrors[name]}">
<c:if test="${!array && !bool && !empty param[name]}">
<c:set var="propValue" value="${param[name]}"/>
</c:if>
<c:if test="${!array && bool}">
<c:set var="propValue" value="${!empty param[name]}"/>
</c:if>
<c:if test="${array && fn:length(paramValues[name]) > 0}">
<c:set var="propValue" value="${paramValues[name]}"/>
</c:if>
</c:if>

<c:if test="${propValue != null}">
<c:catch var="exception">
<c:set target="${formModel}" property="${name}" value="${propValue}"/>
</c:catch>
<c:if test="${exception != null}">
<dfu:addError name="${name}" msg="${exception.message}"
exception="${exception}"/>
</c:if>
</c:if>

setProp.tag 文件用于設置擁有 <c:set> 接受的類型(比如 String 、 int float boolean )的屬性和索引屬性,后者可能是 String 數組。如果發生了類型轉換錯誤或者拋出異常,addError.tag 文件(參見清單 13)就會將錯誤消息放入 formErrors 映射中:


清單 13. addError.tag 文件
            
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="msg" required="true" rtexprvalue="true" %>
<%@ attribute name="exception" required="false" rtexprvalue="true"
type="java.lang.Throwable" %>

<c:if test="${!empty formErrors[name]}">
<c:set var="msg" value="${formErrors[name]}; ${msg}"/>
</c:if>
<c:set target="${formErrors}" property="${name}" value="${msg}"/>

<c:if test="${exception != null}">
<% ((Throwable) jspContext.getAttribute("exception")).printStackTrace(); %>
</c:if>

textarea.tag 文件的最終版本(如清單 14 所示)使用 <dfu:setProp> 獲取 JavaBean 屬性。此外,標記文件會讓您在 JSP 頁面中 <df:textarea> </df:textarea> 之間指定一個默認值。如果 bean 屬性的值為空,則標記文件使用 <jsp:doBody> 從 JSP 頁面獲取定制標記的內容。


清單 14. textarea.tag 的最終版本
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ tag dynamic-attributes="dynAttr" body-content="scriptless" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dfu" tagdir="/WEB-INF/tags/dynamic/forms/util" %>

<dfu:setProp name="${name}"/>

<c:set var="textareaValue" value="${formModel[name]}"/>
<c:if test="${empty textareaValue}">
<jsp:doBody var="textareaValue"/>
</c:if>

<textarea name="${name}" <dfu:attrList tag="textarea" map="${dynAttr}"/>
><c:out value="${textareaValue}"/></textarea>

開發更多的 UI 組件

迄今為止,您已經看到了如何創建自己的文本區域和表單組件,如何處理 HTTP 請求。本節將會展示一些附加組件,比如列表、輸入字段、復選框、單選和提交按鈕,您可以使用它們構建功能全面的 Web 表單。

創建 <df:select> 和 <df:option> 組件

在 JSP 頁面中, <df:option> 標記將會嵌入到 <df:select> 中,就像在 HTML 的 <option> <select> 元素中一樣。因此, select.tag 文件(參見清單 15)將其 name multiple 屬性復制到 request 作用域中,從而可以在 option.tag 中訪問它們。然后, select.tag 文件使用 <dfu:setProp> 設置與表單元素同名的模型屬性。如果 multiple 屬性為 true ,則該屬性的類型應該為一個數組。


清單 15. select.tag 文件
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="multiple" required="false" rtexprvalue="true"
type="java.lang.Boolean" %>
<%@ tag dynamic-attributes="dynAttr" body-content="scriptless" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dfu" tagdir="/WEB-INF/tags/dynamic/forms/util" %>

<c:set var="selectName" scope="request" value="${name}"/>
<c:set var="selectMultiple" scope="request" value="${multiple}"/>

<dfu:setProp name="${name}" array="${multiple}"/>

<select name="${name}"
<c:if test="${multiple}">
multiple
</c:if>
<dfu:attrList tag="select" map="${dynAttr}"/>
>
<jsp:doBody/>
</select>

<c:remove var="selectName" scope="request"/>
<c:remove var="selectMultiple" scope="request"/>

在 JSP 頁面中, <df:select> 標記可以擁有動態屬性,比如 id class ,這些元素通過 <dfu:attrList> 傳遞到輸出的 <select> 元素。JSP 標記 <jsp:doBody> 執行 <df:select> 的內容,該內容通常由幾個 <df:option> 標記組成。

在生成 <option> 元素之前, option.tag 文件(如清單 16 所示)設置 optionLabel optionValue 變量。只有當選項的值與模型(該模型具有與 <select> 元素相同的名稱)的值相等時, <dfu:isSelected> 標記(用于 option.tag 中)才會輸出由 selected 字符串組成的標記正文。因此,數據模型的屬性決定了由 <df:select> <df:option> 產生的列表的初始選擇。


清單 16. option.tag 文件
            
<%@ attribute name="value" required="false" rtexprvalue="true" %>
<%@ tag dynamic-attributes="dynAttr" body-content="scriptless" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dfu" tagdir="/WEB-INF/tags/dynamic/forms/util" %>

<jsp:doBody var="optionLabel"/>

<c:set var="optionValue" value="${value}"/>
<c:if test="${empty optionValue}">
<c:set var="optionValue" value="${optionLabel}"/>
</c:if>

<option
<c:if test="${!empty value}">
value="${fn:escapeXml(value)}"
</c:if>
<dfu:isSelected name="${selectName}" value="${optionValue}"
array="${selectMultiple}">
selected
</dfu:isSelected>
<dfu:attrList tag="option" map="${dynAttr}"/>
><c:out value="${optionLabel}"/></option>

清單 17 展示了 isSelected.tag 文件,該文件從 option.tag 調用。如果 array 屬性為 false ,則 isSelected.tag 文件將 value 屬性與 formModel[name] 進行比較。如果 array 屬性為 true ,則要求 formModel[name] 是一個數組,并且 isSelected.tag 將每個元素與 value 屬性進行比較。


清單 17. isSelected.tag 文件
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="value" required="true" rtexprvalue="true" %>
<%@ attribute name="array" required="false" rtexprvalue="true"
type="java.lang.Boolean" %>
<%@ tag body-content="scriptless" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<c:set var="selected" value="false"/>

<c:if test="${!array}">
<c:set var="selectedValue" value="${formModel[name]}"/>
<c:if test="${!empty selectedValue}">
<c:if test="${selectedValue == value}">
<c:set var="selected" value="${true}"/>
</c:if>
</c:if>
</c:if>

<c:if test="${array}">
<c:set var="selectedValues" value="${formModel[name]}"/>
<c:if test="${fn:length(selectedValues) > 0}">
<c:forEach var="selectedValue" items="${selectedValues}">
<c:if test="${selectedValue == value}">
<c:set var="selected" value="${true}"/>
</c:if>
</c:forEach>
</c:if>
</c:if>

<c:if test="${selected}">
<jsp:doBody/>
</c:if>

isSelected.tag 的 <jsp:doBody> 標記執行 option.tag 中位于 <dfu:isSelected> </dfu:isSelected> 之間的 JSP 代碼,在本例中主要輸出 selected 字符串。 <dfu:isSelected> 組件也用于 input.tag 中,用于驗證是否應該選擇一個單選按鈕。

構建 <df:input> 組件

input.tag 文件(參見清單 18)輸出一個 <input> 元素。根據 type 屬性的值的不同,標記文件執行不同的 JSP 代碼片段,并設置與 HTML 元素同名的模型屬性。

如果 type text password hidden ,當 HTTP 方法是 PSOT 時, <dfu:setProp> 標記將請求參數存儲到 JavaBean 對象中。接下來,無論 HTTP 方法是 GET 還是 POST,都使用 formModel[name] 獲取 bean 屬性的值并將其存儲到 inputValue 變量中。

對于 radio 按鈕,用之前展示的 <dfu:isSelected> 標記比較 value 屬性和與單選按鈕同名的模型屬性的值。如果這兩個值一致,則 inputChecked 變量為 true 。如果 type 屬性為 checkbox ,則要求 bean 屬性的類型為 boolean 。


清單 18. input.tag 文件
            
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="type" required="true" rtexprvalue="true" %>
<%@ attribute name="value" required="false" rtexprvalue="true" %>
<%@ attribute name="action" required="false" rtexprvalue="true" %>
<%@ tag dynamic-attributes="dynAttr" body-content="empty" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dfu" tagdir="/WEB-INF/tags/dynamic/forms/util" %>

<c:set var="inputType" value="${fn:toLowerCase(type)}"/>
<c:set var="inputValue" value="${value}"/>
<c:set var="inputChecked" value="${false}"/>

<c:choose>
<c:when test="${inputType=='text' || inputType=='password' || inputType=='hidden'}">
<dfu:setProp name="${name}"/>
<c:set var="inputValue" value="${formModel[name]}"/>
</c:when>
<c:when test="${inputType == 'radio'}">
<dfu:setProp name="${name}"/>
<dfu:isSelected name="${name}" value="${value}">
<c:set var="inputChecked" value="${true}"/>
</dfu:isSelected>
</c:when>
<c:when test="${inputType == 'checkbox'}">
<dfu:setProp name="${name}" bool="true"/>
<c:if test="${formModel[name]}">
<c:set var="inputChecked" value="${true}"/>
</c:if>
</c:when>
<c:when test="${inputType=='submit'}">
<c:if test="${formPost && !empty param[name] && !empty action}">
<c:set var="formAction" scope="request" value="${action}"/>
</c:if>
</c:when>
</c:choose>

<input name="${name}" type="${type}"
<c:if test="${!empty inputValue}">
value="${fn:escapeXml(inputValue)}"
</c:if>
<c:if test="${inputChecked}">
checked
</c:if>
<dfu:attrList tag="input_${type}" map="${dynAttr}"/>
>

對于 submit 按鈕,input.tag 文件接受 action 屬性,該屬性用于指定一個頁面的 URL。當單擊 submit 按鈕時,該 URL 應該替換表單的操作。因此,一個表單可以有多個提交按鈕,每個按鈕可以將請求發送到不同頁面,以生成 HTML 響應。這與在配置文件中指定導航規則(如在 JSF 框架下)相比要簡單得多。

使用 Ajax 提交 Web 表單

在我的另一篇文章 “使用 XMLHttpRequest 提交 JSF 表單”(參見 參考資料 )中,我展示了如何使用 Ajax 發送 Web 表單的數據。這篇文章還包含一個名為 SupportForm.jsp 的 JSF 示例。此處提供了一個類似的例子,便于您將 JSF 文章中的表單和基于本文 JSP 標記文件的 Web 表單進行比較。

創建 JavaBeans 或 Java Maps 支持的表單

SupportBean 類(見清單 19)是一個簡單的 bean,包含一些和示例 Web 表單的元素綁定的屬性:


清單 19. SupportBean 類
            
package formsdemo;

public class SupportBean implements java.io.Serializable {
private String name;
private String email;
private String versions[];
private String platform;
private String browser;
private boolean crash;
private String problem;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
...
}

清單 20 展示了 SupportForm.jsp 頁面,該頁面使用本文前一節提供的標記文件庫。Web 組件擁有與它們生成的 HTML 元素相同的屬性。 <df:form> 標記擁有額外的 model 屬性,該屬性指定 JavaBean 對象(提交的表單數據將存儲在這里)。


清單 20. SupportForm.jsp 示例
            
<%@ taglib prefix="df" tagdir="/WEB-INF/tags/dynamic/forms" %>

<jsp:useBean id="supportBean" scope="request" class="formsdemo.SupportBean"/>

<html>
<head>
<title>Support Form</title>
<link rel="stylesheet" href="forms.css" type="text/css">
</head>
<body>

<h1>Support Form</h1>

<df:form name="supportForm" model="${supportBean}"
action="SupportConfirm.jsp">

<p>Name: <br>
<df:input name="name" type="text" size="40"/>

<p>Email: <br>
<df:input name="email" type="text" size="40"/>

<p>Versions: <br>
<df:select name="versions" multiple="true" size="5">
<df:option>2.0.1</df:option>
<df:option>2.0.0</df:option>
<df:option>1.1.0</df:option>
<df:option>1.0.1</df:option>
<df:option>1.0.0</df:option>
</df:select>

<p>Platform: <br>
<df:input name="platform" type="radio" value="Windows"/> Windows <br>
<df:input name="platform" type="radio" value="Linux"/> Linux <br>
<df:input name="platform" type="radio" value="Mac"/> Mac <br>

<p>Browser: <br>
<df:select name="browser" size="1">
<df:option value=""></df:option>
<df:option value="IE">IE</df:option>
<df:option value="Firefox">Firefox</df:option>
<df:option value="Netscape">Netscape</df:option>
<df:option value="Mozilla">Mozilla</df:option>
<df:option value="Opera">Opera</df:option>
<df:option value="Safari">Safari</df:option>
</df:select>

<p><df:input name="crash" type="checkbox"/> Causes browser crash

<p>Problem: <br>
<df:textarea name="problem" rows="10" cols="40"/>

<p><df:input name="submit" type="submit" value="Submit"/>

</df:form>

</body>
</html>

SupportForm.jsp 中使用的 <df:form> 標記將 HTTP 請求轉發到 SupportConfirm.jsp 頁面(如清單 21 所示),該頁面的 URL 在 action 屬性中指定。該確認頁面輸出數據模型的屬性。


清單 21. SupportConfirm.jsp 頁面
            
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
<title>Support Confirmation</title>
</head>
<body>

<h1>Support Confirmation</h1>

<p>Your information was received.

<p>Name: <c:out value="${supportBean.name}"/><br>
<p>Email: <c:out value="${supportBean.email}"/><br>
<p>Versions: <c:forEach var="version" items="${supportBean.versions}">
<c:out value="${version}"/></c:forEach><br>
<p>Platform: <c:out value="${supportBean.platform}"/><br>
<p>Browser: <c:out value="${supportBean.browser}"/><br>
<p>Causes browser crash: <c:out value="${supportBean.crash}"/>
<p>Problem: <c:out value="${supportBean.problem}"/><br>

</body>
</html>

JSP EL 和 JSTL 標記(比如 <c:set> )訪問 JavaBean 的屬性和 Map 實例的元素時使用相同的語法。因此,可以使用一個 java.util.HashMap 來取代前面的例子中的 formsdemo.SupportBean 對象。惟一需要更改的是 <jsp:useBean> 標記中的類名稱(參見清單 22):


清單 22. SupportForm2.jsp 示例
            
<jsp:useBean id="supportBean" scope="request" class="java.util.HashMap"/>
...
<df:form name="supportForm" model="${supportBean}" action="SupportConfirm.jsp">
...
</df:form>

將 Ajax 代碼添加到 Web 表單

“使用 XMLHttpRequest 提交 JSF 表單”(參見 參考資料 )完整地描述了 AutoSaveScript.js 文件(可以在源代碼歸檔文件中找到)。JavaScript 文件包含本文重用的一些函數。 getFormData() 函數(如清單 23 所示)接受一個 form 對象并返回編碼在一個字符串中的表單數據:


清單 23. AutoSaveScript.js 的 getFormData() 函數
            
function getFormData(form) {
var dataString = "";

function addParam(name, value) {
dataString += (dataString.length > 0 ? "&" : "")
+ escape(name).replace(//+/g, "%2B") + "="
+ escape(value ? value : "").replace(//+/g, "%2B");
}

var elemArray = form.elements;
for (var i = 0; i < elemArray.length; i++) {
var element = elemArray[i];
var elemType = element.type.toUpperCase();
var elemName = element.name;
if (elemName) {
if (elemType == "TEXT"
|| elemType == "TEXTAREA"
|| elemType == "PASSWORD"
|| elemType == "HIDDEN")
addParam(elemName, element.value);
else if (elemType == "CHECKBOX" && element.checked)
addParam(elemName, element.value ? element.value : "On");
else if (elemType == "RADIO" && element.checked)
addParam(elemName, element.value);
else if (elemType.indexOf("SELECT") != -1)
for (var j = 0; j < element.options.length; j++) {
var option = element.options[j];
if (option.selected)
addParam(elemName,
option.value ? option.value : option.text);
}
}
}
return dataString;
}

AutoSaveScript.js 文件的 submitFormData() 函數(參見清單 24)有兩個參數:一個 form 對象和一個 callback 函數。前者的數據被 Ajax 發送到服務器,后者被調用來處理 Ajax 響應:


清單 24. AutoSaveScript.js 的 submitFormData() 函數
            
function submitFormData(form, callback) {
var xhr;
if (window.ActiveXObject)
xhr = new ActiveXObject("Microsoft.XMLHTTP");
else if (window.XMLHttpRequest)
xhr = new XMLHttpRequest();
else
return null;

var method = form.method ? form.method.toUpperCase() : "GET";
var action = form.action ? form.action : document.URL;
var data = getFormData(form);

var url = action;
if (data && method == "GET")
url += "?" + data;
xhr.open(method, url, true);

function submitCallback() {
if (callback && xhr.readyState == 4 && xhr.status == 200)
callback(xhr);
...
}
xhr.onreadystatechange = submitCallback;

xhr.setRequestHeader("Ajax-Request", "Auto-Save");
if (method == "POST") {
xhr.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
xhr.send(data);
} else
xhr.send(null);

return xhr;
}

清單 25 展示了 submitAllForms() 函數,它發送當前 Web 頁面包含的所有表單數據。此外,此函數從內存中刪除以前的 XMLHttpRequest 對象,以防止 Web 頁面中的內存泄漏。


清單 25. AutoSaveScript.js 的 submitAllForms() 函數
            
var autoSaveXHR = new Array();

function submitAllForms(callback) {
var formArray = document.forms;
for (var i = 0; i < formArray.length; i++) {
if (autoSaveXHR[i]) {
var oldXHR = autoSaveXHR[i];
oldXHR.onreadystatechange = function() { };
oldXHR.abort();
delete oldXHR;
}
autoSaveXHR[i] = submitFormData(formArray[i], callback);
}
}

SupportForm3.jsp 頁面(如清單 26 所示)是前面提供的 Web 表單的一個修改版本。此 JSP 頁面將 AutoSaveScript.js 導入其頁眉并定義一個回調函數,該函數在一個獨立窗口中顯示 Ajax 響應。該表單還包含第二個標記為 Submit with Ajax 的按鈕,這個按鈕調用 submitSupportForm() 函數返回 false ,因此該表單不會被 Web 瀏覽器重新提交。


清單 26. SupportForm3.jsp 示例
            
<%@ taglib prefix="df" tagdir="/WEB-INF/tags/dynamic/forms" %>

<jsp:useBean id="supportBean" scope="request" class="formsdemo.SupportBean"/>

<html>
<head>
...
<script type="text/javascript" src="AutoSaveScript.js">
</script>
<script type="text/javascript">
function ajaxCallback(xhr) {
confirmWindow=window.open("", "_blank",
"menubar=no, resizable=yes, scrollbars=yes, width=600, height=600");
confirmWindow.document.write(xhr.responseText);
confirmWindow.document.close();
}

function submitSupportForm() {
submitAllForms(ajaxCallback);
return false;
}
</script>
</head>
<body>
...
<df:form name="supportForm" model="${supportBean}"
action="SupportConfirm.jsp">
...
<df:input name="ajaxSubmit" type="submit" value="Submit with Ajax"
onclick="return submitSupportForm()"/>
</df:form>
</body>
</html>

結束語

在 本文中,學習了如何構建使用約定簡化 Web 開發的輕量型組件。只需不到 10K 的 JSP 代碼就可以實現一組標記文件,這些文件生成基本的表單元素:列表、文本字段、單選按鈕、復選框和提交按鈕。這些組件功能豐富,但缺少一些基本功能,比如數 據驗證和錯誤報告。請隨時關注本系列的下一篇文章,它將展示如何創建 JSP 標記文件來在服務器端執行驗證,以及在客戶端生成執行驗證的 JavaScript 代碼。








下載

描述 名字 大小 下載方法 本文的示例應用程序
wa-aj-simplejava2.zip 16KB HTTP


參考資料

  • 參與論壇討論 。

  • 您可以參閱本文在 developerWorks 全球站點上的 英文原文

  • 增強 JSF 頁面的外觀 ”(Andrei Cioroianu,developerWorks,2008 年 1 月)展示了如何實現標準 JSF 組件的默認樣式。這篇文章是 “聯合使用 CSS、JavaScript 和 JSF 精心打造 Ajax 應用程序” 系列的第一部分。

  • 使用 XMLHttpRequest 提交 JSF 表單 ” (Andrei Cioroianu,developerWorks,2007 年 8 月)包含 SupportForm.jsp 示例的基于 JSF 的版本,并且詳細描述了 AutoSaveScript.js 文件的 JavaScript 函數。這篇文章是 “借助 Ajax 自動保存 JSF 表單” 系列的第一部分。

  • developerWorks Web 開發專區 包含大量的 Web 2.0 開發工具和信息。

  • developerWorks Ajax 資源中心 包含不斷增加的大量 Ajax 內容以及有用資源,可以讓您立即開始開發 Ajax 應用程序。

  • 訪問 JSP Technology 主頁 獲得有關 JavaServer Pages 的更多信息。


關于作者


Andrei Cioroianu 是 Devsphere 公司的一名高級 Java 開發人員和顧問,該公司專門提供定制 Java EE 開發服務以及 Ajax/JSF 顧問服務。

簡化Ajax和Java開發


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美剧场成人精品午夜 | 红杏网站永久免费视频入口 | 日韩视频在线精品视频免费观看 | 亚洲精品在线免费观看视频 | 日韩国产在线观看 | 欧美激情二区三区 | 夜夜操av| 在线观看欧美成人 | 国产成人精品午夜 | 黄色日本视频 | 精品欧美一区二区在线观看 | 欧美3区 | 成人国产精品免费视频 | 国产九九在线视频 | 欧美性色生活片免费播放 | 成人二区| 欧美性第一页 | 91高清视频在线免费观看 | 日产国产欧美视频一区精品 | 亚洲成人在线视频播放 | 国产精品99在线观看 | 在线一区观看 | 亚洲成a人片在线网站 | 亚欧美| 天天看高清特色大片 | 国产精品免费入口视频 | 亚州a| 亚洲一区二区在线播放 | 一区二区三区国产免费 | 2021年无线乱码播放高清完整 | 日日射影院 | www.91p| 久久精品二区 | 天堂亚洲网 | 亚洲国产片高清在线观看 | 日本无码免费久久久精品 | 国产精品久久久久久久久久久久 | 日韩中文一区二区三区 | 麻豆影视在线 | 在线a视频网站 | 亚洲欧美中文日韩在线v日本 |