JSF框架整理(一)
一、框架簡介
JavaServer Faces (JSF) 是一種用於構建Java Web 應用程式的標準框架,它提供了一種以元件為中心的使用者介面(UI)構建方法,從而簡化了Java伺服器端應用程式的開發。
典型的JSF應用程式包含下列部分:
-
一組JSP頁面
-
一組後臺bean(為在一個頁面上的UI元件定義的屬性和函式的JavaBean元件)
-
應用程式配置資原始檔(定義頁面導航規則、配置bean和其它的自定物件,如自定義元件)
-
部署描述檔案(web.xml)
-
一組由應用程式開發者建立的自定義物件(有可能)
-
一些可能包含自定義元件、約束、轉換器或者監聽器的物件
-
為在頁面中表現自定義物件的一組自定義tag
包含JSP頁面的JSF應用程式也使用由為了表現UI元件和在頁面上的其他物件的JSF技術而定義的標準的tag庫。
二、JSF生命週期
JSF(JavaServer Faces)應用程式框架的簡單程式是自動管理生命週期階段,並允許您手動管理。JSF(JavaServer Faces)應用程式的生命週期從客戶端對頁面發出HTTP請求時開始,並在伺服器響應頁面時結束。
JSF生命週期分為兩個主要階段:
- 執行階段
- 渲染階段
1. 執行階段
在執行階段,當第一次請求時,構建或恢復應用程式檢視。 對於其他後續請求,執行其他操作,如應用請求引數值,對元件值執行轉換和驗證,受託管的bean
執行階段被進一步分成以下子階段。
- 恢復檢視階段
- 應用請求值階段
- 流程驗證階段
- 更新模型值階段
- 呼叫應用階段
- 渲染響應階段
當客戶端請求一個JavaServer Faces頁面時,JavaServer Faces實現開始恢復檢視階段。 在此階段,JSF將檢視中的元件構建為請求頁面,線性事件處理程式和驗證器的檢視,並將檢視儲存在FacesContext例項中。
如果對該頁面的請求是回發,那麼與該頁面相對應的檢視已經存在於FacesContext例項中。 在此階段,JavaServer Faces實現通過使用儲存在客戶端或伺服器上的狀態資訊來還原檢視。
在此階段,在回發請求期間恢復元件樹。 元件樹是表單元素的集合。樹中的每個元件通過使用其decode(processDecodes())
方法從請求引數中提取其新值。 之後,該值將本地儲存在每個元件上。
- 如果任何解碼方法或事件偵聽器在當前FacesContext例項上呼叫了renderResponse方法,則JavaServer Faces實現將跳過“渲染響應”階段。
- 如果任何事件在此階段已排隊,則JavaServer Faces實現將事件廣播到有興趣的監聽器。
- 如果應用程式需要重定向到其他Web應用程式資源或生成不包含任何JavaServer Faces元件的響應,則可以呼叫
FacesContext.responseComplete()
方法。 - 如果當前請求被識別為部分請求,則從FacesContext檢索部分上下文,並應用部分處理方法。
在此階段,JavaServer Faces通過使用其validate()
方法來處理在元件上註冊的所有驗證器。 它檢查指定驗證規則的元件屬性,並將這些規則與為元件儲存的本地值進行比較。 JavaServer Faces還完成了沒有將immediate
屬性設定為true
的輸入元件的轉換。
- 如果任何驗證方法或事件偵聽器在當前FacesContext上呼叫了
renderResponse
方法,則JavaServer Faces實現將跳過“渲染響應”階段。 - 如果應用程式需要重定向到不同的Web應用程式資源或生成不包含任何JavaServer Faces元件的響應,則可以呼叫
FacesContext.responseComplete
方法。 - 如果事件在此階段已排隊,則JavaServer Faces實現將它們廣播給有興趣的監聽器。
- 如果當前請求被識別為部分請求,則從FacesContext檢索部分上下文,並應用部分處理方法。
確保資料有效後,它遍歷元件樹,並將相應的伺服器端物件屬性設定為元件的本地值。 JavaServer Faces實現只更新輸入元件的value
屬性指向bean
屬性。 如果本地資料無法轉換為bean
屬性指定的型別,生命週期將直接前進到“渲染響應”階段,以便重新呈現頁面並顯示錯誤。
- 如果任何updateModels方法或任何監聽器在當前FacesContext例項上呼叫了
renderResponse()
方法,則JavaServer Faces實現將跳過“渲染響應”階段。 - 如果應用程式需要重定向到其他Web應用程式資源或生成不包含任何JavaServer Faces元件的響應,則可以呼叫
FacesContext.responseComplete()
方法。 - 如果任何事件在此階段已排隊,JavaServer Faces實現將它們廣播到有興趣的監聽器。
- 如果當前請求被識別為部分請求,則從FacesContext檢索部分上下文,並應用部分處理方法。
在此階段,JSF處理應用程式級事件,例如提交表單或連結到另一個頁面。
現在,如果應用程式需要重定向到其他Web應用程式資源或生成不包含任何JSF元件的響應,則可以呼叫FacesContext.responseComplete()
方法。
之後,JavaServer Faces實現將控制轉移到“渲染響應”階段。
這是JSF生命週期的最後階段。 在此階段,JSF將構建檢視並將許可權委託給相應的資源來呈現頁面。
- 如果這是初始請求,則頁面上表示的元件將被新增到元件樹中。
- 如果這不是初始請求,元件已經新增到樹中,不需要再新增。
- 如果請求是迴應,並且在應用請求值階段,過程驗證階段或更新模型值階段期間遇到錯誤,則在此階段將再次呈現原始頁面。
如果頁面包含h:message
或h:messages
標籤,頁面上會顯示任何排隊的錯誤訊息。
在渲染檢視的內容之後,儲存響應的狀態,以便後續請求可以訪問它。 恢復檢視階段可以使用儲存的狀態。
2. 渲染階段
在此階段,請求的檢視作為對客戶端瀏覽器的響應。 檢視渲染是以HTML或XHTML生成輸出的過程。 所以,使用者可以在瀏覽器看到它。
在渲染過程中採取以下步驟。
- 當客戶端對
index.xhtml
網頁進行初始請求時,編譯應用程式。 - 應用程式在編譯後執行,併為應用程式構建一個新的元件樹,並放置在FacesContext中。
- 使用由
EL
表示式表示的元件和與其關聯受託管bean
屬性填充元件樹。 - 基於元件樹。 建立了新的檢視。
- 該檢視作為響應呈現給請求客戶端。
- 元件樹被自動銷燬。
- 在後續請求中,重新構建元件樹,並應用已儲存的狀態。
三、JSF託管Bean
託管bean它是一個純Java類,它包含一組屬性和一組getter
,setter
方法。
以下是託管bean方法執行的常見功能:
- 驗證元件的資料
- 處理元件觸發的事件
- 執行處理以確定應用程式必須導航的下一頁
- 它也可以作為JFS框架的模型。
1、JSF託管Bean示例:
請看看下面一段示例程式碼 :
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
您可以通過以下方式使用此bean
。
- 通過配置成XML檔案。
- 通過使用註釋。
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>User</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
在xml檔案配置bean
是比較舊方法。 在這種方法中,我們必須建立一個名為faces-config.xml
的xml檔案,JSF提供了配置bean
的標籤。
在上面的例子中,我們列出了bean-name
,bean-class
和bean-scope
。 所以,它可以在專案中訪問。
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean // Using ManagedBean annotation
@RequestScoped // Using Scope annotation
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
類中的@ManagedBean
註解自動將該類註冊為JavaServer Faces的資源。 這種註冊的託管bean在應用程式配置資原始檔中不需要託管bean配置項。
@ManagedBean
將bean標識為名稱屬性中指定的名稱的託管bean。如果未指定name
屬性,那麼託管bean名稱將預設為簡單的類名稱,其中第一個字母小寫。 在我們的情況下是helloWorld
。
如果eager
設定為“true
”,則在請求之前建立託管bean。如果使用“lazy
”初始化,只有在請求時才會建立bean。
這是應用程式配置資原始檔方法的替代方法,並減少配置託管bean的任務。 @RequestScoped
註釋用於提供託管的範圍。 您可以使用註解來定義bean將被儲存的範圍。
@ManagedBean(name = "helloWorld", eager = true)
@RequestScoped
public class HelloWorld {
@ManagedProperty(value="#{message}")
private Message message;
...
}
您可以對bean類使用以下範圍:
- 應用程式(@ApplicationScoped):應用程式範圍在所有使用者中保持不變,與Web應用程式的互動。( bean只要Web應用程式生存。 它在第一個HTTP請求或Web應用程式啟動時建立,並且在
@ManagedBean
中設定屬性eager = true
,並在Web應用程式關閉時被銷燬)。 - 會話(@SessionScoped):會話範圍在Web應用程式中的多個HTTP請求中保持不變。(bean只要HTTP會話生存。 它在第一個HTTP請求時建立,並在HTTP會話無效時被銷燬)。
- 檢視(@ViewScoped):在使用者與Web應用程式的單個頁面(檢視)進行互動時,檢視範圍仍然存在。(bean只要使用者在瀏覽器視窗中與同一JSF檢視進行互動即可。 它根據HTTP請求建立,並在使用者導航到其他檢視時被銷燬)。
- 請求(@RequestScoped):在Web應用程式中的單個HTTP請求期間,請求範圍仍然存在。(bean只要HTTP請求響應就行。它根據HTTP請求建立,並在與HTTP請求相關聯的HTTP響應完成時被銷燬)。
- 無(@NoneScoped):表示未為應用程式定義作用域。(bean與單個表示式語言(EL)求值時間一樣長。 在EL求值評估時建立,並在EL求值評估後被銷燬)。
- 自定義(@CustomScoped):使用者定義的非標準作用域。 其值必須配置為
java.util.Map
,自定義範圍很少使用。(bean只要在為此範圍建立的自定義Map中的bean的條目生效)。
託管bean
預設是懶惰的。 這意味著,只有在從應用程式發出請求時才會去例項化bean。
如果想自動提前強制將bean
例項化,那麼可在應用程式啟動時,可以強制將bean
例項化並放置在應用程式(@ApplicationScoped
)範圍內。您需要將託管 bean 的eager
屬性設定為true
,如以下示例所示:
@ManagedBean(eager=true)
JSF是一個簡單的靜態依賴注入(DI)框架。 @ManagedProperty
註釋標記被託管的bean的屬性以注入另一個受託管的Bean。
2、如何進行bean注入
我們先定義一個訊息bean,它有一個字串屬性來儲存訊息。
@ManagedBean(name="message")
@SessionScoped
public class MessageBean implements Serializable {
private static final long serialVersionUID = 1L;
private String sayWelcome = "Welcome to JSF 2.0";
然後我們再定義另一個託管bean,並使用@ManagedProperty
註解注入MessageBean
。
@ManagedBean
@SessionScoped
public class UserBean implements Serializable {
private static final long serialVersionUID = 1L;
@ManagedProperty(value="#{message}")
private MessageBean messageBean;
public void setMessageBean(MessageBean messageBean) {
this.messageBean = messageBean;
}
例項:
建立一個名為: InjectManagedBeans 的工程,並加入以下檔案程式碼。
以下是檔案:UserBean.java 中的程式碼
package com.yiibai;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class UserBean implements Serializable {
private static final long serialVersionUID = 1L;
@ManagedProperty(value="#{message}")
private MessageBean messageBean;
public void setMessageBean(MessageBean messageBean) {
this.messageBean = messageBean;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSayWelcome(){
//check if null?
if("".equals(name) || name ==null){
return "";
}else{
return messageBean.getSayWelcome() + name;
}
}
}
以下是是檔案:index.xhtml 中的程式碼
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h:form>
<h:inputText id="name" value="#{userBean.name}"></h:inputText>
<h:commandButton value="Welcome Me">
<f:ajax execute="name" render="output" />
</h:commandButton>
<h2><h:outputText id="output" value="#{userBean.sayWelcome}" /></h2>
</h:form>
</h:body>
</html>
以下是檔案:MessageBean.java 中的程式碼
package com.yiibai;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="message")
@SessionScoped
public class MessageBean implements Serializable {
private static final long serialVersionUID = 1L;
private String sayWelcome = "Welcome to JSF 2.0";
public String getSayWelcome() {
return sayWelcome;
}
public void setSayWelcome(String sayWelcome) {
this.sayWelcome = sayWelcome;
}
}
執行測試結果:
Tomcat啟動完成後,在瀏覽器位址列中輸入以下URL。
http://localhost:8084/InjectManagedBeans/
執行結果如下所示