所謂的即時事件(Immediate Events),是指JSF視圖元件在取得請求中該取得的值之後,即立即處理指定的事件,而不再進行後續的轉換器處理、驗證器處理、更新模型值等流程。
在JSF的事件模型中會有所謂即時事件,導因於Web應用程式的先天特性不同於GUI程式,所以JSF的事件模式與GUI程式的事件模式仍有相當程度的不同,一個最基本的問題正因為HTTP無狀態的特性,使得Web應用程式天生就無法直接喚起伺服端的特定物件。
所有的物件喚起都是在伺服端執行的,至於該喚起什麼物件,則是依一個基本的流程:
- 回復畫面(Restore View)
依客戶端傳來的session資料或伺服端上的session資料,回復JSF畫面元件。
- 套用請求值(Apply Request Values)
JSF畫面元件各自獲得請求中的值屬於自己的值,包括舊的值與新的值。
- 執行驗證(Process Validations)
轉換為物件並進行驗證。
- 更新模型值(Update Model Values)
更新Bean或相關的模型值。
- 喚起應用程式(Invoke Application)
執行應用程式相關邏輯。
- 繪製回應畫面(Render Response)
對先前的請求處理完之後,產生畫面以回應客戶端執行結果。
對於動作事件(Action Event)來說,元件的動作事件是在套用請求值階段就生成ActionEvent物件了,但相關的事件處理並不是馬上進行,ActionEvent會先被排入佇列,然後必須再通過驗證、更新模式值階段,之後才處理佇列中的事件。
這樣的流程對於按下按鈕然後執行後端的應用程式來說不成問題,但有些事件並不需要這樣的流程,例如只影響畫面的事件。
舉個例子來說,在表單中可能有使用者名稱、密碼等欄位,並提供有一個地區選項按鈕,使用者可以在不填下按鈕的情況下,就按下地區選項按鈕,如果依照正常的流程,則會進行驗證、更新模型值、喚起應用程式等流程,但顯然的,使用者名稱與密碼是空白的,這會引起不必要的錯誤。
您可以設定元件的事件在套用請求值之後立即被處理,並跳過後續的階段,直接進行畫面繪製以回應請求,對於JSF的input與command元件,都有一個immediate屬性可以設定,只要將其設定為true,則指定的事件就成為立即事件。
一個例子如下:
- index.jsp
<%@ 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:
- UserBean.java
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";
}
}
}
- faces-config.xml
<?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>
訊息資源檔的內容則是如下:
- messages_en.properties
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就請自行設計了,程式的畫面如下: