首先我們將介紹應(yīng)用于 JSF 生命周期的轉(zhuǎn)換和驗(yàn)證過程,然后展示一個(gè)簡單的 JSF 應(yīng)用程序中的默認(rèn)轉(zhuǎn)換和驗(yàn)證過程。接著將展示如何創(chuàng)建和插入自定義的實(shí)現(xiàn),以應(yīng)對要求更高的場景。正如 Rick 在以前的文章中所說的,我們會(huì)理論與實(shí)踐并重,先介紹概念,再用一個(gè)實(shí)際例子說明這些概念的應(yīng)用。示例應(yīng)用程序?qū)⒑w大多數(shù)轉(zhuǎn)換和驗(yàn)證用例,雖然只是初級的。
注意,示例應(yīng)用程序的默認(rèn)編譯環(huán)境是 Maven,不過, 還提供了一個(gè) Ant 腳本。可以單擊本頁頂部或者底部的 Code 圖標(biāo)下載示例源代碼。為了簡便起見,您會(huì)發(fā)現(xiàn),該例子的設(shè)置與上一篇文章中的一樣。關(guān)于構(gòu)建環(huán)境配置的更多說明,包括在 Ant 環(huán)境中而不是在 Maven 環(huán)境中編譯和運(yùn)行示例應(yīng)用程序的說明,請參閱 參考資料 。
轉(zhuǎn)換和驗(yàn)證
雖然在 JSF Web 應(yīng)用程序中使用轉(zhuǎn)換和驗(yàn)證不一定要理解 JavaServer Faces 生命周期的基礎(chǔ)知識(shí),但是在深入轉(zhuǎn)換和驗(yàn)證內(nèi)容之前,最好對一些基本知識(shí)做一回顧。此外,掌握一點(diǎn) JSF 生命周期技巧可以極大地幫助簡化 Web 應(yīng)用程序的開發(fā)工作。還有助于更好地理解 JSF 的可插入能力。
圖 1 描繪了我們所說的“基本 JSF 生命周期”。 基本 是在暗示這只是一個(gè)典型的處理所提交表單值的請求-響應(yīng)(request-and-response)場景。
顯然,不同的場景對這里重點(diǎn)描述的生命周期有不同的影響。我們將在本文稍后介紹其中一些場景。現(xiàn)在,只需要注意轉(zhuǎn)換和驗(yàn)證過程發(fā)生在 應(yīng)用請求值 、 處理驗(yàn)證 和 呈現(xiàn)響應(yīng) 階段即可。
我們將在稍后介紹為什么轉(zhuǎn)換和驗(yàn)證會(huì)在這些階段出現(xiàn),但是首先讓我們澄清一個(gè)更基本的問題: 轉(zhuǎn)換 是什么?簡單地說,轉(zhuǎn)換是確保數(shù)據(jù)擁有正確的對象或者類型的過程。下面是兩個(gè)典型的轉(zhuǎn)換:
-
字符串值可以轉(zhuǎn)換為
java.util.Date
。 - 字符串值可以轉(zhuǎn)換為 Float。
至于 驗(yàn)證 ,它用于確保數(shù)據(jù)包含所期望的內(nèi)容。下面是兩個(gè)典型的驗(yàn)證:
- java.util.Date 的格式為 MM/yyyy。
- Float 在 1.0 和 100.0 之間。
關(guān)注生命周期階段
轉(zhuǎn)換和驗(yàn)證的主要目的是確保在更新模型數(shù)據(jù)之前已經(jīng)經(jīng)過了正確的
無害處理
。之后,當(dāng)需要調(diào)用應(yīng)用程序方法用這些些數(shù)據(jù)實(shí)際
做一些事情
時(shí),就可以有把握地假定模型的某些狀態(tài)。轉(zhuǎn)換和驗(yàn)證使您可以側(cè)重于業(yè)務(wù)邏輯,而不是側(cè)重于對輸入數(shù)據(jù)進(jìn)行繁瑣的資格認(rèn)定,比如 null 檢驗(yàn)、長度限定、范圍邊界,等等。
因此,在 更新模型數(shù)據(jù) 生命周期階段中,在組件數(shù)據(jù)被綁定到 backing bean 模型 之前 進(jìn)行轉(zhuǎn)換和驗(yàn)證處理是有道理的。正如圖 1 所示,轉(zhuǎn)換發(fā)生在應(yīng)用請求值階段,而驗(yàn)證發(fā)生在處理驗(yàn)證階段。圖 2 突出顯示了這些階段。
圖 2. 要關(guān)注的轉(zhuǎn)換和驗(yàn)證階段
關(guān)于 immediate 屬性
注意,圖 2 中描繪的轉(zhuǎn)換和驗(yàn)證過程表示了將
UIInput
組件的
immediate
屬性設(shè)置為
false
時(shí)的應(yīng)用程序流程。如果這個(gè)屬性設(shè)置為
true
,那么轉(zhuǎn)換和驗(yàn)證會(huì)發(fā)生在生命周期更早的時(shí)期,即應(yīng)用請求值階段(參見圖 3)。對使用 immediate 屬性的詳細(xì)討論超出了本文的范圍,但是在某些情況下,比如管理動(dòng)態(tài)清單(可能您還記得,本系列的上一篇文章中曾介紹過),它很有用,它甚至可以繞過驗(yàn)證(在與
UICommand
組件結(jié)合使用時(shí))。能想像一個(gè)需要完全繞過驗(yàn)證的應(yīng)用程序嗎?
圖 3 展示了當(dāng)
immediate
屬性設(shè)置為
true
時(shí),在 JSF 應(yīng)用程序生命周期中的哪些地方進(jìn)行轉(zhuǎn)換和驗(yàn)證。
圖 3. 將 immediate 屬性設(shè)置為 true
實(shí)際的例子
下面,我們將用一個(gè)示例應(yīng)用程序展示所討論的概念。本月的示例應(yīng)用程序?qū)⒄故?JSF 的轉(zhuǎn)換和驗(yàn)證能力。記住,這個(gè)示例應(yīng)用程序非常簡單,沒有追求一些不必要的面面俱到:無論如何,我們的目的不是構(gòu)建一個(gè)在真實(shí)世界中使用的應(yīng)用程序!這個(gè)示例應(yīng)用程序?qū)⒄故疽韵聨c(diǎn):
- 使用標(biāo)準(zhǔn) JSF 轉(zhuǎn)換器轉(zhuǎn)換表單字段數(shù)據(jù)。
- 使用標(biāo)準(zhǔn) JSF 驗(yàn)證組件驗(yàn)證表單字段數(shù)據(jù)。
- 如何編寫自定義轉(zhuǎn)換器和驗(yàn)證器。
- 如何在 faces-config.xml 文件中注冊自定義轉(zhuǎn)換器和驗(yàn)證器。
- 如何定制默認(rèn)錯(cuò)誤消息。
這個(gè)示例應(yīng)用程序是一個(gè)簡單的用戶注冊表單。我們的目標(biāo)是收集用戶數(shù)據(jù),比如姓名、年齡、電子郵箱地址和電話號碼。然后,我們將展示如何利用 JSF 轉(zhuǎn)換和驗(yàn)證確保收集的數(shù)據(jù)對于模型是適合的。
這個(gè)應(yīng)用程序使用了三個(gè) JSP 頁:
- index.jsp 將用戶定向到 UserRegistration.jsp。
- UserRegistration.jsp 包含應(yīng)用程序的表單字段。
- results.jsp 通知應(yīng)用程序用戶已經(jīng)注冊。
我們將首先分析編寫 JSF 轉(zhuǎn)換過程的選擇。
JSF 轉(zhuǎn)換
如前所述,轉(zhuǎn)換是確保數(shù)據(jù)對象或者類型正確的一個(gè)過程,因此,我們將字符串值轉(zhuǎn)換為其他類型,比如
Date
對象、基本浮點(diǎn)型或者
Float
對象。可以使用自帶的轉(zhuǎn)換器,也可以編寫自定義的轉(zhuǎn)換器。
JSF 提供了許多標(biāo)準(zhǔn)數(shù)據(jù)轉(zhuǎn)換器。也可以通過實(shí)現(xiàn)
Converter
接口插入自定義轉(zhuǎn)換器,但是這些將在后面進(jìn)行介紹。下表顯示了 JSF 進(jìn)行簡單數(shù)據(jù)轉(zhuǎn)換所使用的轉(zhuǎn)換器
id
及其對應(yīng)的實(shí)現(xiàn)類。大多數(shù)數(shù)據(jù)轉(zhuǎn)換是自動(dòng)發(fā)生的。
javax.faces.BigDecimal
|
javax.faces.convert.BigDecimalConverter
|
javax.faces.BigInteger
|
javax.faces.convert.BigIntegerConverter
|
javax.faces.Boolean
|
javax.faces.convert.BooleanConverter
|
javax.faces.Byte
|
javax.faces.convert.ByteConverter
|
javax.faces.Character
|
javax.faces.convert.CharacterConverter
|
javax.faces.DateTime
|
javax.faces.convert.DateTimeConverter
|
javax.faces.Double
|
javax.faces.convert.DoubleConverter
|
javax.faces.Float
|
javax.faces.convert.FloatConverter
|
圖 4 展示了用戶年齡的默認(rèn)轉(zhuǎn)換。JSF 標(biāo)簽配置如下:
|
各種情況的轉(zhuǎn)換器
UserRegistration.user.age
表示一個(gè)值綁定屬性,它的類型為
int
。對于基本型或者
BigInteger
/
BigDecimal
的綁定,JSF 選擇了標(biāo)準(zhǔn)轉(zhuǎn)換器。不過,還可以通過
<f:converter/>
標(biāo)簽,利用一個(gè)特定的轉(zhuǎn)換器來增加粒度,如下所示。
|
在圖 5 中,可以看到 JSF 使用標(biāo)準(zhǔn)轉(zhuǎn)換器的場景。在這種情況下,雖然年齡實(shí)際上是一個(gè)有效的整數(shù),但轉(zhuǎn)換仍然會(huì)失敗,因?yàn)樵撝挡皇嵌陶偷摹?
選擇日期格式樣式
盡管在默認(rèn)情況下,JSF 可以很好地處理基本型及類似的類型,但是在處理日期數(shù)據(jù)時(shí),必須指定轉(zhuǎn)換標(biāo)簽
<f:convertDateTime/>
。這個(gè)標(biāo)簽基于
java.text
包,并使用短、長和自定義樣式。下面是一個(gè)例子:
|
這個(gè)例子展示了如何用
<f:convertDateTime/>
確保用戶的生日可以轉(zhuǎn)換為格式為 MM/yyyy(月/年)的日期對象。請參閱 JSF 的
java.text.SimpleDataFormat
(在
參考資料
中),以獲取模式列表。
其他樣式
除了可以轉(zhuǎn)換日期和時(shí)間格式外,JSF 還提供了處理像百分?jǐn)?shù)或者貨幣數(shù)據(jù)這類值的特殊轉(zhuǎn)換器。這個(gè)轉(zhuǎn)換器處理分組(如逗號)、小數(shù)、貨幣符號等。例如,以下
<f:convertNumber/>
的用法就是處理貨幣的一種技巧:
|
在圖 6 中,可以看到一些格式編排不正確的貨幣數(shù)據(jù),以及所導(dǎo)致的轉(zhuǎn)換錯(cuò)誤。
圖 6. 使用 f:convertNumber 標(biāo)簽
自定義轉(zhuǎn)換
如果需要將字段數(shù)據(jù)轉(zhuǎn)換為特定于應(yīng)用程序的值對象,則需要自定義數(shù)據(jù)轉(zhuǎn)換,如下面例子所示:
- String 轉(zhuǎn)換為 PhoneNumber 對象 (PhoneNumber.areaCode、PhoneNumber.prefix、 ...)。
- String 轉(zhuǎn)換為 Name 對象 (Name.first、Name.last)。
- String 轉(zhuǎn)換為 ProductCode 對象 (ProductCode.partNum、ProductCode.rev、 ...)。
要?jiǎng)?chuàng)建自定義轉(zhuǎn)換器,必須完成以步驟:
-
實(shí)現(xiàn)
Converter
接口(也就是javax.faxes.convert.Converter
)。
-
實(shí)現(xiàn)
getAsObject
方法,它將一個(gè)字段(字符串)轉(zhuǎn)換為一個(gè)對象(例如,PhoneNumber
)。
-
實(shí)現(xiàn)
getAsString
方法,它將一個(gè)對象(如PhoneNumber
)轉(zhuǎn)換為一個(gè)字符串。
-
在
Faces
上下文中注冊自定義轉(zhuǎn)換器。
-
用
<f:converter/>
標(biāo)簽在 JSP 中插入這個(gè)轉(zhuǎn)換器。
您可以自己看到如何在 JSF 應(yīng)用程序生命周期中加入這些步驟。在圖 7 中,JSF 在應(yīng)用請求值階段調(diào)用自定義轉(zhuǎn)換器的
getAsObject
方法。轉(zhuǎn)換器必須在這里將請求字符串轉(zhuǎn)換為所需的對象類型,然后返回這個(gè)對象,將它存儲(chǔ)在相應(yīng)的 JSF 組件中。如果該值被返回呈現(xiàn)在視圖中,那么 JSF 將在呈現(xiàn)響應(yīng)階段調(diào)用
getAsString
方法。這意味著轉(zhuǎn)換器還要負(fù)責(zé)將對象數(shù)據(jù)轉(zhuǎn)換回字符串表示形式。
圖 7. 自定義轉(zhuǎn)換器 getAsObject 和 getAsString 方法
創(chuàng)建自定義轉(zhuǎn)換器
我們將使用一個(gè)案例分析來展示
Converter
接口、
getAsObject
和
getAsString
方法的實(shí)現(xiàn),同時(shí)還將展示如何在
Faces
上下文中注冊這個(gè)轉(zhuǎn)換器。
這個(gè)案例分析的目的是將一個(gè)單字段字符串值轉(zhuǎn)換為一個(gè)
PhoneNumber
對象。我們將一步一步地完成這個(gè)轉(zhuǎn)換過程。
第 1 步:實(shí)現(xiàn) Converter 接口
這一步實(shí)現(xiàn)
Converter
接口。
|
第 2 步:實(shí)現(xiàn) getAsObject 方法
這一步將一個(gè)字段值轉(zhuǎn)換為一個(gè)
PhoneNumber
對象。
|
第 3 步:實(shí)現(xiàn) getAsString 方法
這一步將一個(gè)
PhoneNumber
對象轉(zhuǎn)換為一個(gè)字符串。
|
第 4 步:在 faces 上下文中注冊自定義轉(zhuǎn)換器
第 4 步可以以兩種方式執(zhí)行。第一種選擇使用(比如)
arcmind.PhoneConverter
的 id 來注冊
PhoneConverter
類。JSP 頁中的
<f:converter/>
標(biāo)簽會(huì)使用這個(gè) id。下面是第 4 步的選項(xiàng) 1 的代碼:
|
另一種方法是注冊
PhoneConverter
類來自動(dòng)處理所有
PhoneNumber
對象,如下所示。
|
第 5 步:在 JSP 中使用轉(zhuǎn)換器標(biāo)簽?
自然,下一步的執(zhí)行取決于所選的注冊方法。如果選擇使用
arcmind.PhoneConverter
的 id 來注冊
PhoneConverter
類,那么就使用
<f:converter/>
標(biāo)簽,如下所示。
|
如果選擇注冊
PhoneConverter
類來
自動(dòng)
處理所有
PhoneNumber
,那么就不需要在 JSP 頁中使用
<f:converter/>
標(biāo)簽。下面是第 5 步的不帶轉(zhuǎn)換器標(biāo)簽的代碼。
|
這樣,我們已經(jīng)完成了這個(gè)示例應(yīng)用程序的轉(zhuǎn)換處理代碼!到目前為止完成的應(yīng)用程序如下所示。
圖 8. 帶有轉(zhuǎn)換處理的示例應(yīng)用程序
JSF 驗(yàn)證
如前所述,JSF 驗(yàn)證可以確保應(yīng)用程序數(shù)據(jù)包含預(yù)期的內(nèi)容,例如:
- java.util.Date 為 MM/yyyy 格式。
- Float 在 1.0 和 100.0 之間。
在 JSF 中有 4 種驗(yàn)證:
- 自帶驗(yàn)證組件。
- 應(yīng)用程序級驗(yàn)證。
-
自定義驗(yàn)證組件(它實(shí)現(xiàn)了
Validator
接口)。 - 在 backing bean 中的驗(yàn)證方法(內(nèi)聯(lián))。
我們將在下面的討論中介紹并展示每一種形式。
JSF 驗(yàn)證生命周期和組件
圖 9 顯示了用戶注冊表單中名字字段的生命周期案例分析。代碼引用被有意解釋為偽代碼(pseudo-code)。
下面是 JSF 提供的一組標(biāo)準(zhǔn)驗(yàn)證組件:
-
DoubleRangeValidator
:組件的本地值必須為數(shù)字類型,必須在由最小和/或最大值所指定的范圍內(nèi)。
-
LongRangeValidator
:組件的本地值必須為數(shù)字類型,并且可以轉(zhuǎn)換為長整型,必須在由最小和/或最大值所指定的范圍內(nèi)。
-
LengthValidator
:類型必須為字符串,長度必須在由最小和/或最大值所指定的范圍內(nèi)。
標(biāo)準(zhǔn)驗(yàn)證
在我們的示例應(yīng)用程序中,用戶的年齡可以是任意有效的整數(shù)(byte、short、int)。因?yàn)閷⒛挲g設(shè)置為(比如說)
-2
是無意義的,所以可能要對這個(gè)字段添加一些驗(yàn)證。下面是一些簡單的驗(yàn)證代碼,用以確保年齡字段中的數(shù)據(jù)模型完整性:
|
完成年齡字段后,可能希望指定對名字字段的長度加以限制。可以像這樣編寫這個(gè)驗(yàn)證:
|
圖 10 顯示了由上面標(biāo)準(zhǔn)驗(yàn)證示例所生成的默認(rèn)詳細(xì)驗(yàn)證消息。
圖 10. 標(biāo)準(zhǔn)驗(yàn)證錯(cuò)誤消息
盡管 JSF 自帶的驗(yàn)證在許多情況下都可以滿足,但是它有一些局限性。在處理電子郵件驗(yàn)證、電話號碼、URL、日期等數(shù)據(jù)時(shí),有時(shí)編寫自己的驗(yàn)證器會(huì)更好一些,不過我們將在稍后對此進(jìn)行討論。
應(yīng)用程序級驗(yàn)證
在概念上,應(yīng)用程序級驗(yàn)證實(shí)際上是業(yè)務(wù)邏輯驗(yàn)證。JSF 將表單和/或字段級驗(yàn)證與業(yè)務(wù)邏輯驗(yàn)證分離開。應(yīng)用程序級驗(yàn)證主要需要在 backing bean 中添加代碼,用這個(gè)模型確定綁定到模型中的數(shù)據(jù)是否合格。對于購物車,表單級驗(yàn)證可以驗(yàn)證輸入的數(shù)量是否有效,但是需要使用業(yè)務(wù)邏輯驗(yàn)證檢查用戶是否超出了他或者她的信用額度。這是在 JSF 中分離關(guān)注點(diǎn)的另一個(gè)例子。
例如,假定用戶單擊了綁定到某個(gè)操作方法的按鈕,那么就會(huì)在調(diào)用應(yīng)用程序階段調(diào)用這個(gè)方法(有關(guān)的細(xì)節(jié),請參見上面的 圖 1 )。假定在更新模型階段進(jìn)行了更新,那么在對模型數(shù)據(jù)執(zhí)行任何操縱之前,可以添加一些驗(yàn)證代碼,根據(jù)應(yīng)用程序的業(yè)務(wù)規(guī)則檢查輸入的數(shù)據(jù)是否有效。
例如,在這個(gè)示例應(yīng)用程序中,用戶單擊了
Register
按鈕,這個(gè)按鈕被綁定到應(yīng)用程序控制器的
register()
方法。我們可以在
register()
方法中添加驗(yàn)證代碼,以確定名字字段是否為 null。如果該字段為 null,那么還可以在
FacesContext
中添加一條消息,指示相關(guān)組件返回到當(dāng)前頁。
其實(shí)它現(xiàn)在并不是業(yè)務(wù)規(guī)則邏輯的一個(gè)好例子。更好的例子是檢查用戶是否超出了她或者她的信用額度。在該例中,不是檢查字段是否為空,我們可以調(diào)用模型對象的方法來確保當(dāng)前用戶已經(jīng)不在系統(tǒng)中。
圖 11 描繪了這個(gè)過程。
注意在
register()
方法中,消息是如何以
${formId}:${fieldId}
的形式添加到
FacesContext
中的。圖 12 顯示了消息與組件 id 之間的關(guān)系。
應(yīng)用程序級驗(yàn)證的優(yōu)缺點(diǎn)
應(yīng)用級驗(yàn)證非常直觀并且容易實(shí)現(xiàn)。不過,這種形式的驗(yàn)證是在其他形式的驗(yàn)證(標(biāo)準(zhǔn)、自定義、組件)之后發(fā)生的。
應(yīng)用程序級驗(yàn)證的優(yōu)點(diǎn)如下:
- 容易實(shí)現(xiàn)。
- 不需要單獨(dú)的類(自定義驗(yàn)證器)。
- 不需要頁編寫者指定驗(yàn)證器。
應(yīng)用程序級驗(yàn)證的缺點(diǎn)如下:
- 在其他形式的驗(yàn)證(標(biāo)準(zhǔn)、自定義)之后發(fā)生。
- 驗(yàn)證邏輯局限于 backing bean 方法,使得重用性很有限。
- 在大型應(yīng)用程序和/或團(tuán)隊(duì)環(huán)境中可能難于管理。
最終,應(yīng)用程序級驗(yàn)證只應(yīng)該用于那些需要業(yè)務(wù)邏輯驗(yàn)證的環(huán)境中。
自定義驗(yàn)證組件
對于標(biāo)準(zhǔn) JSF 驗(yàn)證器不支持的數(shù)據(jù)類型,則需要建立自己的自定義驗(yàn)證組件,其中包括電子郵件地址和郵政編碼。如果需要明確控制顯示給最終用戶的消息,那么還需要建立自己的驗(yàn)證器。在 JSF 中,可以創(chuàng)建可在整個(gè) Web 應(yīng)用程序中重復(fù)使用的可插入驗(yàn)證組件。
MyFaces 是一個(gè) JSF 的開放源代碼實(shí)現(xiàn),它提供了許多額外的驗(yàn)證器,其中包括一些 JSF 中所沒有的驗(yàn)證器。要了解 MyFaces 的內(nèi)容,請參閱 參考資料 。 |
創(chuàng)建自定義驗(yàn)證器的步驟如下,我們將一步步地分析:
-
創(chuàng)建一個(gè)實(shí)現(xiàn)了
Validator
接口的類 (javax.faces.validator.Validator
)。
-
實(shí)現(xiàn)
validate
方法。
-
在 faces-confix.xml 文件中注冊自定義驗(yàn)證。
-
在 JSP 頁中使用
<f:validator/>
標(biāo)簽。
下面是創(chuàng)建自定義驗(yàn)證器的分步示例代碼。
第 1:實(shí)現(xiàn) Validator 接口
第一步是實(shí)現(xiàn)
Validator
接口。
|
第 2 步:實(shí)現(xiàn)驗(yàn)證方法
接下來,需要實(shí)現(xiàn)
validate
方法。
|
第 3 步:在 FacesContext 中注冊自定義驗(yàn)證器
您現(xiàn)在應(yīng)該熟悉在
FacesContext
中注冊自定義驗(yàn)證器的代碼了。
|
第 4 步:在 JSP 中使用 <f:validator/> 標(biāo)簽
<f:validator/>
標(biāo)簽聲明使用
zipCodeValidator
。
<f:attribute/>
標(biāo)簽將
plus4Optional
屬性設(shè)置為
true
。注意,它定義了
inputText
組件的屬性,而
不是
驗(yàn)證器的屬性!
|
為了讀取
zipCode
inputText
組件的
plus4Optional
屬性,請完成以下步驟::
|
總體而言,創(chuàng)建自定義驗(yàn)證器是相當(dāng)直觀的,并且可以使該驗(yàn)證在許多應(yīng)用程序中重復(fù)使用。缺點(diǎn)是必須創(chuàng)建一個(gè)類,并在 faces 上下文中管理驗(yàn)證器注冊。不過,通過創(chuàng)建一個(gè)使用這個(gè)驗(yàn)證器的自定義標(biāo)簽,使其看上去像是一個(gè)自帶的驗(yàn)證,可以進(jìn)一步實(shí)現(xiàn)自定義驗(yàn)證器。對于常見的驗(yàn)證問題,如電子郵件驗(yàn)證,這種方法可以支持這樣一種設(shè)計(jì)理念,即代碼重用和一致的應(yīng)用程序行為是最重要的。
backing bean 中的驗(yàn)證方法
作為創(chuàng)建單獨(dú)的驗(yàn)證器類的替代方法,可以只在 backing bean 的方法中實(shí)現(xiàn)自定義驗(yàn)證,只要這個(gè)方法符合
Validator
接口的
validate
方法的參數(shù)簽名即可。例如,可以編寫以下方法:
|
之后,可通過如下所示的
validator
屬性在 JSF 中使用這個(gè)方法:
|
JSF 用
validateEmail
方法對綁定到
user.email
模型屬性的
inputText
組件值進(jìn)行自定義驗(yàn)證。如果電子郵件格式無效,那么就在相關(guān)組件的 faces 上下文中添加消息。考慮到這種驗(yàn)證方法實(shí)際上是 backing bean 的一部分,為什么通常必須用某個(gè)值與相關(guān)組件的關(guān)聯(lián)來評估該值,而不是直接檢查本地 bean 屬性呢?線索就在前面的生命周期圖中。如果現(xiàn)在不能馬上找到答案,也不要擔(dān)心,我們將在本文的最后對此加以說明。
默認(rèn)驗(yàn)證
注意上面
email
標(biāo)簽的
required
屬性。利用
required
屬性是一種
默認(rèn)
驗(yàn)證形式。如果這個(gè)屬性是
true
,那么相應(yīng)的組件必須有一個(gè)值。一個(gè)重要的說明:如果
required
屬性為
false
,那么就不用對這個(gè)標(biāo)簽/組件指派驗(yàn)證,這樣,JSF 將跳過對這個(gè)組件的驗(yàn)證,并讓值和組件的狀態(tài)保持不變。
圖 13 概述了我們討論過的驗(yàn)證形式。
自定義消息
您可能注意到了,JSF 提供的默認(rèn)轉(zhuǎn)換和驗(yàn)證消息非常長,這會(huì)讓那些總是輸入無效表單數(shù)據(jù)的最終用戶感到困惑和惱火。幸運(yùn)的是,您可以通過創(chuàng)建自己的消息資源綁定來改變 JSF 提供的默認(rèn)消息。jsf-impl.jar (或類似的文件中)中包含了一個(gè) message.properties 文件,該文件包含圖 14 所示的默認(rèn)消息。
圖 14. 默認(rèn) JSF 轉(zhuǎn)換和驗(yàn)證消息
通過創(chuàng)建自己的 message.properties 文件并斷開指定場所的 faces 上下文中綁定的消息資源,您可以更改默認(rèn)消息,如圖 15 所示。
關(guān)于在 JSF 中創(chuàng)建自定義轉(zhuǎn)換和驗(yàn)證消息的更多內(nèi)容請參前閱 參考資料 。
處理 JSF 生命周期
我們在本文前面留下了一些問題讓您考慮,現(xiàn)在可以解決它們了!我們提到的一件事是對
UICommand
按鈕使用
immediate 屬性
,比如
commandLink
或者
commandButtons
。現(xiàn)在請您考慮希望在什么樣的場景中跳過驗(yàn)證。
基本上只要用戶需要輸入數(shù)據(jù),就需要對這個(gè)數(shù)據(jù)進(jìn)行驗(yàn)證。不過,如果整個(gè)數(shù)據(jù)項(xiàng)是可選的,那么就不需要進(jìn)行驗(yàn)證。一種避免 JSF 生命周期的驗(yàn)證階段的方法是利用
UICommand
組件的
immediate
屬性,該屬性可以在處理驗(yàn)證階段
之前
的應(yīng)用請求值階段期間(而不是在處理驗(yàn)證階段
之后
的調(diào)用應(yīng)用程序階段)強(qiáng)制調(diào)用這個(gè)操作。
immediate
屬性允許您通過標(biāo)準(zhǔn)瀏覽規(guī)則控制頁流程,并繞過驗(yàn)證。可以針對特定的場景實(shí)現(xiàn)這項(xiàng)技術(shù),比如帶有可選步驟和/或表單的在線向?qū)Вㄈ绠?dāng)用戶單擊
Skip
按鈕以進(jìn)入下一視圖),或者在用戶因?yàn)槟撤N原因而取消某個(gè)表單的情況下。
我們在本文中留下的第二個(gè)問題是:既然驗(yàn)證方法實(shí)際上是 backing bean 的一部分,那么為什么通常必須利用組件關(guān)聯(lián)來判斷它的值。請參閱前面的 JSF 應(yīng)用程序生命周期 ,看看您能否找到答案。
這里的密訣是:盡管
validateEmail
嵌入驗(yàn)證方法是實(shí)際的 backing bean 的一部分,但是該方法必須通過組件關(guān)聯(lián)來引用這,而不是直接訪問本地屬性來引用值。由于驗(yàn)證發(fā)生在組件值綁定到模型
之前
(在更新模型值階段),所以模型處于未知狀態(tài)。因此,必須編寫嵌入自定義驗(yàn)證邏輯,就像使用一個(gè)自定義
Validator
對象處理驗(yàn)證一樣。這也解釋了維護(hù)相同方法簽名的需求。
這些尚待解決的枝節(jié)問題有什么意義呢,當(dāng)然,它們最終將我們帶回 JSF 應(yīng)用程序生命周期。將這些問題匯總在一起,就能體現(xiàn)充分理解生命周期的重要性 —— 向后、向前或由內(nèi)向外,這樣您就可以在需要的時(shí)候操縱它。
結(jié)束語
在本文中我們討論了相當(dāng)多的 JSF 轉(zhuǎn)換和驗(yàn)證的基本內(nèi)容。事實(shí)上,我們討論了在自己的應(yīng)用程序中使用這些過程需要知道的大部分內(nèi)容(至少對這個(gè)版本的 JSF 而言)!
當(dāng)然,我們不可能討論到 所有內(nèi)容 。例如,您可能想要了解 MyFaces (請參閱 參考資料 )中 JSF 沒有提供、或者這里沒有討論到的驗(yàn)證器組件。此外,雖然我們討論了大多數(shù)常用的轉(zhuǎn)換和驗(yàn)證技術(shù),但還有一些沒有包含在內(nèi)。例如,在編寫自定義組件時(shí),可以在組件的解碼/編碼過程中直接處理轉(zhuǎn)換和/或驗(yàn)證(取決于組件的類型及其功能),但是我們只能將對自定義組件開發(fā)的更深入討論留到以后進(jìn)行了。
其他要牢記的是轉(zhuǎn)換和驗(yàn)證不一定會(huì)很好地協(xié)同工作。轉(zhuǎn)換將字符串轉(zhuǎn)換為對象,而大多數(shù)標(biāo)準(zhǔn)驗(yàn)證是對字符串進(jìn)行的。因此,在同時(shí)使用自定義轉(zhuǎn)換和驗(yàn)證必須格外小心。例如,
PhoneNumber
對象不能與長度驗(yàn)證器一起使用。在這種情況下,要么編寫自定義驗(yàn)證器,要么在自定義轉(zhuǎn)換器中添加一個(gè)特別的驗(yàn)證邏輯。我們偏向后一種方法,因?yàn)樗屛覀兛梢詫⒆远x轉(zhuǎn)換器(自帶驗(yàn)證邏輯)與特定的對象類型相關(guān)聯(lián),并讓 JSF 處理這種對象類型。JSF 自動(dòng)為我們做這項(xiàng)工作,不需要在 JSP 中包含任何特定的轉(zhuǎn)換器 id。(當(dāng)然,有人會(huì)稱它為懶惰編程,它也不是對所有用例都適用的最佳解決方案。)
我們認(rèn)為本月文章中的討論再次聲明了以下這點(diǎn),即 JSF 提供了一種靈活的、強(qiáng)大的可插入式 Web 應(yīng)用程序開發(fā)框架。除了標(biāo)準(zhǔn)轉(zhuǎn)換器和驗(yàn)證器之外,JSF 還可以促進(jìn)同時(shí)滿足應(yīng)用程序和框架開發(fā)人員的要求的自定義實(shí)現(xiàn)。最終,要由您來確定選擇何種轉(zhuǎn)換和驗(yàn)證策略。JSF 使您能夠在原型制造階段很快、很容易地上手(標(biāo)準(zhǔn)轉(zhuǎn)換器、驗(yàn)證器、內(nèi)部驗(yàn)證等),并在以后的開發(fā)階段移植到更復(fù)雜的生產(chǎn)解決方案中(自定義對象、自定義消息等)。JSF 生命周期在所有階段都提供了可靠的基礎(chǔ)設(shè)施,始終如一地保證數(shù)據(jù)模型的完整性。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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