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

JSF 轉換與驗證深度解析:從生命週期到自訂實作完整指南

     編輯:Java 相關知識

JSF (JavaServer Faces) 內建強大的轉換與驗證框架,發生在請求處理生命週期的「應用請求值」與「處理驗證」階段。本文系統解析標準轉換器/驗證器、自訂實作步驟、錯誤訊息客製化、immediate 屬性機制與生命週期關鍵點。

一、JSF 生命週期與轉換/驗證切入點

基本生命週期階段:

  1. 還原視圖
  2. 應用請求值 ← 轉換發生此處
  3. 處理驗證 ← 驗證發生此處
  4. 更新模型值
  5. 調用應用程式
  6. 呈現響應 ← getAsString() 發生此處

轉換器 getAsObject() 在階段 2 執行,將請求字串轉為物件;驗證器 validate() 在階段 3 執行;getAsString() 在階段 6 將物件轉回字串呈現。

immediate 屬性改變執行時機

  • UIInput immediate="true":轉換+驗證提前至階段 2 (應用請求值)
  • UICommand immediate="true":動作調用提前至階段 2,跳過驗證,適用「取消」、「跳過」按鈕

二、標準轉換器 (自動/宣告式使用)

自動轉換範例




強制指定轉換器



     

日期/數字格式化




    




    

三、自訂轉換器開發步驟

場景:單一輸入欄位 (如 "1 886 2 1234567") 轉換為 PhoneNumber 物件 (countryCode, areaCode, prefix, number)。

1. 實作 Converter 介面


import javax.faces.convert.Converter;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

public class PhoneConverter implements Converter {
    // 字串 → 物件 (階段 2)
    public Object getAsObject(FacesContext ctx, UIComponent comp, String value) {
        if (value == null || value.trim().length() == 0) return null;
        PhoneNumber phone = new PhoneNumber();
        String[] parts = value.split("[\\s(),.-]+");
        phone.setCountryCode(parts[0]);
        if ("1".equals(parts[0])) { // 北美格式
            phone.setAreaCode(parts[1]);
            phone.setPrefix(parts[2]);
            phone.setNumber(parts[3]);
        } else {
            phone.setNumber(value);
        }
        return phone;
    }
    
    // 物件 → 字串 (階段 6)
    public String getAsString(FacesContext ctx, UIComponent comp, Object value) {
        return value.toString(); // 委託 PhoneNumber.toString()
    }
}

2. PhoneNumber 實體類別


public class PhoneNumber implements Serializable {
    private String countryCode, areaCode, prefix, number;
    // Getter/Setter...
    public String toString() {
        if ("1".equals(countryCode)) {
            return countryCode + " " + areaCode + " " + prefix + " " + number;
        }
        return number;
    }
}

3. faces-config.xml 註冊 (兩種方式)

方式 A:指定 Converter ID,JSF 頁面引用



    com.example.PhoneConverter
    com.example.converter.PhoneConverter

JSF 頁面:<f:converter converterId="com.example.PhoneConverter"/>

方式 B:針對目標類別自動套用 (推薦)



    com.example.model.PhoneNumber
    com.example.converter.PhoneConverter

JSF 頁面:無需任何標籤,綁定 PhoneNumber 型別屬性自動套用。

四、四種驗證機制

1. 標準驗證組件 (標籤式宣告)

Converter ID實作類別適用型別
javax.faces.BigDecimalBigDecimalConverterBigDecimal
javax.faces.BigIntegerBigIntegerConverterBigInteger
javax.faces.BooleanBooleanConverterBoolean/boolean
javax.faces.ByteByteConverterByte/byte
javax.faces.CharacterCharacterConverterCharacter/char
javax.faces.DateTimeDateTimeConverterDate/Calendar
javax.faces.DoubleDoubleConverterDouble/double
javax.faces.FloatFloatConverterFloat/float
javax.faces.IntegerIntegerConverterInteger/int
javax.faces.LongLongConverterLong/long
javax.faces.NumberNumberConverterNumber 子類
javax.faces.ShortShortConverterShort/short
驗證器標籤用途
DoubleRangeValidator<f:validateDoubleRange>數值在 min/max 範圍
LongRangeValidator<f:validateLongRange>長整數在 min/max 範圍
LengthValidator<f:validateLength>字串長度在 min/max 範圍


    


    

