この章では、図10.1[名前と現在の時刻を表示する]のようなサンプルについて考えてみましょう。
まず、画面1で名前を入力します。画面1のボタンを押すと、画面2に遷移します。画面2では、画面1で入力された名前と、現在の時刻を表示しています。
このサンプルでは、ボタンが押されたときに、「現在の時刻を取得する」という「ビジネスロジック」が実行されています。JSFでは、こうしたビジネスロジックのことを「Action Method」と言います。Action Methodは、Managed Beanに記述します。
では、このサンプルのManaged Beanを見てみましょう。
import java.util.Date; import java.text.DateFormat; public class ParameterBean { private String word = ""; public void setWord(String word) { this.word = word; } public String getWord() { return word; } public String currentTime() { Date d = new Date(); DateFormat df = DateFormat.getDateTimeInstance(); StringBuffer sb = new StringBuffer(); sb.append("こんにちは、"); sb.append(word); sb.append("さん。\n"); sb.append("いまは"); sb.append(df.format(d)); sb.append("です。"); word = new String(sb); return "success"; } }
このManaged Beanでは、currentTimeというメソッドがAction Methodになります。
このcurrentTimeメソッドでは、現在の日時を取得して、入力フィールドのパラメータと組み合わせています。
そして、返値として"success"という文字列を返しているのがポイントです。
では、画面1に対応する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" %> <html> <head> <link href="style.css" type="text/css" rel="stylesheet" /> <title>JSF: ビジネスロジックのテスト</title> </head> <body> <h1>JSF: ビジネスロジックのテスト</h1> <f:view> <h:form id="searchForm"> <h:inputText id="word" value="#{ParameterBean.word}" /> <h:commandButton id="button1" action="#{ParameterBean.currentTime}" value="Go!" /> </h:form> </f:view> </body> </html>
h:commandButton要素のaction属性に注目してください。
<h:commandButton id="button1" action="#{ParameterBean.currentTime}" value="Go!" />
action属性の値は、#{ParameterBean.currentTime}という表記になっています。
これを、前章のh:commandButton要素のaction属性と比較してみましょう。
(前章の action 属性) <h:commandButton id="button1" action="success" value="Go!" /> (本章の action 属性) <h:commandButton id="button1" action="#{ParameterBean.currentTime}" value="Go!" />
前章では、"success"となっているのに対し、本章では、前章で出てきたValue Binding式のようなスタイルになっています。
では、#{ParameterBean.currentTime}という表記について解説しましょう。
ここでは、画面1のボタンが押されると、ParameterBeanのcurrentTimeメソッドが実行されるのです。こうしたしくみのことを"Method Binding"と言います。そして、#{……}という書式を"Method Binding式"と言います。
Method Binding式は、次のようなスタイルになります。
#{ Beanの名前 . Action Method名 }
"Beanの名前"は、先のmanaged-bean-name要素の内容部分となります。
"Action Method名"は、ボタンが押されたときに実行されるAction Method名になります。
Action Methodには、次の3つのルールがあります。
currentTimeメソッドが、この3つのルールに適合していることを確認してください。
いま説明したように、Action Methodの返値がoutcomeとなります。このoutcomeが、h:commandButton要素のaction属性の値となるのです。この値と、faces-config.xmlの設定情報により遷移先が決まります。
次のようなh:commandButtonタグの記述が
<h:commandButton id="button1" action="#{ParameterBean.currentTime}" value="Go!" />
currentTimeというAction Methodの実行によって、次のように変化するというイメージです。
<h:commandButton id="button1" action="success" value="Go!" />
では、ここでもう一つサンプルプログラムを作ってみましょう。題材は「図書検索プログラム」です。
図10.2[検索語入力画面]で検索語を入力すると、その検索語を含む本のデータのリストを出力します。図書データはデータベースに格納されています。
入力フィールドに検索語を入れ、ボタンを押すと、Action Methodが呼ばれます。Action Methodで検索語に基づく検索を行います。そして図10.3[検索結果出力画面]に遷移して、検索結果を出力するのです。
<%@ 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> <hr /> <f:view> <h:form id="searchForm"> <h:inputText id="searchWord" value="#{BookSearcher.word}" /> <h:commandButton id="submit" action="#{BookSearcher.searchBooks}" value="Go!" /> </h:form> </f:view> </body> </html>
h:input要素でValue Binding式、h:commandButton要素でMethod Binding式が使われています。
次に、Managed Beanです。
import java.util.List; import java.util.ArrayList; import java.sql.*; import javax.sql.*; import javax.faces.context.FacesContext; import javax.faces.el.ValueBinding; public class BookSearcher { private String word = ""; private String id = ""; private List list = null; private BookData book = null; public void setWord(String word) { this.word = word; } public String getWord() { return word; } public List getBookList() { return list; } public BookData getBookData() { return book; } public String searchBooks() { searchBooks(word); return "success"; } private void searchBooks(String word) { list = new ArrayList(); try { Class.forName("org.hsqldb.jdbcDriver"); String url = "jdbc:hsqldb:hsql://localhost"; Connection con = DriverManager.getConnection(url, "sa", ""); String selectStatement = "select * " + "from books where ndc like ? " + "or tyosya_hyouji like ? " + "or id like ? " + "or title like ? " + "or author like ? " + "or publisher like ? "; PreparedStatement prepStmt = con.prepareStatement(selectStatement); prepStmt.setString(1, appendPercent(word)); prepStmt.setString(2, appendPercent(word)); prepStmt.setString(3, appendPercent(word)); prepStmt.setString(4, appendPercent(word)); prepStmt.setString(5, appendPercent(word)); prepStmt.setString(6, appendPercent(word)); ResultSet rs = prepStmt.executeQuery(); while (rs.next()) { BookData book = new BookData(); book.setNdc(rs.getString("ndc")); book.setTyosya_hyouji(rs.getString("tyosya_hyouji")); book.setId(rs.getString("id")); book.setTitle(rs.getString("title")); book.setAuthor(rs.getString("author")); book.setPublisher(rs.getString("publisher")); list.add(book); } prepStmt.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } private String appendPercent(String from) { StringBuffer to = new StringBuffer(); to.append("%"); to.append(from); to.append("%"); return new String(to); } }
setWord, getWordというメソッドの存在から、wordプロパティがあることがわかります。また、bookList, bookDataプロパティもあります。
そして、searchBooksというAction Methodがあります。Action Methodのルールに則っていることがわかります。このメソッドでは、(別の)searchBooksメソッドで、データベースの検索処理を行っています。
public String searchBooks() { searchBooks(word); return "success"; } private void searchBooks(String word) { // データベースの検索処理 }
次に、ModelとなるBookDataというJavaBeansです。
import java.io.Serializable; public class BookData implements Serializable { private String ndc = ""; private String tyosya_hyouji = ""; private String id = ""; private String title = ""; private String author = ""; private String publisher = ""; public String getNdc() { return ndc; } public void setNdc(String ndc) { this.ndc = ndc; } public String getTyosya_hyouji() { return tyosya_hyouji; } public void setTyosya_hyouji(String tyosya_hyouji) { this.tyosya_hyouji = tyosya_hyouji; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } }
ndc, tyosya_hyouji, titleなどのプロパティがあることがわかります。
データベースの検索結果には、複数の図書データが含まれます。1冊の図書データは、1つのBookDataに格納されます。そしてjava.util.Listを使って、複数のBookDataをまとめておきます。
次のような処理になります。
List list = new ArrayList(); BookData book = new BookData(); book.setId(rs.getString("id")); book.setTitle(rs.getString("title")); book.setAuthor(rs.getString("author")); list.add(book);
検索結果を出力する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" %> <html> <head> <title>検索結果</title> </head> <body> <h1>検索結果</h1> <f:view> <h:form id="listForm"> <h:dataTable id="table" border="1" value="#{BookSearcher.bookList}" var="book"> <h:column> <f:facet name="header"> <h:outputText value="タイトル"/> </f:facet> <h:outputText id="bookTitle" value="#{book.title}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="著者"/> </f:facet> <h:outputText id="bookAuthor" value="#{book.author}"/> </h:column> </h:dataTable> </h:form> </f:view> </body> </html>
主に、dataTableというタグを使って検索結果を表示しています。
h:dataTableタグは、コレクション(List,配列など)のデータを表にして表示するUIコンポーネントです。
ほかのUIコンポーネントと同じく、id属性があります。border属性では、表の罫線の太さを指定しています。
value属性で、表示するコレクション型のプロパティを指定します。このとき、Value Binding式を使います。var属性は、コレクション中の1つの要素を表す変数名です。
この例では、value属性はList型であるbookListプロパティを指定しています。このbookListには、複数のBookDataが格納されています。従って、var属性で指定されたbookという変数名は、BookData Beanを指していることになります。
<h:dataTable id="table" border="1" value="#{BookSearcher.bookList}" var="book"> </h:dataTable>
h:dataTableタグでは、複数のh:columnタグが含まれています。このタグは、図10.4[h:column タグ]のように、h:dataTable要素の1列分のデータを表すUIコンポーネントです。
<h:dataTable id="table" border="1" value="#{BookSearcher.bookList}" var="book"> <h:column> <f:facet name="header"> <h:outputText value="タイトル"/> </f:facet> <h:outputText id="bookTitle" value="#{book.title}"/> </h:column> ......
h:column要素には、f:facet要素とh:outputText要素が含まれています。
このうち、f:facet要素は、表の1列のヘッダやフッタを表すUIコンポーネントです。
name属性に"header"を指定するとヘッダになります。"footer"だとフッタです。
<f:facet name="header"> <h:outputText value="タイトル"/> </f:facet>
そして、h:outputTextタグです。この列では、bookという変数(BookData Beanのこと)のtitleプロパティの値を出力しています。
<h:outputText id="bookTitle" value="#{book.title}"/>
では、h:dataTableタグの働きについて整理してみましょう。
表示される表の1行分が、h:dataTableのvar属性の値に対応しています。つまり、コレクション中の1つのJavaBeansが、表の1行分となるのです。この例では、List中の1つのBookDataが、表の1行分となります。
BookData Beanのどのプロパティを出力するかは、column要素によって決まります。1つのcolumn要素で、1つのプロパティを出力するのです。