この章では、図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つのプロパティを出力するのです。