データベースとの連携
Struts 2を用いたアプリケーションでデータベース(RDBMS)を利用するのも、基本的には、通常のJavaアプリケーションと変わりはありません。直接JDBCを使うこともできますし、いわゆるO/Rマッピングフレームワーク(Hibernateなど)を利用することもできます。
また、DIコンテナであるSpringとの連携も可能で、Springを通して、データベースとの接続を行うこともできます。ただ、Springを利用すると、どうしてもXMLファイルでの設定項目が多くなってしまいます。また、ちょっとした処理でも前準備が必要で、ソースコードも長くなってしまいますので、今回は、XML設定が不要な、ActiveObjectsというO/Rマッピングフレームワークのみを用いて、データベース接続の基本を説明することにします。
O/Rマッピングとは、オブジェクト指向でのObjectと、RDB(リレーショナルデータベース)をマッピングするということです。一般的なRDBでは、いわゆるオブジェクト指向言語で、直接データベースの値を操作することができません。そのため、オブジェクトをデータベースのレコードに関連付ける仕組みが必要になってきます。
また、そのような機能をコンポーネント化したものを、O/Rマッピングフレームワークと呼び、Hibernate、iBATIS、JPA(Java Persistence API)などが有名です。
一方、DIコンテナとは、「DI(Dependency Injection:依存性の注入)」と呼ばれる設計思想に沿って作られたコンポーネントを、管理するためのライブラリです。DIとは、コンポーネント間の依存関係をソースコードから排除して、実行時に依存するコードを「注入」するデザインパターンです。代表的なDIコンテナとしては、Spring Frameworkや、Seasarがあります。
サンプルとしては、先ほどのBooks2Actionクラスを少し拡張して、データベースに登録する処理と、登録したデータを一覧表示する処理を追加してみます。

