JSF2.2 カスタムバリデーションの実施と独自タグの作成
JSFに標準でついているバリデーションを使っているのですが、小数の扱いに困ったのでカスタムバリデータ―を作成することにしました。小数点以下何桁まで許可するのかをパラメータで渡す必要があったのですが、バリデータの作成は結構資料があるんだけど、カスタムタグの方法があんまりない…有っても、JSF1の頃の資料とかで結構古い感じだったので、備忘録としてメモ■カスタムバリデータの作成すごく簡単。アノテーションをつけて、Validatorクラスを継承するだけ。例)半角英数字バリデーション※実際の半角チェック部分は省略import javax.faces.application.FacesMessage;import javax.faces.component.UIComponent;import javax.faces.context.FacesContext;import javax.faces.validator.FacesValidator;import javax.faces.validator.Validator;import javax.faces.validator.ValidatorException;import com.sun.faces.util.MessageUtils;/** * 半角英数字バリデーション */@FacesValidator("alphanumValid")public class AlphanumValidator implements Validator { @Override public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { if (context == null) throw new NullPointerException(); if (component == null) throw new NullPointerException(); if (value == null) return; String text = value.toString(); if (!CheckUtils.checkAlphanum(text)) { //ここで半角チェックを行う //メッセージ取得 FacesMessage fm = MessageUtils.getExceptionMessage("messgae.NOT_MATCHED"); throw new ValidatorException(fm); } }}アノテーション@FacesValidatorを付けることで、JSF1のときに必要だったfaces-config.xmlへの設定が不要になっています。便利。()内に別名を指定することも可能。この状態で、以下のようにタグを指定することで使用できます。<h:inputText type="text" id="alphaValue" label="半角英数字" value="#{testForm.alphaValue}"> <f:validator validatorId="alphanumValid" /></h:inputText>■カスタムバリデータをタグ化さらに上記バリデータをタグ化してみます。タグ化するためには、PartialStateHolderのimplementsが必要になります。多分多分…多分です…本当は要らないのかもしれないけど、参考にしたLengthValidatorなんかが継承していたので、とりあえずつけています。PartialStateHolderを追加することで、いろいろとメソッドの追加が必要になります。さっきの半角英数字バリデーションに、テスト用に引数onlyNumberを追加したのがこちら。import javax.faces.application.FacesMessage;import javax.faces.component.PartialStateHolder;import javax.faces.component.UIComponent;import javax.faces.context.FacesContext;import javax.faces.validator.FacesValidator;import javax.faces.validator.Validator;import javax.faces.validator.ValidatorException;import com.sun.faces.util.MessageUtils;/** * 半角英数字バリデーション */@FacesValidator("alphanumValid")public class AlphanumValidator implements Validator, PartialStateHolder { private Boolean onlyNumber; @Override public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { if (context == null) throw new NullPointerException(); if (component == null) throw new NullPointerException(); if (value == null) return; if (onlyNumber == null) onlyNumber = false; String text = value.toString(); if (!CheckUtils.checkAlphanum(text, onlyNumber)) { //メッセージ取得 FacesMessage fm = MessageUtils.getExceptionMessage("messgae.NOT_MATCHED"); throw new ValidatorException(fm); } } @Override public Object saveState(FacesContext context) { if (context == null) throw new NullPointerException(); Object values[] = new Object[3]; values[0] = this.onlyNumber; return values; } @Override public void restoreState(FacesContext context, Object state) { if (context == null) throw new NullPointerException(); if (state != null) { Object values[] = (Object[]) state; this.onlyNumber = (Boolean) values[0]; } } private boolean transientValue = false; private boolean initialState; @Override public boolean isTransient() { return transientValue; } @Override public void setTransient(boolean transientValue) { this.transientValue = transientValue; } @Override public void markInitialState() { this.initialState = true; } @Override public boolean initialStateMarked() { return this.initialState; } @Override public void clearInitialState() { this.initialState = false; }}restoreState、saveStateはそれぞれ引数の値の設定・復元を行います。それ以降のisTransient等は…よくわかりません。で、上記のように変更したら、次にカスタムタグの定義を行います。このあたりは、通常のカスタムタグを作成する場合と似たような形のようです。今回はWEB-IF/custom.taglib.xmlに作成しました。<?xml version="1.0" encoding="UTF-8"?><facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd" version="2.0"> <!-- validator tag --> <namespace>http://hogehoge/custom-taglib</namespace> <tag> <tag-name>ValideAlphanum</tag-name> <validator> <validator-id>alphanumValid</validator-id> </validator> <attribute> <name>onlyNumber</name> <required>true</required> </attribute> </tag></facelet-taglib>この定義内で、カスタムタグ内で使用する引数の設定を行います。attributeのところですね。requiredを指定すると、必須のパラメータにできます。これ以外の定義はまだちゃんと調べていません・・・ここまで定義したら、あとはxmlnsの宣言のところで、上記で作成したnamespaceを追加することで、カスタムバリデータタグが使えるようになります。たとえば、こんな感じに指定したら…<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:cf="http://hogehoge/custom-taglib">こんな感じで使えます。<h:inputText type="text" id="alphaValue" label="半角英数字" value="#{testForm.alphaValue}"> <f:ValideAlphanum onlyNumber="false" /></h:inputText>JSF1のころ?だと、カスタムタグ化するために、タグ用のクラスを生成したりしないといけなかったようですが、ずいぶん楽になったように思います。これで、相互チェックにも対応してくれていれば言うことないんですけど…そこはまだみたいですねえ