JPA + EJB + JSF による Web アプリケーション(その 4)

Facelets を作成する

管理 Bean の次は Facelets を作成します。
/customer/list.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"
  xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>顧客マスタ一覧</title>
  </h:head>
  <h:body>
    <h1>顧客マスタ一覧</h1>
    <h:dataTable var="item" value="#{customerList.items}" border="1">
      <h:column>
        <f:facet name="header">顧客ID</f:facet>
        <h:outputText value="#{item.id}" />
      </h:column>
      <h:column>
        <f:facet name="header">顧客名</f:facet>
        <h:outputText value="#{item.name}" />
      </h:column>
      <h:column>
        <f:facet name="header">連絡先</f:facet>
        <h:outputText value="#{item.phone}" />
      </h:column>
    </h:dataTable>
  </h:body>
</html>

XHTML ファイルの作成を選ぶとひな型ができていますのでそれに追記していく形になります。
h:headhead 要素、h:bodybody 要素です。
h:dataTableCollection などをもとに一覧表を作るための要素で、value 属性に Collection を指定します。# で始まる JSF 用の EL 式を使って、管理 Bean である CustomerListitems プロパティ(List<Customer> 型 !)を指定しています。管理 Bean 名を EL 式で指定するときは、クラス名の最初の一文字を小文字にしたものを指定します。
h:column が表の列に対応します。f:facet は、ここでは name 属性に header を指定して、thead 要素と th 要素による表見出しを作成するために使っています。
h:outputText は普通の文字列を出力するためのもので、value 属性に指定された値が文字列として出力されます。ここでは h:dataTable 内で利用する変数名 itemCustomer 型なので、Customer のプロパティを呼び出して出力させています。

/customer/search.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"
  xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>顧客マスタ参照</title>
    <h:outputStylesheet library="css" name="customer/search.css" />
  </h:head>
  <h:body>
    <h1>顧客マスタ参照</h1>
    <h:form>
      <h:panelGrid columns="2">
        <h:outputText value="顧客ID" />
        <h:inputText size="5" binding="#{customerSearch.id}" required="true" />

        <h:outputText value="顧客名" />
        <h:inputText size="20" value="#{customerSearch.item.name}" readonly="true" />

        <h:outputText value="連絡先" />
        <h:inputText size="20" value="#{customerSearch.item.phone}" readonly="true" />
      </h:panelGrid>
      <p><h:commandButton action="#{customerSearch.search}" value="検索" /></p>
    </h:form>
  </h:body>
</html>

h:outputStylesheetCSS を読み込むための要素です。CSS は後で /resources/css フォルダにまとめて作成しますが、このようなフォルダ構成にしておくことで

<h:outputStylesheet library="css" name="foo/bar.css" />

で /resources/css/foo/bar.css を読み込むことができます。
h:panelGrid は表を作成するための要素で、列数を指定しておくと行数を自動で判別して表を作成してくれます。
h:formform 要素に対応します。
h:inputText

<input type="text" ... />

に対応する要素です。

<h:inputText size="5" binding="#{customerSearch.id}" />

で、CustomerSearchid プロパティとバインドします。バインドするプロパティは、その要素に対応した型である必要があり、h:inputText の場合は HtmlInputText 型でないといけません。required 属性を true にしておくと、何も入力せずに送信しようとするとサーバのログにメッセージが表示されます。

<h:inputText size="20" value="#{customerSearch.item.name}" readonly="true" />

は単に値を表示させるだけのものですが、value 属性の EL 式に注目してください。このように、プロパティが入れ子になっているときはドットでつないで呼び出すことができます。この場合、CustomerSearchitem プロパティは Customer 型ですから id, name, phone の各プロパティを持ちますので、それらを呼び出すことができます。
h:commandButton

<input type="submit" ... />

に対応します。action 属性で管理 Bean に定義したアクションメソッドを呼び出すことができます。

/product/search.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"
      xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>商品マスタ検索</title>
    <h:outputStylesheet library="css" name="product/search.css" />
  </h:head>
  <h:body>
    <h:form>
      <p>
        <h:inputText size="30" binding="#{productSearch.keyword}" />
        <h:commandButton action="#{productSearch.search}" value="検索" />
      </p>
    </h:form>
    <h:dataTable var="item" value="#{productSearch.items}" border="1">
      <h:column>
        <f:facet name="header">商品ID</f:facet>
        <h:outputText value="#{item.id}" />
      </h:column>
      <h:column headerClass="name">
        <f:facet name="header">商品名</f:facet>
        <h:outputText value="#{item.name}" />
      </h:column>
    </h:dataTable>
  </h:body>
</html>

要素としてはすでに説明したものだけを使っています。h:columnheaderClass 属性は、f:facet によってつくられる thead 要素内の th 要素に対する class 属性を指定します。つまりこの例だと

<table border="1">
  <thead>
    <tr><th>商品ID</th><th class="name">商品名</th></tr>
  </thead>
  <tbody>
    ...
  </tbody>
</table>

と変換されることになります。