作成 2004/2/10
更新 2004/4/7
もくじ
JSF(JavaServer Faces)は、Java Webアプリケーション(など)を簡単につくるための標準フレームワークです。JSFは以下の利点があります(Specより)。
利用を簡単に。Webアプリケーションのビュー部分の開発というのはいかにもどろくさいです。JSFを利用するとどろくさいビューの開発が、スイスイとできるようになるらしいです。
Project Rave、Ease of Developmentといった「開発を簡単に」しようというJavaをとりまく流れの一つでもあると思います。
標準化。Webアプリケーションのフレームワークは、開発生産性や保守性を向上させるものとして多く利用されています。しかし、フレームワークを使いこなすためには、多くの時間を必要とし、フレームワークに強い技術者を探すのも大変です。JSFはJSR127で仕様策定された、標準フレームワークです。
標準化することで、ツールベンダーが開発支援ツールを開発しやすくなります。JSFのEase-of-Useはツールによる支援とセットで実現されます。
JSFではビューのUIコンポーネントはロジックと分離されています。ブラウザをクライアントとした、HTMLベースのWebアプリケーションへの利用が想定されていますが、HTMLに限定されたものではありません。UIコンポーネントの実装が提供されれば、ロジックの変更なしに、FlushやSWTといったリッチクライアントに移植可能です。
ツールのイメージはMicrosoftのWebFormみたいなもののようです(使ったことないけど)。JSFを使った開発は、Javaのサーバーサイドについて深く知らなくても、ツールを使って簡単に行えることを目指しています。VBプログラマのとりこみも目論まれているようです。
とりあえず、「うだうだダルイJSPのコーディングをもっとカンタンに」してくれるものだと思っています。
参考
Sun JSF
http://java.sun.com/j2ee/javaserverfaces/
JSR127
http://www.jcp.org/en/jsr/detail?id=127
Sun The J2EE 1.4 Tutorial
http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html
Sun The Java Web Services Tutorial
http://java.sun.com/webservices/docs/1.3/tutorial/doc/(J2EE 1.4 Tutrialの方が新しいデス)
JSF Central
http://www.jsfcentral.com/
JamesHolmes.com Java Server Faces Resources
http://www.jamesholmes.com/JavaServerFaces/
Sun Developer Forum: JavaServer Faces Technology
http://forum.java.sun.com/forum.jsp?forum=427
jsf-jp(日本語ML)
http://groups.yahoo.co.jp/group/jsf-jp/
@IT JavaServer Facesを理解する(2003/7/26)
http://www.atmarkit.co.jp/fjava/special/jsf01/jsf01.html
Izu@San Diego JSF
http://izu.shinzui.org/space/JSF
nemuneko.com Java Server Faces
http://nemuneko.com/jsf/
WebSphere Studio (5.1.1〜)
http://www-106.ibm.com/developerworks/websphere/downloads/(評価版Download)
http://www-6.ibm.com/jp/software/websphere/developer/studio/jsf/1.html(Tutorial)
Sun Studio Creator
http://wwws.sun.com/software/products/jscreator/
(2004/3/17 まだかも?)
その他、JSF CentralやJamesHolmes.comからリンクをたどるといろいろあります。
ダウンロード
何事もHelloWorldからということで、超簡単なJSFアプリケーションを作ってみました。
ここでは以下の環境で実験しました。
http://java.sun.com/j2ee/javaserverfaces/のページのDownloadからサンプル含むRI(Reference Implemantaion)がダウンロード可能です。ここでは現在の最新版のv1.0をダウンロードしました。
ダウンロードしたRIを展開します。samplesのWAR形式のサンプルアプリケーションがいくつかあり、デプロイして実行可能です。ここでは例として、guessNumberアプリケーションを実行してみます。Tomcatのwebappsディレクトリにjsf-guessNumber.warをコピーし、Tomcatを起動します。ブラウザで、http://localhost:8080/jsf-guessNumber/ にアクセスするとguessNumberアプリケーションが表示されます。
画面 サンプルのguessNumberアプリケーション
その他のアプリケーションも同様の手順で実行できます。βのときと違い、security-constraintをかけているものがあり、cardemoアプリケーションなどは、コンテキストルートやindex.jspではアクセス不可で、index.facesでアクセスする必要があります。
はじめてのJSF
さて、簡単なJSFアプリケーションを作成してみます。 ここで作成するのは、単純な入力画面(input.jsp)と出力画面(result.jsp)をもったアプリケーションです。入力画面では、テキストフィールドとサブミットボタンを配置します。
以下は、今回作成するWebアプリケーションのリソース一覧です。
jsf1/ WEB-INF/ classs/ hoge/ MyBean.class Messages_ja.properties lib/ commons-beanutils.jar commons-collections.jar commons-digester.jar commons-logging.jar jsf-api.jar jsf-impl.jar jstl.jar standard.jar web.xml faces-config.xml index.jsp input.jsp result.jsp
まず、lib以下に含めるJARですが、RIのlib以下にあります。ただしRIのlibには、JSTLのJAR(jstl.jar、standard.jar)が含まれていないので、ここでは、jsf-guessNumber.warの中のWEB-INF/lib以下をコピーして利用しました(別途JSTLをダウンロードするか、アプリケーションサーバ付属のものを利用してもいいでしょう)。
web.xmlは以下のようになります。FacesServletを登録し、"/faces/*"でURLマッピングしているのがわかります(URLマッピングのパターンは任意です)。
リスト web.xml
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> </web-app>
JSFの設定ファイルがfaces-config.xmlです。デフォルトでWEB-INF/faces-config.xmlがそれです。まだ、何も登録していません。
リスト faces-config.xml
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_0.dtd"> <faces-config> </faces-config>
最初のJSPを記述します。
リスト input.jsp(バージョン1)
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <body> <f:view> <h2>hello</h2> </f:view> </body> </html>
最初の2行がJSFのtaglib宣言で、JSFのタグライブラリを宣言しています。<f:view>内にJSFのUIコンポーネントをおいていきます。ここではまだUIコンポーネントはおかず、helloという文字列を指定しているだけです。
まだ、JSFらしいことは何も行っていませんが、ここまで作成したアプリケーションで、JSFアプリケーションを実行可能です。Tomcatを起動し、ブラウザで以下のURLにアクセスします。
http://localhost:8080/jsf1/input.jsp
しかし実行するとエラーになります。以下のようなエラーが出力されます。
javax.servlet.ServletException: Cannot find FacesContext
これはJSFサーブレットを経由せずに、JSFコンポーネントを利用するJSPに直接アクセスしたためです。変わりに次のURLでアクセスします。
http://localhost:8080/jsf1/faces/input.jsp
するとエラーなく実行できました。
リスト 実行画面
URL入力を手打ちで/faces/...とするのも手間です。コンテキストルートのURLを指定しても、正しく表示できるようにindex.jspという名前のファイルを作成します(index.jspはTomcatの場合、デフォルトのweb.xmlのwelcomeファイルリストです)。
リスト index.jsp
<jsp:forward page="faces/input.jsp" />
これで、http://localhost:8080/jsf1/ にアクセスすると/index.jsp→/faces/input.jspが表示されます。
さて、作成したスカスカのアプリケーションに機能を追加していきましょう。まずはJavaBeansを作成し、テキストフィールドに関連づけます。まず、以下のようなJavaクラスを作成します。このクラスはmessageというプロパティーを持つ(getMessage、setMessageメソッドをもつ)JavaBeansです。
リスト MyBean.java
package hoge; public class MyBean { private String message = "hello"; public String getMessage() { return message; } public void setMessage(String string) { message = string; } }
作成したhoge.MyBeanクラスをfaces-config.xmlに登録します。managed-bean要素にJavaクラスを登録することで、JSFのUIコンポーネントと関連づけて利用することができるようになります。
リスト faces-config.xml
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_0.dtd"> <faces-config> <managed-bean> <managed-bean-name>myBean</managed-bean-name> <managed-bean-class>hoge.MyBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>
次にinput.jspにテキストフィールドを追加します。
リスト input.jsp(バージョン2)
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <body> <f:view> <h2>hello</h2> <h:form> <h:inputText value="#{myBean.message}"/> </h:form> </f:view> </body> </html>
<h:form>はHTMLのフォームに対応するUIコンポーネントです。 <h:inputText>がテキストフィールドに対応するUIコンポーネントです。inputTextのvalue属性に#{myBean.message}を指定しています。これは、faces-config.xmlで登録したmyBeanのmessageプロパティーを表しています。
実行すると次のようなテキストフィールドが表示されます。初期値のhelloという文字列がテキストフィールドに表示されているのがわかります。
さて、次は画面遷移を行ってみましょう。画面遷移は、faces-config.xmlにnavigation-ruleを記述することで行います。
リスト faces-config.xml
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_0.dtd"> <faces-config> <navigation-rule> <from-view-id>/input.jsp</from-view-id> <navigation-case> <from-outcome>ok</from-outcome> <to-view-id>/result.jsp</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <managed-bean-name>myBean</managed-bean-name> <managed-bean-class>hoge.MyBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>
上の例では、/input.jspからokのときの/result.jspへ遷移するという記述になっています。
次に、input.jspに画面遷移用のSubmitボタンを追加します。
リスト input.jsp(バージョン3)
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <body> <f:view> <h2>hello</h2> <h:form> <h:inputText value="#{myBean.message}"/> <h:commandButton action="ok" value="GOGO"/> </h:form> </f:view> </body> </html>
ボタンは<h:commandButton<です。value属性にはGOGOを指定しています(表示文字がGOGOになります)。またaction属性にokという文字列を指定してます。ボタンが押されたときに"ok"というアクションが実行され(アクション結果のokがナビゲーションにわたされ)、画面遷移が実行されます。
次に遷移先のresult.jspを作成します。
リスト result.jsp
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <body> <f:view> <h2>result</h2> <h:form> <h:outputText value="#{myBean.message}"/> </h:form> </f:view> </body> </html>
ここではmyBeanのmessageを<h:outputText>で表示しています。
実行すると、GOGOボタンのついたinput.jspが表示され、ボタンを押すと、result.jspに遷移するのがわかります。
画面 実行画面
※ナビゲーション定義は、URLパターンを指定することもできます。また、アクションなどを指定して範囲をしぼることもできます。
上の例だと、単に、静的なリンクと変わりありません。ボタンを押したときに、なんらかのビジネスロジックを実行し、結果に応じて画面遷移を行うようにしてみましょう。上の例からの変更はMyBean.javaとinput.jspです。
MyBean.javaではdoHoge()という文字列を返すメソッドを追加します。
リスト MyBean.java
package hoge; public class MyBean { private String message = "hello"; public String getMessage() { return message; } public void setMessage(String string) { message = string; } public String doHoge(){ return "ok"; } }
input.jspでは、commandButtonのaction属性を#{myBean.doHoge}に変更します。
リスト input.jsp
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <body> <f:view> <h2>hello</h2> <h:form> <h:inputText value="#{myBean.message}"/> <h:commandButton action="#{myBean.doHoge}" value="GOGO"/> </h:form> </f:view> </body> </html>
これで、ボタンが押されたときにMyBean#doHoge()メソッドが呼ばれ、結果文字列の"ok"からナビゲーションされ、result.jspに画面遷移します。
JSFではUIコンポーネントにリスナーを指定して、イベントハンドリングを行うことができます。リスナーには、valueChangeListenerとactionListenerがあります。
まずMyBean.javaにリスナーメソッドを実装します。valueChangeListenerはValueChangeEventを引数にとるメソッド、actionListenerはActionEventを引数にとるメソッドを作成します。返り値はvoidです。なお、JSFのAPIを利用しているので、MyBean.javaのコンパイルにはJSFのクラスをクラスパスに通す必要があります。
リスト MyBean.java
package hoge; import javax.faces.event.ActionEvent; import javax.faces.event.ValueChangeEvent; public class MyBean { private String message = "hello"; public String getMessage() { return message; } public void setMessage(String string) { message = string; } public String doHoge(){ return "ok"; } public void messageChanged(ValueChangeEvent event){ System.out.println("called messageChanged"); } public void hogePushed(ActionEvent e){ System.out.println("called hogePushed"); } }
input.jspではリスナーをそれぞれ指定します。
リスト input.jsp
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <body> <f:view> <h2>hello</h2> <h:form> <h:inputText value="#{myBean.message}" valueChangeListener="#{myBean.messageChanged}"/> <h:commandButton action="#{myBean.doHoge}" value="GOGO" actionListener="#{myBean.hogePushed}"/> </h:form> </f:view> </body> </html>
実行すると、ボタンが押されたときにMyBean#hogePushed(...)メソッドが、ボタンが押されたときに、messageの値に変更があった場合にMyBean#messageChanged(...)メソッドが呼ばれるのがわかります。なお、ここでは2つのリスナーを両方使っていますが、もちろん片方だけで実行できます。
※Backing Beanにメソッドを登録せず、ValueChangeListenerやActionListenerを実装したクラスを別に作成する方法もあります。
お次は入力チェックです。入力チェックは、組み込みのVadlidatorを利用する方法、自作のValidadatorクラスを作成する方法、validateメソッドを利用する方法があります。組み込みのValidatorには、DoubleRangeValidator、LengthValidator 、LongRangeValidator があります。次の例では文字数チェックを行うLengthValidatorを利用しています。
リスト input.jsp
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <body> <f:view> <h2>hello</h2> <h:form> <h:inputText value="#{myBean.message}" > <f:validateLength maximum="5"/> </h:inputText> <h:commandButton action="#{myBean.doHoge}" value="GOGO"/> <br> <h:messages/> </h:form> </f:view> </body> </html>
リスナー部分のコードは関係ないのではずしています
実行し、5文字より大きな文字数を入力し、ボタンを押すと入力エラーが表示されます。
画面 実行画面
なお、<h:messages/>は全部のエラーを一覧するタグです。個々のエラーを表示するには<h:message/>タグとfor属性を使います。for属性には、UIコンポーネントのid属性を指定します。
リスト 個々のエラー表示
<h:inputText id="mymessage" value="#{myBean.message}" > <f:validateLength maximum="5"/> </h:inputText> <h:message for="mymessage"/>
※組み込みのValidator以外(?)に必須チェックはrequired="true"を指定すればいけます。
※メソッドValidate、日本語リソース等は後述(予定)
上の例で表示されたメッセージは、組み込みのデフォルトメッセージです。デフォルトのメッセージファイルはSunのRIであれば、jsf-impl.jarのjavax.faces以下にあります。アプリケーションのメッセージファイルは、faces-config.xmlのapplication要素で指定します。
リスト faces-config.xml
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_0.dtd"> <faces-config> <application> <message-bundle>hoge.Messages</message-bundle> <locale-config> <default-locale>en</default-locale> <supported-locale>ja</supported-locale> </locale-config> </application> <navigation-rule> <from-view-id>/input.jsp</from-view-id> <navigation-case> <from-outcome>ok</from-outcome> <to-view-id>/result.jsp</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <managed-bean-name>myBean</managed-bean-name> <managed-bean-class>hoge.MyBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>
上の例ではhoge.Messagesを指定しているので、クラスパス上のhoge/Messages.proepertiesがメッセージリソースファイルです(日本語のメッセージファイルはhoge/Messages_ja.proeperties)。このプロパティーファイルにメッセージを定義します。日本語の場合はnative2asciiもかけましょう。
リスト Messages.properties(抜粋)
javax.faces.validator.LengthValidator.MAXIMUM=Validation Error: ''{0}''文字以下で入力してください
実行すると、定義したメッセージが表示されます。
画面 実行画面
とりあえず、サンプルみようみまねで簡単なJSFアプリケーションを作成してみました。なんとなくStrutsを違う方向から再設計したような印象も受けました。まだJSFのよさがわかってないかも知れません。JSFの意義というのは、ビューとロジックが分離されていること、およびツールによりこれらが作れること(作る仕組みが出来ていること)です。まだ調べ始めなので、ちょくちょく更新していきたいと思います。
一応上で作ったものを置いておきます(重いのでlib抜き。Eclipseプロジェクト付)。
jsf1.zip
なお、SunのJ2EE(TM) 1.4 Tutorial(Chapter17〜)は、まだJSFまわりのまとまった情報が少ない中で重宝します。
なお、SunのThe Java(TM) Web Services Tutorial(Chapter20、21、22)は、まだJSFまわりのまとまった情報が少ない中で重宝します。現状(2004/3/17)サンプルコードはFinalの前の仕様に沿ったものなので、HTMLタグが若干異なります(Finalではアンダーバー区切りでなくキャメルケースに変更)。
JSFタグについてはRI付属のTag Library Documentationがリファレンスになります(tlddocsディレクトリにある)。サンプルコードはありませんが、何の属性を指定できるかとか、簡単な説明は記述されています。
次のページ(HTMLタグサンプル)