[特別企画]
JavaServer Facesを理解する
(後編)
JSFによるWebアプリケーション開発

 

  カスタムコンバータ、カスタムバリデータ、
タブハンドラ

カスタムコンバータ、カスタムバリデータ、タブハンドラクラスの実装

 次に、カスタムコンバータ、カスタムバリデータ、バリデータ用タグハンドラを説明しましょう。

 お客様情報入力画面(Customer.jsp)において入力されたクレジットカード番号を変換するためのコンバータは、CreditCardConverterです。

お客様情報入力画面(Customer.jsp)

 独自のコンバータを作成する場合は、javax.faces.convert.Converterインターフェイスをimplementsしたクラスを作成し、2つのメソッドを実装します。1つ目が、リクエストパラメータとして受け取ったStringなどを対応するモデルオブジェクトに変換するgetAsObjectメソッドで、Apply Request Valuesフェイズで呼び出されます。そして、2つ目がモデルデータを、プレゼンテーションとしてのStringに変換するgetAsStringメソッドで、Render Responseフェイズにおいて呼び出されます。

リスト5 CreditCardConverter.java
public class CreditCardConverter implements Converter {
    
    public Object getAsObject(
FacesContext context, UIComponent component, String newValue) 
throws ConverterException {
        String convertedValue = null;
        if ( newValue == null ) {
            return newValue;
        }
        convertedValue = newValue.trim();
        if ( ((convertedValue.indexOf("-")) != -1) || 
((convertedValue.indexOf(" ")) != -1)) {
            char[] input = convertedValue.toCharArray();
            StringBuffer buffer = new StringBuffer(50);
            for ( int i = 0; i < input.length; ++i ) {
                if ( input[i] == '-' || input[i] == ' '  ) {
                    continue;
                } else {
                    buffer.append(input[i]);
                }
            }
            convertedValue = buffer.toString();
        }           
        return convertedValue;
    }
     
    public String getAsString(
FacesContext context, UIComponent component, Object value)
 throws ConverterException {
    -- 省略 -- 
// モデルデータを、プレゼンテーションとしてのStringに変換するロジックを実装
    }
}

 入力されたクレジットカード番号のフォーマットが正しいかを検証するのがFormatValidatorクラスです。独自のValidatorを実装する際は、javax.faces.validator.Validatorインターフェイスをimplementsし、コンストラクタ、アクセッサメソッド、そして実際に値の検証を行うvalidateメソッドを実装します。

 validateメソッドでは、初めにユーザーが入力したクレジットカード番号を(((UIOutput)component).getValue()).toString()で取得し、この後紹介するFormatValidatorTag用のJSPカスタムタグのformatPatternsで、指定したフォーマットと一致するかを検証します。そして、検証の結果はバリデータが登録されているUIコンポーネントに、setValidメソッドで設定します。

 さて、前回紹介したguessNumberアプリケーションでは、ルールに反する範囲外の数値を入力した際に、エラーが表示されました。今回のアプリケーションでは、このメッセージの生成する部分の処理についても実装します。

 まず、メッセージ生成のためにgetMessageResourcesメソッドで、javax.faces.context.MessageResourcesのインスタンスを取得しています。MessageResourcesは、messageテンプレートのコレクションで、ローカライズされたjavax.faces.application.Messageインスタンスを構築するために使用し、ここでは「carShopResources」というIDで取得しています。そのMessageResourcesのgetMessage()メソッドを呼び出すことにより、Messageインスタンスを取得しFacesContextに登録することで、エラーメッセージがユーザーに返されます。

 なお、ここでは実際のメッセージ自体は記述していませんが、メッセージは後で説明するfaces-config.xml内に定義します。

リスト6 FormatValidator.java
public class FormatValidator implements Validator {
    
    public static final String FORMAT_INVALID_MESSAGE_ID 
= "carshop.Format_Invalid";
    private ArrayList formatPatternsList = null;
    private String formatPatterns = null;
    