2. 應用程式層級驗證 (Backing Bean 方法)

業務邏輯驗證,如「信用額度檢查」、「用戶名唯一性」。在 Action 方法中執行:


public String register() {
    if (userService.exists(user.getUsername())) {
        FacesMessage msg = new FacesMessage("用戶名已存在");
        facesContext.addMessage("registerForm:username", msg);
        return null; // 留在當前頁
    }
    // 繼續註冊邏輯
    return "success";
}

訊息關鍵:clientId = formId:componentId,對應視圖組件顯示錯誤。

3. 自訂驗證器組件 (可重用、可配置)

步驟:

  1. 實作 javax.faces.validator.Validator
  2. 實作 validate(FacesContext, UIComponent, Object)
  3. faces-config.xml 註冊 <validator>
  4. JSF 頁面 <f:validator validatorId="..."/>

郵遞區號驗證器範例 (支援可選 +4 碼):


public class ZipCodeValidator implements Validator {
    private boolean plus4Required, plus4Optional;
    private static final String ZIP_REGEX = "[0-9]{5}";
    private static final String PLUS4_REQUIRED = "[ |-]{1}[0-9]{4}";
    private static final String PLUS4_OPTIONAL = "([ |-]{1}[0-9]{4})?";

    public void validate(FacesContext ctx, UIComponent comp, Object value) 
            throws ValidatorException {
        initProps(comp); // 讀取 f:attribute 設定
        String regex = ZIP_REGEX + (plus4Required ? PLUS4_REQUIRED : plus4Optional ? PLUS4_OPTIONAL : "");
        if (!Pattern.matches(regex, (String)value)) {
            FacesMessage msg = new FacesMessage("郵遞區號格式錯誤");
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(msg);
        }
    }
    private void initProps(UIComponent comp) {
        plus4Optional = Boolean.valueOf((String)comp.getAttributes().get("plus4Optional"));
        plus4Required = Boolean.valueOf((String)comp.getAttributes().get("plus4Required"));
    }
}

註冊:



    com.example.ZipCodeValidator
    com.example.validator.ZipCodeValidator

使用:



    
    

4. Backing Bean 內嵌驗證方法 (Inline Validator)

方法簽名必須符合 validate(FacesContext, UIComponent, Object):


// Backing Bean
public void validateEmail(FacesContext ctx, UIComponent comp, Object value) {
    String email = (String)value;
    if (email.indexOf('@') == -1) {
        ((UIInput)comp).setValid(false);
        FacesMessage msg = new FacesMessage("Email 格式錯誤");
        ctx.addMessage(comp.getClientId(ctx), msg);
    }
}

JSF 頁面:<h:inputText validator="#{userRegistration.validateEmail}"/>

關鍵: 驗證發生在「更新模型值」之前,故無法直接存取 Backing Bean 屬性,必須透過 UIComponent 取得提交值。

5. required 屬性 (最簡單驗證)



required="false" 時完全跳過該組件驗證。

五、錯誤訊息客製化

JSF 內建訊息在 jsf-impl.jar!/javax/faces/Messages.properties,內容冗長。客製化步驟:

  1. 建立 messages.properties (或 messages_zh_TW.properties)
  2. 覆寫鍵值,如:
    javax.faces.component.UIInput.REQUIRED = {0} 為必填欄位
    javax.faces.converter.DateTimeConverter.DATE = {0} 日期格式錯誤,請輸入 {1}
  3. faces-config.xml 註冊訊息包:


    com.example.messages

六、轉換與驗證協同注意事項

  • 轉換器產出物件 (如 PhoneNumber),標準驗證器 (如 LengthValidator) 只能驗證字串,**不可混用**
  • 解決方案:在自訂轉換器內嵌驗證邏輯 (拋 ConverterException),或撰寫對應物件型別的自訂驗證器
  • 自動關聯優勢:converter-for-class 讓 JSF 自動處理,無需頁面標籤

七、結語

JSF 轉換/驗證框架提供從原型到生產的平滑演進:標準組件快速起步、自訂組件構建領域驗證庫、訊息包統一用戶體驗。深度理解生命週期階段、immediate 屬性、轉換驗證順序,是掌握 JSF 資料完整性控制的關鍵。

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