為了適應不同的應用程序需求和開發樣式,大部分 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 語法創建定制標記庫。此外,標記文件可以像 JSP 頁面一樣部署,而且不需要標記庫描述符(Tag Library Descriptor,TLD),因為它們使用由 JSP 標準定義的命名和設置約定,該標準還提供了在 JSP 標記文件中聲明標記屬性的指令。
更改時,應用服務器會重新編譯并加載一個 JSP 標記文件,而無需重新啟動應用程序,這使開發和測試都變得非常簡單。JSP 標記文件很快,因為它們受自動生成的 Java? 類支持,與將 JSP 頁面轉換為 Servlet 類很相似。
![]() |
|
本文將演示如何使用 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 實例。
Web 框架必須提供的一個主要功能是將 UI 組件綁定到數據模型的屬性。這意味著當 Web 頁面被請求時,框架必須從 JavaBean 對象獲取數據并將其包含到 HTML 表單中。用戶提交表單時,框架必須獲取請求參數并將更新值回存到數據模型中。例如,JSF 框架會讓您使用
value
屬性指定輸入組件的數據綁定(如清單 1 所示):
清單 1. JSF 數據綁定
|
必須在一個 XML 文件中為 JSF 配置數據模型,如清單 2 所示:
清單 2. 數據模型的 JSF 配置
|
本節演示如何使用 JSTL 和 JSP 標記文件實現相同的輸入組件。您可能想知道為什么 JSF 框架中的組件可用時還要這樣做。如果將本文中的
textarea.tag
文件與 JSF 框架中實現等價組件的 Java 類的源代碼相比較,您就會完全了解 JSP 標記文件帶來的好處。然后,請考慮一下您需要在 JSF 框架或另一個第三方庫未提供的其他組件上投入多少工作吧。
清單 3 展示了一個包含一個
<textarea>
元素的簡單 Web 表單,該元素的值是從一個
AddressBean
實例獲取的。
<jsp:useBean>
標記創建 JavaBean 對象并將其放到 JSP
request
作用域中。
address
屬性的值被包含在帶有 JSTL 標記
<c:out>
的 Web 頁面中。
清單 3. JSP 頁面使用 JSTL 對數據綁定進行編碼
|
當用戶單擊 Submit 按鈕時,Web 瀏覽器將用戶的輸入發回給相同的頁面,因為
<form>
元素沒有
action
屬性。然后,應用服務器執行 JSP 頁面,該頁面使用 JSTL 標記
<c:set>
將
address
參數的值存儲到
dataModel
bean 中。
如果比較清單 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()
使用
"
、
&
、
<
和
>
替換。
清單 4. textarea.tag 文件
|
清單 5 中顯示的 Web 頁面為包含標記文件的 JSP 庫聲明
df
前綴。然后,該頁面使用
<df:textarea>
組件生成
<textarea>
元素,該元素會讓用戶輸入
dataModel
對象的
address
屬性的值。
清單 5. 使用標記文件的 JSP 頁面
|
在我以前的文章 “增強 JSF 頁面的外觀”(參見
參考資料
)中,我展示了一種設置標準 JSF 組件的默認屬性的技術。我使用了一個定制 JSF 組件來遍歷視圖樹并設置每個組件的
styleClass
屬性,這非常適合于呈現單個 HTML 元素的簡單 JSF 組件。
生 成較大的 HTML 片段(比如一個樹或表)的非標準 JSF 組件可能不允許設置任何 HTML 元素的樣式。假設 JSF 組件使用 Java 代碼生成 HTML,如果要更改 HTML 元素的樣式,您的惟一選擇就是對 JSF 組件的呈現程序進行重新編碼。但是,如果使用 JSP 標記文件和 JSTL,將能夠全權訪問輸出 HTML 的 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 文件
|
skin
參數在 Web 應用程序的 web.xml 文件中指定(參見清單 7):
清單 7. 在 web.xml 中配置外觀參數
|
清單 8 展示了更改后的
textarea.tag
文件,它使用
<dfu:attrList>
輸出
<textarea>
元素的動態屬性:
清單 8. textarea.tag 的更新版本
|
樣式規則可以在 CSS 文件中定義。例如,如果想要更改
<df:textarea>
產生的每個
<textarea>
元素的邊框,只需編寫一個像清單 9 中那樣的樣式規則:
清單 9. 定義 <textarea> 元素的默認樣式
|
JSF 框架有一個復雜的請求處理生命周期,它可以劃分為 6 個不同的階段。很少有開發人員能夠完全理解它并進行定制。對于高流量的 Ajax 應用程序,需要使用一種更簡單的 HTTP 請求處理機制,以避免過高的 CPU 開銷。本節將展示如何借助 JSTL 和 JSP 標記文件輕松實現這一點。
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 文件
|
<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>
|
之前展示的
textarea.tag
文件不處理在設置與表單元素綁定的 JavaBean 屬性時可能發生的任何異常。這個問題可以使用
setProp.tag
文件解決(如清單 12 所示),如果出現轉換錯誤(比如
NumberFormatException
),該文件會使用 JSTL 標記
<c:catch>
捕捉 JavaBean 屬性的設置方法或者甚至是
<c:set>
標記可能拋出的任何異常:
清單 12. setProp.tag 文件
|
setProp.tag
文件用于設置擁有
<c:set>
接受的類型(比如
String
、
int
、
float
和
boolean
)的屬性和索引屬性,后者可能是
String
數組。如果發生了類型轉換錯誤或者拋出異常,addError.tag 文件(參見清單 13)就會將錯誤消息放入
formErrors
映射中:
清單 13. addError.tag 文件
|
textarea.tag 文件的最終版本(如清單 14 所示)使用
<dfu:setProp>
獲取 JavaBean 屬性。此外,標記文件會讓您在 JSP 頁面中
<df:textarea>
與
</df:textarea>
之間指定一個默認值。如果 bean 屬性的值為空,則標記文件使用
<jsp:doBody>
從 JSP 頁面獲取定制標記的內容。
清單 14. textarea.tag 的最終版本
|
迄今為止,您已經看到了如何創建自己的文本區域和表單組件,如何處理 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 文件
|
在 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 文件
|
清單 17 展示了 isSelected.tag 文件,該文件從
option.tag
調用。如果
array
屬性為
false
,則
isSelected.tag
文件將
value
屬性與
formModel[name]
進行比較。如果
array
屬性為
true
,則要求
formModel[name]
是一個數組,并且
isSelected.tag
將每個元素與
value
屬性進行比較。
清單 17. isSelected.tag 文件
|
isSelected.tag 的
<jsp:doBody>
標記執行
option.tag
中位于
<dfu:isSelected>
和
</dfu:isSelected>
之間的 JSP 代碼,在本例中主要輸出
selected
字符串。
<dfu:isSelected>
組件也用于 input.tag 中,用于驗證是否應該選擇一個單選按鈕。
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 文件
|
對于
submit
按鈕,input.tag 文件接受
action
屬性,該屬性用于指定一個頁面的 URL。當單擊
submit
按鈕時,該 URL 應該替換表單的操作。因此,一個表單可以有多個提交按鈕,每個按鈕可以將請求發送到不同頁面,以生成 HTML 響應。這與在配置文件中指定導航規則(如在 JSF 框架下)相比要簡單得多。
在我的另一篇文章 “使用 XMLHttpRequest 提交 JSF 表單”(參見
參考資料
)中,我展示了如何使用 Ajax 發送 Web 表單的數據。這篇文章還包含一個名為
SupportForm.jsp
的 JSF 示例。此處提供了一個類似的例子,便于您將 JSF 文章中的表單和基于本文 JSP 標記文件的 Web 表單進行比較。
創建 JavaBeans 或 Java Maps 支持的表單
SupportBean
類(見清單 19)是一個簡單的 bean,包含一些和示例 Web 表單的元素綁定的屬性:
清單 19. SupportBean 類
|
清單 20 展示了 SupportForm.jsp 頁面,該頁面使用本文前一節提供的標記文件庫。Web 組件擁有與它們生成的 HTML 元素相同的屬性。
<df:form>
標記擁有額外的
model
屬性,該屬性指定 JavaBean 對象(提交的表單數據將存儲在這里)。
清單 20. SupportForm.jsp 示例
|
SupportForm.jsp 中使用的
<df:form>
標記將 HTTP 請求轉發到 SupportConfirm.jsp 頁面(如清單 21 所示),該頁面的 URL 在
action
屬性中指定。該確認頁面輸出數據模型的屬性。
清單 21. SupportConfirm.jsp 頁面
|
JSP EL 和 JSTL 標記(比如
<c:set>
)訪問 JavaBean 的屬性和 Map 實例的元素時使用相同的語法。因此,可以使用一個
java.util.HashMap
來取代前面的例子中的
formsdemo.SupportBean
對象。惟一需要更改的是
<jsp:useBean>
標記中的類名稱(參見清單 22):
清單 22. SupportForm2.jsp 示例
|
“使用 XMLHttpRequest 提交 JSF 表單”(參見
參考資料
)完整地描述了 AutoSaveScript.js 文件(可以在源代碼歸檔文件中找到)。JavaScript 文件包含本文重用的一些函數。
getFormData()
函數(如清單 23 所示)接受一個
form
對象并返回編碼在一個字符串中的表單數據:
清單 23. AutoSaveScript.js 的 getFormData() 函數
|
AutoSaveScript.js 文件的
submitFormData()
函數(參見清單 24)有兩個參數:一個
form
對象和一個
callback
函數。前者的數據被 Ajax 發送到服務器,后者被調用來處理 Ajax 響應:
清單 24. AutoSaveScript.js 的 submitFormData() 函數
|
清單 25 展示了
submitAllForms()
函數,它發送當前 Web 頁面包含的所有表單數據。此外,此函數從內存中刪除以前的
XMLHttpRequest
對象,以防止 Web 頁面中的內存泄漏。
清單 25. AutoSaveScript.js 的 submitAllForms() 函數
|
SupportForm3.jsp 頁面(如清單 26 所示)是前面提供的 Web 表單的一個修改版本。此 JSP 頁面將 AutoSaveScript.js 導入其頁眉并定義一個回調函數,該函數在一個獨立窗口中顯示 Ajax 響應。該表單還包含第二個標記為
Submit with Ajax
的按鈕,這個按鈕調用
submitSupportForm()
函數返回
false
,因此該表單不會被 Web 瀏覽器重新提交。
清單 26. SupportForm3.jsp 示例
|
在 本文中,學習了如何構建使用約定簡化 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 顧問服務。 |
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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