    public FormatValidator(String formatPatterns) {
        super();
        this.formatPatterns = formatPatterns;
        parseFormatPatterns();
    }
    public String getFormatPatterns() {
        return (this.formatPatterns);
    }
    public void setFormatPatterns(String formatPatterns) {
        this.formatPatterns = formatPatterns;
        parseFormatPatterns();
    }
    public void parseFormatPatterns() {
    -- 省略 --
        StringTokenizer st =  new StringTokenizer(formatPatterns, "|");
        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            formatPatternsList.add(token);
        }
    }
    
    public void validate(FacesContext context, UIComponent component) {
     -- 省略 --
        String value = (((UIOutput)component).getValue()).toString();
        Iterator patternIt = formatPatternsList.iterator();
        while (patternIt.hasNext()) {
            valid = isFormatValid(((String)patternIt.next()), value);
            if (valid) {
                break;
            }
        }
        if (valid) {
            component.setValid(true);
        } else {
            component.setValid(false);
            Message errMsg = getMessageResources().getMessage(context, FORMAT_INVALID_MESSAGE_ID, 
(new Object[] {formatPatterns})); // メッセージを表すMessageの取得
            context.addMessage(component, errMsg); // FacesContextへのメッセージの登録
        }
    }
    
    protected boolean isFormatValid(String pattern, String value) {
     -- 省略 --
        value = value.trim();

        char[] input = value.toCharArray();
        char[] fmtpattern = pattern.toCharArray();
        for ( int i = 0; i < fmtpattern.length; ++i ) {
            if (!(Character.isDigit(input[i]))) {
                valid = false;
            }
        }
        return valid;
    }    
    
    public synchronized MessageResources getMessageResources() {
        MessageResources carResources = null;
        ApplicationFactory aFactory = (ApplicationFactory)FactoryFinder.getFactory(
FactoryFinder.APPLICATION_FACTORY);
        Application application = aFactory.getApplication();
carResources = application.getMessageResources("carShopResources");
        return (carResources);
    }

 FormatValidatorTagは、FormatValidatorをJSPで利用するためのタグハンドラクラスです。Validatorのタグハンドラを実装する際は、javax.faces.webapp.ValidatorTagクラスを継承します。

 FormatValidatorTagでは、まず、コンストラクタ内でsuper.setID("FormatValidator")を呼び出し、FormatValidatorというIDでこのValidatorを登録します。このIDは、faces-config.xml内にValidatorを登録するときのID(<validator-id>)と一致する必要があります。次に、createValidatorメソッドで、FormatValidarをインスタンス化し、JSPタグ内で指定したフォーマットをformatPatternsプロパティに設定しています。実際の値の検証は、先ほど作成したFormatValidator内で行いますので、タグハンドラの実装は以上になります。

リスト7 FormatValidatorTag.java
public class FormatValidatorTag extends ValidatorTag {
    
    protected String formatPatterns = null;    
    
    public FormatValidatorTag() {
        super();
        super.setId("FormatValidator");        
    }
    
    public String getFormatPatterns() {
        return formatPatterns;
    }

    public void setFormatPatterns(String fmtPatterns){
       formatPatterns = fmtPatterns;
    }
    
    protected Validator createValidator() throws JspException {
        
        FormatValidator result = null;
        result = (FormatValidator) super.createValidator();        
        result.setFormatPatterns(formatPatterns);
        
        return result;
    }
}

購入画面(buy.jsp)


3/4

 INDEX

JavaServer Facesを理解する(後編)
  Page1
JSFアプリケーションの構築
 

Page2
モデルとビジネスロジック

  Page3
カスタムコンバータ、カスタムバリデータ、タブハンドラ
Page4
UIコンポーネント、JSFタグライブラリを使用したJSPの作成
ページナビゲーションの定義
まとめ


INDEX
特別企画:JavaServer Facesを理解する
  前編 JSFの構造を理解する
後編 JSFによるWebアプリケーション開発



連載記事一覧






Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間