前準備
今回のサンプルでは、ActiveObjectsフレームワークが対応しているデータベースの一つである、MySQLを利用します。MySQLのインストールについては、WINGSプロジェクトのサポートページを参照してください。
まず、データベースとテーブルを作成しておきます。ここではデータベースはbooks、テーブルもbooksという名前にしました。テーブルを作成するSQLスクリプトは、次のようになります。ごく単純に、BooksModelオブジェクトのフィールドを文字列の項目とし、さらに、ActiveObjectsのデフォルトのプライマリーキーである、数値のIDカラムを追加しています。
CREATE TABLE books (
id INTEGER NOT NULL AUTO_INCREMENT,
isbn VARCHAR(14),
title VARCHAR(100),
author VARCHAR(50),
PRIMARY KEY (id)
) ENGINE=InnoDB;
また、ActiveObjects(activeobjects-0.8.2.zip)をダウンロードし、解凍して得られるactiveobjects-0.8.2.jarと、MySQLのコネクタであるmysql-connector-java-5.1.7-bin.jarを、参照ライブラリーにコピーしておきます。
Actionクラス(BooksDBAction.java)
まずは、Actionクラスの変更点を見ていきましょう。
public class BooksDBAction extends ActionSupport
implements ScopedModelDriven<BooksModel> {
private BooksModel model; // 本情報のModelクラス
private String scopeKey; // セッションでのModelオブジェクト識別キー
List<BooksModel> books; // 登録した本情報の一時格納用
private String message; // データベース例外メッセージ表示用
@Action(
value = "/registerDB",
results = {
@Result(name = "success", location = "booksRegisterDB.jsp" )
}
)
public String register() throws Exception {
try{
// DAOオブジェクトの生成
BooksDAO dao = new BooksDAO();
// 入力値のデータベース登録
dao.register(model.getIsbn(), model.getTitle(), model.getAuthor());
// データベースから全登録データを取得
books = dao.getAll();
}
catch(SQLException e) {
setMessage(e.getMessage());
}
return "success";
}
フィールドを2つ追加しています。
booksは、データベースに登録した本の情報を取得し、一時的に格納しておくListオブジェクトです。最後のデータ一覧画面では、このListオブジェクトの内容を表示しています。
messageは、データベース処理で例外が発生した場合に、その例外メッセージを保持しておく文字列です。
registerメソッドで、データベースの接続、登録/取得処理を行っています。といっても、Actionクラスでは、BooksDAOクラスのメソッドを呼んでいるだけです。データベースの実際の処理は、BooksDAOクラスが行っています。
このような実装方法を、「DAO(Data Access Object)パターン」と呼びます。DAOパターンでは、データベースへのアクセスを専用のクラスでカプセル化します。それにより、データベースに依存する処理を、ビジネスロジックから排除することができます。
なお、通常のDAOパターンでは、処理を抽象化したインターフェイスを定義して、DAOクラスで実装するようにします。そうしておけば、データベースへのアクセス手段や実装が異なるDAOクラスを使う場合でも、公開しているインターフェイスは変わりませんので、ビジネスロジックを変更する必要がありません。
DAOクラス(BooksDAO.java)
では、次にBooksDAOクラスなのですが、その前に、Booksインターフェイスを説明しておきます。このインターフェイスは、booksテーブルに対応するオブジェクトのインターフェイスで、テーブルの項目に対して、Getter/Setterを定義しているだけです(IDカラムは、既にEntityインターフェイスで定義済み)。
実装は、フレームワークのActiveObjectsが自動で生成してくれます。
public interface Books extends Entity {
public String getIsbn();
public void setIsbn(String isbn);
public String getTitle();
public void setTitle(String title);
public String getAuthor();
public void setAuthor(String author);
}
BooksDAOクラス本体は、次のようになります。
public class BooksDAO {
private static EntityManager manager;
public BooksDAO(){
manager =
new EntityManager("jdbc:mysql://localhost/books", "root", "");
// ホスト/データベース名、ユーザー、パスワードを指定
}
// 登録
public void register(String isbn, String title, String author ) throws SQLException{
Books book = manager.create(Books.class);
book.setIsbn(isbn);
book.setTitle(title);
book.setAuthor(author);
book.save();
}
// 全データ取得
public List<BooksModel> getAll() throws SQLException{
List<BooksModel> b = new ArrayList<BooksModel>();
Books[] books = manager.find(Books.class);
for (Books element : books) {
BooksModel tmp = new BooksModel();
tmp.setIsbn(element.getIsbn());
tmp.setTitleNoencode(element.getTitle());
tmp.setAuthorNoencode(element.getAuthor());
b.add(tmp);
}
return b;
}
}
コンストラクタ
BooksDAOクラスも、とてもシンプルです。コンストラクタで、net.java.ao.EntityManagerクラスをインスタンス化しています。EntityManagerクラスのコンストラクタで、MySQLのホスト名、データベース名、ユーザー名、パスワードを指定します。サンプルでは、それぞれ、"localhost"、"books"、"root"、なし、としています。
registerメソッド
テーブルへの登録は、EntityManager.createメソッドでBooksオブジェクトを生成し、登録したい値をセットしたのち、EntityManager.saveメソッドを呼び出します。
getAllメソッド
テーブルからの参照は、EntityManager.findメソッドを用います。findメソッドのパラメータで何も指定しなければ、テーブルからすべてのデータを、配列として取得することができます。
サンプルでは、BooksModelオブジェクトのListを作り、取得した配列から一つずつデータを取りだして、Listコンテナに追加しています。
なお、ActiveObjectsの詳細については、前述のサイトや、JavaDocを参照してください。
booksRegisterDB.jsp
booksRegisterDB.jspファイルでは、<s:iterator>タグを用いて、BooksModelのListオブジェクト全内容の一覧を表示しています。
<s:iterator value="books"> <p> 書名 : <s:property value="title" /><br /> 著者 : <s:property value="author" /><br /> ISBN : <s:property value="isbn" /><br /> </p> </s:iterator>
まとめ
今回は、ActionクラスとViewレイヤーでデータをやりとりする仕組みを解説しました。データベースとの連携も、ActiveObjectsを利用すれば、ごくシンプルに記述できることが分かるかと思います。
次回は、これまで紹介してきた機能をまとめて、より本格的なアプリケーションを作成することにしましょう。
