バリデータとは、入力されたデータが、そのアプリケーションに適合するものかどうかチェックする機能のことです。
JSFの参照実装(Reference Implementation)では、次のようなバリデータが標準で搭載されています。
例を挙げると、バリデータを使うことによって「このh:inputTextは必須項目で、必ず何らかの文字列が入力されていなければならない」といったことを指定できるようになります。
バリデータに適合しなかった場合は、エラーメッセージを表示できます。
Tomahawk (JSFのオープンソース実装であるMyFacesに含まれている)には、次のようなバリデータが含まれています。
今回は、これらのバリデータを使ったプログラム例について解説します。
今回のサンプルプログラムは、1つめの画面で入力した文字列を、2つめの画面でそのまま表示するというものです。ただし、1つめの画面ではバリデータが設定されています。
まず、1つめの画面です(図9.1[1つめの画面])。
バリデータに適合しない文字列が入力された場合は、図9.2[バリデータに適合しなかった例]のような表示になります。
バリデータに適合した文字列が入力されると、2つめの画面(図9.3[2つめの画面に遷移(バリデータに適合)])に遷移します。
まず、最初に表示されるpage1.jspを示します。
<%@ page contentType="text/html; charset=Shift_JIS" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t" %> <html> <head> <link href="style.css" type="text/css" rel="stylesheet" /> <title>バリデータのテスト</title> </head> <body> <h1>バリデータのテスト</h1> <f:view> <h:form id="form"> <h:panelGrid columns="3"> <f:facet name="header"> <h:outputText value="入力してください" /> </f:facet> <h:outputText value="お名前を入力してください(必須)" /> <h:inputText id="name" required="true" value="#{ParameterBean.name}" /> <h:message for="name" styleClass="error" /> <h:outputText value="パスワードを設定してください(5文字以上)" /> <h:inputSecret id="password" value="#{ParameterBean.password}"> <f:validateLength minimum="5" /> </h:inputSecret> <h:message for="password" styleClass="error" /> <h:outputText value="品物の数を入力してください(1〜10)" /> <h:inputText id="quantity" value="#{ParameterBean.quantity}"> <f:validateLongRange minimum="1" maximum="10"/> </h:inputText> <h:message for="quantity" styleClass="error" /> <h:outputText value="e-mailアドレス(必須)" /> <h:inputText id="email" required="true" value="#{ParameterBean.email}"> <t:validateEmail /> </h:inputText> <h:message for="email" styleClass="error" /> <h:outputText value="もう一度e-mailアドレス" /> <h:inputText id="email2" required="true" value="#{ParameterBean.anotherEmail}"> <t:validateEqual for="email" /> </h:inputText> <h:message for="email2" styleClass="error" /> <h:outputText value="クレジットカードの番号" /> <h:inputText id="creditCardNumber" value="#{ParameterBean.creditCardNumber}"> <t:validateCreditCard /> </h:inputText> <h:message for="creditCardNumber" styleClass="error" /> <h:outputText value="郵便番号 (例: 097-0013)" /> <h:inputText id="zipNumber" value="#{ParameterBean.zipNumber}"> <t:validateRegExpr pattern='\d{3}-\d{4}' /> </h:inputText> <h:message for="zipNumber" styleClass="error" /> </h:panelGrid> <p> <h:commandButton id="button" action="success" value="Go!" /> </p> </h:form> </f:view> </body> </html>
このJSPでは、UIコンポーネントを表形式でレイアウトするため、h:panelGridというタグを使っています。
<h:panelGrid columns="3"> <f:facet name="header"> <h:outputText value="入力してください" /> </f:facet> <h:outputText ...... /> <h:inputText ...... > ...... </h:inputText> <h:message ...... /> ...... </h:panelGrid>
まず、f:facetタグがあります。このタグは、以前h:dataTableをご紹介したときにも出てきましたが、表形式の直前に「ヘッダ」として表示されます。
表形式で表示するときには、h:panelGrid要素のcolumns属性で指定された個数のUIコンポーネントが1行分として表示されます。
ここでは、columns属性の値は"3"です。
つまり、h:panelGridの子要素になっている、h:outputText, h:inputText, h:messageという3つのUIコンポーネントが同じ行で表示されます。
その後に続く3つのUIコンポーネントが、次の行に表示され、また3つのUIコンポーネントがその次の行に...、といったように表示されていきます。
図9.1[1つめの画面]と見比べてみてください。
次に、遷移先のpage2.jspです。ここでもh:panelGridが使われていることを確認しましょう。ここでは、表の罫線を表示するため、h:panelGridでborder属性が使われています。
図9.3[2つめの画面に遷移(バリデータに適合)]と見比べてみてください。
<%@ page contentType="text/html; charset=Shift_JIS" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <head> <link href="style.css" type="text/css" rel="stylesheet" /> <title>バリデータのテスト</title> </head> <body> <h1>バリデータのテスト</h1> <f:view> <h:panelGrid border="1" columns="2"> <h:outputText value="お名前" /> <h:outputText id="name" value="#{ParameterBean.name}" /> <h:outputText value="パスワード" /> <h:outputText id="password" value="#{ParameterBean.password}" /> <h:outputText value="品物の数" /> <h:outputText id="quantity" value="#{ParameterBean.quantity}" /> <h:outputText value="e-mailアドレス" /> <h:outputText id="email" value="#{ParameterBean.email}" /> <h:outputText value="クレジットカードの番号" /> <h:outputText id="card" value="#{ParameterBean.creditCardNumber}" /> <h:outputText value="郵便番号" /> <h:outputText id="zip" value="#{ParameterBean.zipNumber}" /> </h:panelGrid> <h:form> <h:commandButton id="button" action="back" value="戻る" /> </h:form> </f:view> </body> </html>
では、まず「必須項目のチェック」からです。
<h:outputText value="お名前を入力してください(必須)" /> <h:inputText id="name" required="true" value="#{ParameterBean.name}" /> <h:message for="name" styleClass="error" />
h:inputTextタグに次の属性があります。
required="true"
このrequired属性がtrueになっていると、このh:inputTextは必須項目となります。
このh:inputTextに入力されたデータがバリデータに適合しなかったとき(つまり、文字列が入力されていなかったとき)、エラーメッセージが表示されます。
このエラーメッセージの表示は、次の部分で行われます。
<h:message for="name" styleClass="error" />
h:messageタグは、エラーメッセージを表示するUIコンポーネントです。for属性で指定したUIコンポーネントに関するエラーメッセージを表示します。
ここでは、すぐ上にある"name"というidを持つh:inputTextについて、バリデータの結果を表示するということです。
styleClass属性では、このJSPで使っているスタイルシートの中から、エラーメッセージ表示用のクラス名を指定しています。
このJSPでは、次の部分で指定されているように、style.cssというスタイルシートが使われています。
<link href="style.css" type="text/css" rel="stylesheet" />
style.cssには、次のような記述があります。この記述(「クラスセレクタ」といいます)では、フォントにイタリック体と赤色が指定されています。
.error { font-style: italic; color: red; }
h:messageのstyleClass属性が"error"になっていると、エラーメッセージを表示するときに、スタイルシート中の".error"というクラスセレクタの設定が適用されるのです。
styleClass属性は、このバリデータだけなく、HTML出力に関係するようなUIコンポーネントすべてに利用できる属性です。
次に、入力された文字列の長さをチェックするバリデータです。
<h:outputText value="パスワードを設定してください(5文字以上)" /> <h:inputSecret id="password" value="#{ParameterBean.password}"> <f:validateLength minimum="5" /> </h:inputSecret> <h:message for="password" styleClass="error" />
ここでは、h:inputSecretというタグが登場しています。このタグは、パスワードなどを入力するときに、入力された文字をそのまま表示せずに、"・・・・・"のように伏せ字にして表示してくれるコンポーネントです。
f:validateLengthというタグは、文字列の長さをチェックするバリデータです。ここでは、入力される文字列は、最小でも5文字以上になることを指定しています。
f:validateLengthタグは、"password"というidを持つh:inputTextタグの子要素になっています。つまり、このf:validateLengthタグは、"password"というidを持つh:inputSecretに属しているということになります。
f:validateLengthタグには、ほかにmaximum属性もあります。最大で何文字までかチェックします。
<f:validateLength maximum="10" />
数の範囲をチェックするバリデータです。
<h:outputText value="品物の数を入力してください(1〜10)" /> <h:inputText id="quantity" value="#{ParameterBean.quantity}"> <f:validateLongRange minimum="1" maximum="10"/> </h:inputText> <h:message for="quantity" styleClass="error" />
f:validateLongRangeというタグは、整数の数の範囲をチェックするバリデータです。この例では、入力される数は1〜10までの範囲となります。それ以外だとエラーになるのです。
<f:validateLongRange minimum="1" maximum="10"/>
なお、このh:inputTextタグは、Managed BeanのquantityプロパティとValue Bindingしています。では、Managed Beanのquantityプロパティのgetterとsetterを見てみましょう。
public Integer getQuantity() { return quantity; } public void setQuantity(Integer q) { quantity = q; }
通常のプロパティはString型ですが、ここではquantityプロパティはInteger型になっています。
先に見たように、このプロパティに関連づけられているh:inputTextには、f:validateLongRangeバリデータが設定されています。つまり、このh:inputTextには整数が入るということですね。こうした場合、プロパティの型をIntegerにすることができます。このしくみのことを、「コンバータ」と言います。
コンバータは、h:inputTextタグやh:outputTextタグなどのValue Bindingが必要となるタグと、Managed Beanのプロパティ間でデータ変換を行います。例えば、テキスト入力フィールドに入力された文字列をJavaのIntegerやDate型に変換します。また、IntegerやDate型のオブジェクトを、h:outputTextタグなどで画面上に出力します。
t:validateEmailタグで、入力データがe-mailアドレスの形式になっているかどうかチェックします。
そして、このh:inputTextには、required属性があり、"true"という値になっています。このことは、このh:inputTextは必須項目であり、必ず何らかの文字列が入らなければならないことを意味していました。
<h:outputText value="e-mailアドレス(必須)" /> <h:inputText id="email" required="true" value="#{ParameterBean.email}"> <t:validateEmail /> </h:inputText> <h:message for="email" styleClass="error" />
t:validateEqualでは、2つのコンポーネントの入力値が等しいかどうかチェックします。
Webアプリケーションでは、パスワードやe-mailアドレスを確認のため再度入力させる、といった処理が頻繁に行われます。t:validateEqualでは、こうした処理を実現できるのです。
ここでは、"email"というidを持つh:inputTextの入力内容と、"email2"というidを持つh:inputTextの入力内容が同じかどうかチェックしています。
<h:outputText value="e-mailアドレス(必須)" /> <h:inputText id="email" required="true" value="#{ParameterBean.email}"> ...... </h:inputText> ...... <h:outputText value="もう一度e-mailアドレス" /> <h:inputText id="email2" required="true" value="#{ParameterBean.anotherEmail}"> <t:validateEqual for="email" /> </h:inputText> <h:message for="email2" styleClass="error" />
細かく見てみましょう。
t:validateEqualタグは、"email2"というidを持つh:inputTextに属しています。
<h:inputText id="email2" required="true" value="#{ParameterBean.anotherEmail}"> <t:validateEqual for="email" /> </h:inputText>
そして、t:validateEqualのfor属性の値は、"email"となっています。これは、最初にe-mailアドレスを入力しているh:inputTextのid属性の値です。
こうして、"email2"に入力された文字列が"email"に入力された文字列と同じものであるかどうかチェックできるようになります。
t:validateCreditCardは、入力された文字列がクレジットカードの番号として正しいかどうかチェックします。
残念ながら、JCBのカードには対応していないようです。筆者はJCBのカード(だけ)を所有しているのですが、筆者のカードの番号だとこのバリデータに引っかかってしまいます。
MyFacesでは、Apache Software FoundationのJakarta Projectで作成している「Jakarta Commons」のライブラリを利用しています。このt:validateCreditCardは、「Jakarta Commons」のコンポーネントのひとつである「commons validator」のクレジットカードのチェック機構をベースにしていますが、この「commons validator」でJCBがサポートされていないのです。
こうした理由のため、筆者はこのバリデータが正しく動作しているかどうか検証できていません。
<h:outputText value="クレジットカードの番号" /> <h:inputText id="creditCardNumber" value="#{ParameterBean.creditCardNumber}"> <t:validateCreditCard /> </h:inputText>
t:validateRegExprでは、入力データがpattern属性で指定した正規表現にマッチするかどうかチェックします。
この'\d{3}-\d{4}'という正規表現は、次のことを意味します。
つまり、郵便番号のパターンになるわけですね。
正規表現のおかげで、カスタムバリデータを作らなくても、かなりのことができるようになるでしょう。
<h:outputText value="郵便番号 (例: 097-0013)" /> <h:inputText id="zipNumber" value="#{ParameterBean.zipNumber}"> <t:validateRegExpr pattern='\d{3}-\d{4}' /> </h:inputText>
JSFでは、バリデータを自作することもできます。作成方法については、本講義では扱いません。