所謂的即時事件(Immediate Events),是指JSF視圖元件在取得請求中該取得的值之後,即立即處理指定的事件,而不再進行後續的轉換器處理、驗證器處理、更新模型值等流程。
在JSF的事件模型中會有所謂即時事件,導因於Web應用程式的先天特性不同於GUI程式,所以JSF的事件模式與GUI程式的事件模式仍有相當程度的不同,一個最基本的問題正因為HTTP無狀態的特性,使得Web應用程式天生就無法直接喚起伺服端的特定物件。
所有的物件喚起都是在伺服端執行的,至於該喚起什麼物件,則是依一個基本的流程:
依客戶端傳來的session資料或伺服端上的session資料,回復JSF畫面元件。
- 套用請求值(Apply Request Values)
JSF畫面元件各自獲得請求中的值屬於自己的值,包括舊的值與新的值。
- 執行驗證(Process Validations)
轉換為物件並進行驗證。
- 更新模型值(Update Model Values)
更新Bean或相關的模型值。
- 喚起應用程式(Invoke Application)
執行應用程式相關邏輯。
對先前的請求處理完之後,產生畫面以回應客戶端執行結果。
對於動作事件(Action Event)來說,元件的動作事件是在套用請求值階段就生成ActionEvent物件了,但相關的事件處理並不是馬上進行,ActionEvent會先被排入佇列,然後必須再通過驗證、更新模式值階段,之後才處理佇列中的事件。
這樣的流程對於按下按鈕然後執行後端的應用程式來說不成問題,但有些事件並不需要這樣的流程,例如只影響畫面的事件。
舉個例子來說,在表單中可能有使用者名稱、密碼等欄位,並提供有一個地區選項按鈕,使用者可以在不填下按鈕的情況下,就按下地區選項按鈕,如果依照正常的流程,則會進行驗證、更新模型值、喚起應用程式等流程,但顯然的,使用者名稱與密碼是空白的,這會引起不必要的錯誤。
您可以設定元件的事件在套用請求值之後立即被處理,並跳過後續的階段,直接進行畫面繪製以回應請求,對於JSF的input與command元件,都有一個immediate屬性可以設定,只要將其設定為true,則指定的事件就成為立即事件。
一個例子如下:
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@page contentType="text/html;charset=UTF8"%>
<f:view locale="#{user.locale}"> <f:loadBundle basename="messages" var="msgs"/>
<html> <head> <title><h:outputText value="#{msgs.titleText}"/></title> </head> <body>
<h:form> <h3><h:outputText value="#{msgs.hintText}"/></h3> <h:outputText value="#{msgs.nameText}"/>: <h:inputText value="#{user.name}"/><p> <h:outputText value="#{msgs.passText}"/>: <h:inputSecret value="#{user.password}"/><p> <h:commandButton value="#{msgs.commandText}" action="#{user.verify}"/> <h:commandButton value="#{msgs.Text}" immediate="true" actionListener="#{user.changeLocale}"/> </h:form>
</body> </html> </f:view>
這是一個可以讓使用者決定使用語系的示範,最後一個commandButton元件被設定了immediate屬性,當按下這個按鈕後,JSF套用請求值
之後會立即處理指定的actionListener,而不再進行驗證、更新模型值,簡單的說,就這個程式來說,您在輸入欄位與密碼欄位中填入的值,不會影
響您的user.name與user.password。
基於範例的完整起見,我們列出這個程式Bean物件及faces-config.xml:
package onlyfun.caterpillar;
import javax.faces.event.ActionEvent;
public class UserBean { private String locale = "en"; private String name; private String password; private String errMessage; public void changeLocale(ActionEvent e) { if(locale.equals("en")) locale = "zh_TW"; else locale = "en"; } public String getLocale() { if (locale == null) { locale = "en"; } return locale; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setPassword(String password) { this.password = password; } public String getPassword() { return password; } public void setErrMessage(String errMessage) { this.errMessage = errMessage; } public String getErrMessage() { return errMessage; } public String verify() { if(!name.equals("justin") || !password.equals("123456")) { errMessage = "名稱或密碼錯誤"; return "failure"; } else { return "success"; } } }
<?xml version="1.0"?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config> <navigation-rule> <from-view-id>/pages/index.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/pages/welcome.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>failure</from-outcome> <to-view-id>/pages/index.jsp</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <managed-bean-name>user</managed-bean-name> <managed-bean-class> onlyfun.caterpillar.UserBean </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>
訊息資源檔的內容則是如下:
titleText=JSF Demo hintText=Please input your name and password nameText=name passText=password commandText=Submit Text= \u4e2d\u6587
Text中設定的是「中文」轉換為Java Unicode Escape格式的結果,另一個訊息資源檔的內容則是英文訊息的翻譯而已,其轉換為Java Unicode Escape格式結果如下:
- messages_zh_TW.properties
titleText=JSF\u793a\u7bc4 hintText=\u8acb\u8f38\u5165\u540d\u7a31\u8207\u5bc6\u78bc nameText=\u540d\u7a31 passText=\u5bc6\u78bc commandText=\u9001\u51fa Text=English
welcome.jsp就請自行設計了,程式的畫面如下:


|