首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JSF 1.2 入門教學(二):生命週期、轉換器、驗證器與階段監聽器完整指南

     編輯:Java 相關知識

承接第一部分的基礎應用建立,本教程深入 JSF 1.2 核心進階特性:請求處理生命週期六階段、自訂資料轉換器、多層次驗證機制、階段監聽器 實作物件級驗證框架。透過持續擴充的「聯絡人管理 CRUD 系統」為例,示範如何善用 JSF 組件模型簡化開發。

聯絡人管理 CRUD 應用架構

單視圖 contacts.jsp 承載所有操作,後端包含:

  • ContactController (Request Scope) - JSF 控制器,管理表單狀態與動作
  • Contact - 領域模型 (含 firstName, lastName, group, tags, type 等屬性)
  • ContactRepository (Application Scope) - 資料存取介面 (CRUD)
  • faces-config.xml - 托管 Bean 宣告與依賴注入 (Repository 注入 Controller)

關鍵技術點:UIForm、UICommand 組件綁定控制表單顯示/隱藏與按鈕標籤切換;<h:dataTable> 以 var 映射列表項,搭配 <f:setPropertyActionListener> 於點擊編輯/刪除時將當前行物件注入 selectedContact。

常用 JSF 組件實戰

子視圖 <f:subview> 與 <jsp:include>

將表單與列表拆分為 form.jsp、listing.jsp,於主頁面包含,結構更清晰。JSF 1.2 中 <f:subview> 為可選,但部分 IDE 仍要求保留。

選擇類組件

組件後端渲染器適用場景
<h:selectOneMenu>HtmlSelectOneMenu單選下拉選單 (如 Group)
<h:selectOneRadio>HtmlSelectOneRadio單選按鈕群 (如 ContactType Enum)
<h:selectManyCheckbox>HtmlSelectManyCheckbox多選核取方塊 (如 Tags)
<h:selectManyListbox>HtmlSelectManyListbox多選清單框
<h:selectManyMenu>HtmlSelectManyMenu多選下拉選單
<h:selectBooleanCheckbox>HtmlSelectBooleanCheckbox布林值切換 (如 Active)
<h:inputTextarea>HtmlInputTextarea多行文字輸入 (如 Description)

Enum 直接綁定:JSF 1.2 內建 Enum 轉換器,<h:selectOneRadio value="#{contactController.contact.type}"> 可直接綁定 ContactType Enum 屬性,無需額外轉換器。

JSF 請求處理生命週期六階段

理解生命周期是掌握轉換/驗證時機的關鍵:

  1. 恢復視圖:FacesServlet 擷取 View ID,建立/恢復組件樹至 FacesContext.viewRoot。新視圖建立樹、初始視圖直接進入階段 6、Postback 還原狀態
  2. 應用請求值:從請求參數/ Cookie/ Header 取值存入組件 submittedValue。若 immediate="true" 此階段即轉換/驗證
  3. 處理驗證:轉換 submittedValue 為正確類型 → 執行驗證規則。失敗則加入錯誤訊息至 FacesContext,跳過後續階段直接進入階段 6
  4. 更新模型值:驗證通過後,將組件值更新至托管 Bean 屬性
  5. 調用應用程式:執行動作方法 (persist(), read()),導航規則解析下一個視圖
  6. 顯示響應:渲染視圖與所有組件當前狀態

開發者可呼叫 FacesContext.renderResponse() 直接跳至階段 6,或 responseComplete() 完全脫離 JSF 流程。

資料轉換器:標準與自訂

標準轉換器 (自動套用)

原始型別、包裝類別、String、Enum、BigDecimal/Integer/Double/Float/Boolean/Byte/Character/DateTime 皆有對應轉換器 (如 javax.faces.Integer → IntegerConverter)。

日期/數字格式需顯式指定:<f:convertDateTime pattern="MM/yyyy"/>、<f:convertNumber>。

自訂轉換器實作步驟

  1. 實作 javax.faces.convert.Converter 介面
  2. 實作 getAsObject(FacesContext, UIComponent, String):字串 → 物件 (如 ID → Group 物件)
  3. 實作 getAsString(FacesContext, UIComponent, Object):物件 → 字串 (如 Group → ID)
  4. 於 faces-config.xml 註冊 <converter>,指定 converter-for-class 為目標類別

範例:GroupConverter 從 Application Map 取得 GroupRepository 查詢物件,TagConverter 同理。註冊後,EL 綁定 #{contactController.contact.group} 即自動套用,無需 JSP 指定。

