JSF 2.0で作るWebアプリケーション 中編

http://d.hatena.ne.jp/shin/20091030/p1の続き。

前回までにデータベースのアクセスが完了しています。

ではさっそくトップページを作成します。ここに一覧表示をします。

一覧画面のテンプレート

まずテンプレートを作ります。
index.xhtmlは以下のようになります。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <head>
        <title>従業員一覧</title>
    </head>
    <body>
        <h1>従業員一覧</h1>
        <form >
            <table border="1">
                <thead>
                    <tr>
                        <td>ID</td>
                        <td>従業員名</td>
                        <td>入社年月</td>
                        <td>給料</td>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1</td>
                        <td>@@@</td>
                        <td>2000/12/31</td>
                        <td>123</td>
                    </tr>
                </tbody>
            </table>
        </form>
    </body>
</html>

単体で見た場合以下のようになります。通常のXHTMLなんで当たり前ですが。
http://shin.cside.com/diary/2009/1031-01.png

管理対象Bean

では管理対象Beanを作ります。管理対象BeanというのはJSFによってライフサイクルを管理されるManagedBeanの日本語訳です。最近管理Beanから変更されたようです。

package managed;

import entity.Employee;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import service.EmployeeService;


@ManagedBean
@RequestScoped
public class Index implements Serializable{

    @ManagedProperty("#{employeeService}")
    private EmployeeService service;

    //一覧
    private List<Employee> list;

    @PostConstruct
    public void init(){
        //最初に検索させる
        list = service.findAll();
    }

    
    public List<Employee> getList() {
        return list;
    }
    
    public void setService(EmployeeService service) {
        this.service = service;
    }

}

見てわかるとおりアノテーションをつけた通常のクラスです。JSF1.xのようにアノテーションをはずして環境設定ファイルに書くことも可能です。

検索処理は@PostConstructコモンアノテーションJava EE 5もしくはJava SE 6で定義されている標準アノテーション)がついたメソッドによってインスタンスが生成されて使用可能になった直後(つまり注入後。コンストラクタのタイミングでは早すぎて使えない場合に利用する)に呼び出されます。


テンプレートに埋め込み

ではこれを先ほどのテンプレートに埋め込んでみましょう。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <head>
        <title>従業員一覧</title>
    </head>
    <body>
        <h1>従業員一覧</h1>
        <form >
            <table border="1">
                <thead>
                    <tr bgcolor="#ffff00">
                        <td>ID</td>
                        <td>従業員名</td>
                        <td>入社日</td>
                        <td>給料</td>
                    </tr>
                </thead>
                <tbody>
                    <tr jsfc="ui:repeat" value="#{index.list}" var="row">
                        <td><span jsfc="h:outputText" value="#{row.id}"/></td>
                        <td><span jsfc="h:outputText" value="#{row.従業員名}"/></td>
                        <td><h:outputText value="#{row.入社日}" >
                                <f:convertDateTime timeZone="JST" pattern="yyyy年MM月dd日"/>
                            </h:outputText>
                        </td>
                        <td>
                            <span jsfc="h:outputText" value="#{row.給料}">
                                <f:convertNumber pattern="#,###"/>
                            </span>
                        </td>
                    </tr>
                </tbody>
            </table>
        </form>
    </body>
</html>

ポイントはui:repeatです。これはjstlのc:foreachとほぼ同じものと捉えてください。ただし、指定回数のループはできません。あくまでもコレクションをまわすことしか出来ませんが、問題はないでしょう。jsfc属性をすることによってここがリピートされることを期待しています。

入社日だけ通常のカスタムタグを利用していますが、ほかのタグのようにjsfc属性を指定することももちろん可能です。その場合単純に置き換えが発生しているのが給料のところ(spanの配下にコンバータをおいてる)をみるとわかります。

以下jsfcを使ったり使わなかったりしてるのでよく見てください。


実行してみると以下のようになります。
http://shin.cside.com/diary/2009/1031-02.png

後編に向けて画面遷移

では今回はロジックは入れませんが、後編に向けてボタンと画面遷移を追加してみます。

まず遷移後のedit.xhtmlを作成します。

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">
    
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>編集</title>
    </h:head>
    
    <h:body>

        <h1>編集</h1>
        <form>
            <table border="1">
                <tr>
                    <td>ID</td>
                    <td>@</td>
                </tr>
                <tr>
                    <td>従業員名</td>
                    <td>@</td>
                </tr>
                <tr>
                    <td>入社日</td>
                    <td>@</td>
                </tr>
                <tr>
                    <td>給料</td>
                    <td>@</td>
                </tr>
            </table>
        </form>

        <h:button outcome="index" value="一覧へ戻る"/>
    </h:body>
    
</html>

一覧へ戻るのにGETで移動しているのがわかります。

表示すると以下のようになります。
http://shin.cside.com/diary/2009/1031-04.png


index.xhtmlで追加するのは一番上に新規作成ボタンと各行に修正ボタンです。今回はJSF2らしくPOSTBackではなく画面遷移はGETを利用し、GETパラメータ使っています。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <head>
        <title>従業員一覧</title>
    </head>
    <body>
        <h1>従業員一覧</h1>
        <form >
            <h:button outcome="edit" value="新規作成">
                <f:param name="editId" value="-1"/>
            </h:button>
            <table border="1">
                <thead>
                    <tr bgcolor="#ffff00">
                        <td>ID</td>
                        <td>従業員名</td>
                        <td>入社日</td>
                        <td>給料</td>
                        <td></td>
                    </tr>
                </thead>
                <tbody>
                    <tr jsfc="ui:repeat" value="#{index.list}" var="row">
                        <td><span jsfc="h:outputText" value="#{row.id}"/></td>
                        <td><span jsfc="h:outputText" value="#{row.従業員名}"/></td>
                        <td><h:outputText value="#{row.入社日}" >
                                <f:convertDateTime timeZone="JST" pattern="yyyy年MM月dd日"/>
                            </h:outputText>
                        </td>
                        <td>
                            <span jsfc="h:outputText" value="#{row.給料}">
                                <f:convertNumber pattern="#,###"/>
                            </span>
                        </td>
                        <td>
                            <h:button outcome="edit" value="修正">
                                <f:param name="editId" value="#{row.id}"/>
                            </h:button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </form>
    </body>
</html>

実行します。

http://shin.cside.com/diary/2009/1031-03.png

上の新規ボタンの生成されたソースは以下のようになります。

<input type="button" onclick="window.location.href='/Employee/faces/edit.xhtml?editId=-1'; return false;" value="新規作成" />

各行に生成される編集ボタンの生成ソースは以下のようになります。

<input type="button" onclick="window.location.href='/Employee/faces/edit.xhtml?editId=1'; return false;" value="修正" />

f:paramにかいたものがURLパラメータに入っているのがわかります。

いまのところどちらもedit.xhtmlへ飛びますが、画面遷移は動いているのがわかるはずです。URLパラメータの違いをよく見て確認してください。


カスタムタグの使用頻度が上がってきたような気がしますが、これはNetBeans上で補完が利くからです。このあとカスタムタグからjsfcへ変更するのは容易なため(タグ名をjsfcの属性へもっていくだけ)IDEでの操作のあと変更していくのがよいようです。