泛型限制:JSF 不支援 List<Tag> 直接轉換,解法為於 Model 提供 Tag[] getTags() / setTags(Tag[]) 陣列存取器。

驗證機制:四種形式完整解析

1. 內建驗證標籤

  • <f:validateLongRange minimum="0" maximum="150"/> (年齡)
  • <f:validateLength minimum="2" maximum="25"/> (姓名長度)
  • <f:validateDoubleRange>

2. 應用程式級驗證 (業務邏輯)

於動作方法 (persist()) 中呼叫 Model validate(),拋出自訂異常轉為 FacesMessage,回傳 null 留在當前視圖。優點:關注點分離、不需額外類別;缺點:執行時機最晚 (階段 5)。

3. 後端 Bean 內聯驗證方法

托管 Bean 定義 validatePhone(FacesContext, UIComponent, Object),於 JSP 以 validator="#{contactValidators.validatePhone}" 綁定。適合應用開發者,無需建立獨立類別。

4. 獨立自訂驗證器 (可重用組件)

  1. 實作 javax.faces.validator.Validator
  2. 實作 validate(FacesContext, UIComponent, Object) 拋出 ValidatorException
  3. faces-config.xml 註冊 <validator-id> 與 <validator-class>
  4. JSP 使用 <f:validator validatorId="..."/>

範例:ZipCodeValidator 使用 Regex 驗證郵遞區號格式。

轉換器與驗證器的協作關係

生命週期中 轉換先於驗證。若使用自訂 PhoneConverter 將字串轉為 PhoneNumber 物件並內建格式驗證,後續驗證器 (如 ContactValidators.validatePhone) 接收的即為 PhoneNumber 物件,可直接檢查領域邏輯 (如區碼必須為亞利桑那州 520/602)。此模式將格式驗證前置至轉換階段,業務驗證留至驗證階段,分工明確。

階段監聽器:擴展 JSF 流程控制

實作 PhaseListener 介面

public class DebugPhaseListener implements PhaseListener {
    public void beforePhase(PhaseEvent e) { 
        System.out.println("------ BEFORE PHASE " + e.getPhaseId()); 
    }
    public void afterPhase(PhaseEvent e) { 
        System.out.println("------ AFTER PHASE " + e.getPhaseId()); 
        if (e.getPhaseId() == PhaseId.RENDER_RESPONSE) 
            System.out.println("REQUEST END\n"); 
    }
    public PhaseId getPhaseId() { return PhaseId.ANY_PHASE; }
}

於 faces-config.xml 註冊 <lifecycle><phase-listener> 或 JSF 1.2 新增的視圖級綁定 <f:phaseListener binding="#{controller.phaseListener}"/>。

輸出分析範例

  • 初始載入:RESTORE_VIEW → RENDER_RESPONSE (直接跳過中間階段)
  • 點擊 Add New:完整六階段,INVOKE_APPLICATION 執行 addNew()
  • 提交無效資料:PROCESS_VALIDATIONS 階段執行轉換器與驗證器,失敗後直接 RENDER_RESPONSE
  • 提交有效資料:完整六階段,UPDATE_MODEL_VALUES 更新 Bean 屬性,INVOKE_APPLICATION 執行 persist()

實戰:物件級驗證框架

  1. 定義 Validateable 介面含 validate() throws ValidationException
  2. Model (Contact) 實作介面,封裝業務驗證邏輯 (如至少一組電話)
  3. 建立抽象基類 AbstractCrudController 內含匿名 PhaseListener,監聽 UPDATE_MODEL_VALUES 階段結束後呼叫 validate()
  4. 驗證失敗時呼叫 FacesContext.renderResponse() 跳過 INVOKE_APPLICATION,並加入錯誤訊息
  5. 子類 ContactController 實作 getFormObject() 依編輯模式回傳驗證目標
  6. JSP 綁定 <f:phaseListener binding="#{contactController.phaseListener}"/>

此模式將驗證邏輯下沉至領域模型,控制器僅協調流程,符合關注點分離原則,並可跨專案重用。

結語與資源建議

JSF 提供彈性、強大且可插拔的框架。標準轉換/驗證滿足快速原型,自訂機制支撐生產級複雜需求。注意轉換器輸出物件類型需與驗證器預期輸入一致。進階組件庫可參考 Tomahawk、Crank、Shale、jsf-comp。JSF 生命週期為資料完整性提供一致可靠的基礎設施,助力從原型到生產的平滑演進。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved