Hibernateを使用したLiveCycle Data Service+Flexアプリケーション開発手順の紹介
河合 信敏氏
NECソフト株式会社 勤務
現在、Flex User Groupで、n-kawaiのハンドル名で精力的に活動中。
データベースと
連携するFlexアプリケーション開発では、アプリケーションサーバにLiveCycle Data Service
ES(以後LCDSと記述します)を組み合わせるのが一般的かと思います。(他にもSeaserプロジェクトのS2Flexを利用するなどの選択肢もあり
ます)
この説明ではLCDSとHibernateを利用して、データベース連携するFlexアプリケーション開発の一例を紹介します。
必要ソフトウェア
- FlexBuilder2もしくは3(labs.adobe.comで配布)
- LiveCycle Data Service ES(無償のExpress Editionで良い)
- Java SDK 5.0 (1.5.0_14)
- Tomcat5.5.25
- JOTM2.0.10
- MySQL5.0.41
- Eclipse3.3
- Hibernate(LCDSにも付属)
- HibernateSychronizer3.1.9
※混乱を避けるため、Javaの開発はEclipseで、Flexの開発はFlexBuilderで操作するものとして説明を記述します。
※EclipseにはPleiadesプラグインを入れておくとメニュー等が日本語化されます。
事前に必要な知識
この文書では、次の経験があることを前提として記述していますが、基礎的な知識があれば十分です。
- Javaでプログラムを作成したことがある
- Eclipseを使用したことがある
- Tomcatを使用したことがある
- MySQLを使用したことがある
- FlexBuilderでFlexアプリケーションを作成したことがある
事前に用意するもの
開発実行環境としては、Tomcat上にLCDS付属のflex.warテンプレートがデプロイされている環境を用意してください。
TomcatにLCDS環境を用意する方法は、こちらのURLを参考にしてください。
配布マテリアル(参考ソースコード) ( .zip , 13KB)
この文書のライセンス
1.データベース連携機能の選択について
LCDS上でデータベース連携機能(Assemblerと呼びます)を作成するには、大きく分けて次の3つがあると思います。
(1)JavaでAssemblerを自作する
(2)Hibernate Assemblerを使用する
(3)SQL Assemblerを使用する
(1)はJavaコードを自前で作成します。既存のDBアクセスコードを流用したり、独自のフレームワークを使用しているなどの場合では、それらを流用しつつDataServiceのfill()/sync()などのメソッドを実装したAssemblerを
作成します。少しのコードを記述しなければなりませんが、データベース処理については自分で作成したコードを使用することができます。
(2)はHibernateというオープンソースのO/Rマッピングを使います。基本的なデータアクセスではJavaコーディングをすることなく
データベース連携することができるため、開発工数が削減でき、その分をFlex開発に注力したり品質向上の為に工数を割り振ることができるかと思います。
この文書ではHibernate Assemblerを使用する手順の一例を紹介いたします。
(3)はSQL文をLCDSの設定ファイルに記述することでデータベース連携を実装します。SQL文でデータアクセスを設計できる場合は、SQL
Assemblerを選択してもよいかと思います。ここでは説明はしませんが、LCDS付属のsamples.warのソースコードを参照すれば、使用方
法が理解できると思います。
(2)と(3)については、いわゆるマスタメンテナンス系のシステム開発においては、DBアクセスのJavaコード作成が不要となるため、その分の
工数削減/生産性向上が見込めると思います。どちらを選択するかですが、プロジェクトにおいてデータ処理をSQL文で設計するのが適している場合には
(3)を、
そうでないならば(2)を検討するのが、1つの目安かと思います。
2.実習の流れ
それでは、開発作業の流れを順に実習していきます。作業の流れは、次のようになります
- データベースの作成
- HibernateによるO/Rマッピング作成
- LCDSの設定
- Flexアプリケーションの作成
実習では、図1のようなデータベース・テーブルを参照/更新する基本的なアプリケーションを作成します。
図1
また、システム構成としては、図2のようになります。
図2
サーバ側は、Hibernateの構成ファイルとマッピング、Data Transfer Object(DTO)を作成するだけですが、
プラグイン(HibernateSynchronizer)を使用することでさらに効率化が図れます。
データベース・テーブルの作成
テスト用のデータベース・テーブルを作成します。ここでは図3のような関係をもつテーブルを定義します。
図3
図3はClayデータベースモデリング(Eclipseプラグイン)を使用していますが、各自使い慣れたツールを使用して構いません。
テーブル作成SQLは下記のようになります。それぞれMySQL Query Browserなどで実行してください。
(コード中のtestはMySQLのデフォルトスキーマです)
・グループテーブル作成
CREATE TABLE test.LCDS_Group (
group_id INTEGER NOT NULL
, group_name VARCHAR(50)
, PRIMARY KEY (group_id)
) CHARACTER SET utf8;
・ユーザテーブル作成
CREATE TABLE test.LCDS_User (
user_id INTEGER NOT NULL
, user_name VARCHAR(50)
, email VARCHAR(50)
, group_id INTEGER
, PRIMARY KEY (user_id)
, INDEX (group_id)
, CONSTRAINT FK_User_1 FOREIGN KEY (group_id)
REFERENCES test.LCDS_Group (group_id)
) CHARACTER SET utf8;
またテスト用のデータとして、下記のようなデータをそれぞれのテーブルに作成してください
INSERT INTO `lcds_group` (`group_id`,`group_name`) VALUES
(1,'開発グループ'),
(2,'営業グループ'),
(3,'総務グループ');
INSERT INTO `lcds_user` (`user_id`,`user_name`,`email`,`group_id`) VALUES
(1001,'鈴木','suzuki@foo.com',1),
(1002,'田中','tanaka@foo.com',1),
(1003,'山本','yamamoto@foo.com',1),
(2001,'佐藤','satou@foo.com',2),
(2002,'斉藤','saitou@foo.com',2),
(3001,'伊藤','itou@foo.com',3);
以上でテストで使用するデータベース・テーブル作成ができました。
4.Hibernateの定義
次にHibernate定義を作成します。ここではシンプルなテーブルを使用するだけなので、定義ファイルを手で記述することも可能ですが、項目やテーブルの数が多くなると工数的な負担も大きくなるので、
効率化のためHibernateSynchronizer(Eclipseプラグイン)を使用します。
GUI操作となるので、若干記述が長くなりますが操作は1度試してみれば、簡単で効率的なことを実感できるかと思います。
4-1.Eclipseを起動し、メニューから、[新規]-[プロジェクト]-[Javaプロジェクト]を選択してください。
プロジェクト名は「LCDS_Lesson」とします。
4-2.[次へ]を選択し、ライブラリで、外部JARにHibernateとMySQLのJDBCドライバを追加しておきます。
<Hibernateライブラリ(LCDS付属)>
- antlr-2.7.5H3.jar
- asm-attrs.jar
- asm.jar
- cglib-2.1.2.jar
- commons-collections-2.1.1.jar
- dom4j-1.6.1.jar
- ehcache-1.1.jar
- hibernate3.jar
<MySQL JDBC Connector>
- mysql-connector-java-5.1.5-bin.jar
4-3.作成したプロジェクトのsrcフォルダを右クリックして、[新規]-[その他...]を選択します。
4-4.HibernateのHibernate構成ファイルを選択し、[次へ]をクリックします。
4-5.データベース・タイプにMySQLを指定し、接続に図のような内容を指定します。
ユーザ名/パスワードは各自のアカウント情報を指定してください。
4-6.[終了]をクリックすると、hibernate.cfg.xmlが作成されます。念のためこのファイルをどこかにコピーしてください。
4-7.再びsrcフォルダを右クリックし、[新規]-[パッケージ]を選びパッケージを作成してください。
ここではパッケージ名は「test.lesson.lcds」とします。
4-8.作成したパッケージフォルダを右クリックし、[新規]-[その他...]を選択します。
4-9.HibernateのHibernateマッピング・ファイルを選択し、[次へ]をクリックします。
4-10.パスワードを入力して[更新]をクリックするとデータベース上のテーブルが表示されるので、3章で作成したテーブルを選択し、パッケージには4-7で作成したパッケージ名を指定し、[終了]をクリックします。
4-11.test.lesson.lcdsパッケージの配下にそれぞれのテーブルに対応したマッピングファイルが作成されていることを確認します(LcdsGroup.hbm.xml, LcdsUser.hbm.xml)。
4-12.次にマッピングからDTOを生成します。
LcdsGroup.hbm.xmlを右クリックし、[HibernateSynchronizer]-
[ファイルの同期]を選択します。これでグループ用のDTOソースコードが生成されました。
4-13.同じようにLcdsUser.hbm.xmlを右クリックして、[HibernateSynchronizer]-[ファイルの同期]を選択します。
4-14.マッピング定義の一部を修正します。
この実習で使用するテーブルは、プライマリキーの自動生成は必要ないので、LcdsGroup.hbm.xmlとLcdsUser.hbm.xmlをテキストエディタで開き、それぞれgeneratorタグをコメントアウトしてください。
(例)<!--<generator class="sequence">-->
4-15.次にLcdsGroup.hbm.xmlを右クリックし、[HibernateSynchronizer]-[マッピング参照の追加]を選択します。作成したマッピングが構成ファイルに追加されます。
4-16.同じようにLcdsUser.hbm.xmlを右クリックして、[HibernateSynchronizer]-[マッピング参照の追加]を選択します。
4-17.hibernate.cfg.xmlをテキストエディタで開いて内容を確認します。
マッピング定義はsession-factoryの最後に追加されていますが、実は先頭のDOCTYPEタグが消えてしまいます。
4-6.で作成したコピーから先頭のタグ行をコピーして復元ください。
4-18.Hibernate構成ファイルに若干の編集をします。
TomcatのコンソールでHibernateの動作を確認するためにhibernate.cfg.xmlの中の
hibernate.show_sqlプロパティの値をtrueにしておいてください。
4-19.LCDSで使用するfillメソッドに対応するクエリをマッピング定義に追加します。
それぞれのマッピングファイルの最下行</hibernate-mapping>の前に、次の行を追加してください。
・LcdsGroup.hbm.xmlに追加する行
<query name="all_group">From LcdsGroup</query>
・LcdsUser.hbm.xmlに追加する行
<query name="all_user">From LcdsUser</query>
4-20.グループのマッピングについては、ユーザ・テーブルとの関係を定義しているsetタグのinverse指定をfalseにしてください。
・LcdsGroup.hbm.xmlへの変更
<set name="LcdsUsers" inverse="false">
※one-to-many、many-to-oneの関係についてのタグは、Windows+Eclipse+
HibernateSynchronizerではマッピングが生成されましたが、MacOSX+Eclipse+
HibernateSynchronizerでは生成されませんでした。
私の環境の問題かどうか原因がわかりませんが、one-to-manyの関係をHibernte定義に反映したければ、この作業はWindows上で行った方が、良いかもしれません。
4-21.すでにEclipseが自動的に、生成されたDTOのJavaコードをコンパイルしているので、Eclipseワークスペースのbin配下のファイルをTomcatのwebapps/flex/WEB-INF/classesにコピーします。
testフォルダ
hibernate.cfg.xml
ここまでの操作で作成したHibernate構成ファイル、マッピングファイル、Javaソースコードは、添付マテリアルのsource/hibernateフォルダにあります。アカウント情報やURLなどは環境に合わせて変更してください。
5.LCDSの設定
5-1.Tomcatにデプロイしたflex.warテンプレートに、データサービス定義を追加します。
編集対象ファイルは、webapps/flex/WEB-INF/flex/data-management-config.xmlにあります。
5-2.チャネルの定義を追加します。
<default-channels>
<channel ref="my-rtmp"/>
</default-channels>
5-3.データサービスのdestinationを追加します。
<destination id="hibernate-groupuser">
<adapter ref="java-dao" />
<properties>
<use-transactions>true</use-transactions>
<source>flex.data.assemblers.HibernateAssembler</source>
<scope>application</scope>
<metadata>
<identity property="id"/>
</metadata>
<network>
<session-timeout>20</session-timeout>
<paging enabled="false" pageSize="10" />
<throttle-inbound policy="ERROR" max-frequency="500"/>
<throttle-outbound policy="REPLACE" max-frequency="500"/>
</network>
<server>
<hibernate-entity>test.lesson.lcds.LcdsGroup</hibernate-entity>
<fill-method>
<name>fill</name>
<params>java.util.List</params>
</fill-method>
<fill-configuration>
<use-query-cache>false</use-query-cache>
<allow-hql-queries>true</allow-hql-queries>
</fill-configuration>
</server>
</properties>
</destination>
<destination id="hibernate-user">
<adapter ref="java-dao" />
<properties>
<use-transactions>true</use-transactions>
<source>flex.data.assemblers.HibernateAssembler</source>
<scope>application</scope>
<metadata>
<identity property="id"/>
</metadata>
<network>
<session-timeout>20</session-timeout>
<paging enabled="false" pageSize="10" />
<throttle-inbound policy="ERROR" max-frequency="500"/>
<throttle-outbound policy="REPLACE" max-frequency="500"/>
</network>
<server>
<hibernate-entity>test.lesson.lcds.LcdsUser</hibernate-entity>
<fill-method>
<name>fill</name>
<params>java.util.List</params>
</fill-method>
<fill-configuration>
<use-query-cache>false</use-query-cache>
<allow-hql-queries>true</allow-hql-queries>
</fill-configuration>
</server>
</properties>
</destination>
5-4.LCDS上で動作に必要なHibernateのJARファイルを追加します。
LCDSインストールディレクトリにあるresources/hibernate配下の*.jarをTomcatのwebapps/flex/WEB-INF/libにコピーしてください。
5-5.同じくMySQLのJDBCドライバを追加します。
MySQLのJDBCドライバを、Tomcatのwebapps/flex/WEB-INF/libにコピーしてください。
ここまでで、APサーバ(Tomcat)へのデプロイと設定作業は完了です。
Tomcatを起動してください。起動時にエラーがでるようであれば、エラーメッセージに応じて設定箇所を見直してください。
※LCDSのコンソールエラーは、webapps/flex/WEB-INF/classesにある
commons-logging.propertiesの指定をNoOpLogから希望する書式の指定に変更することで、Tomcatコンソール
(catalina.out)に出力されます。
6.FLEXBUILDERでの作業
6-1.新規にFlexプロジェクトを作成します。ここではプロジェクト名をLcds_GroupUserとします。
6-2.[次へ]をクリックし、各自の環境に合わせてJ2EEサーバの情報を指定します。
6-3.次にFlex側のDTOクラスを作成します。
src
フォルダを右クリックし、ActionSriptクラスを選択し、サーバのDTOクラス(Java)と同じ名前"LcdsGroup"と
"LcdsUser"で作成してください。下記では最低限必要なリモートクラス指定とデータ変数を実装しています。必要に応じて
getter/setterを実装してください。ソースコードファイルは付属マテリアルにもあります。
(LcdsGroup.as)
package
{
import mx.collections.ArrayCollection;
[Managed]
[RemoteClass(alias="test.lesson.lcds.LcdsGroup")]
public class LcdsGroup
{
public var id:int;
public var groupName:String;
public var lcdsUser:ArrayCollection;
}
}
(LcdsUser.as)
package
{
[Managed]
[RemoteClass(alias="test.lesson.lcds.LcdsUser")]
public class LcdsUser
{
public var id:int;
public var userName:String;
public var email:String;
public var group:LCDSGroup;
}
}
6-4.まず、Lcds_GroupUser.mxmlに次のコードを記述してください
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout=“horizontal" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.data.DataService;
import mx.data.events.*;
import mx.rpc.events.*;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]
private var acGroups:ArrayCollection;
private var dsGroupUser:DataService;
public function initApp():void {
acGroups = new ArrayCollection();
dsGroupUser = new DataService("hibernate-groupuser");
dsGroupUser.autoCommit = false;
dsGroupUser.addEventListener(ResultEvent.RESULT, resultHandler);
dsGroupUser.addEventListener(FaultEvent.FAULT, faultHandler);
dsGroupUser.addEventListener(DataConflictEvent.CONFLICT, conflictHandler);
dsGroupUser.fill(acGroups, "all_group", []);
}
private function resultHandler(event:ResultEvent):void
{
trace("Data Service result return correct"); //BreakPointを設定
}
private function faultHandler(event:FaultEvent):void
{
Alert.show("Fault Error"); //BreakPointを設定
}
private function conflictHandler(event:DataConflictEvent):void
{
Alert.show("DataConflictError"); //BreakPointを設定
}
]]>
</mx:Script>
</mx:Application>
6-5.各イベントハンドラにブレークポイントを設定して、デバッグ実行してください。
正常に実行できればresultHandler()のブレークポイントで停止し、acGroupsには図のようにデータが格納されていることを確認できます。
6-6.ユーザ・テーブルについても同様です。
これでデータは取得できたので、後はFlexでデータ表示・更新処理のユーザ・インタフェースを記述するだけです。
シンプルな例としてのmxmlソースコードは、マテリアルにあります。
7.補足
7-1.データベース処理動作の確認
Hibernate構成ファイルでshow_sqlにtrueを指定しているので、各データ操作でどのようなSQLが実行されているかをTomcatコンソールで確認することができます。
7-2.アプリケーションの検証
Hibernate構成ファイル・マッピング指定や性能についての検証は十分に行ってください。
HibernateのマニュアルはこちらのURLで参照できます。
古いバージョンですが、日本語のマニュアルはこちらのURLで参照できます。もっと新しい日本語マニュアルの掲載場所をご存知の方は、教えてください。
この説明では触れませんでしたがAPサーバのコネクションプーリング設定等(hibernate.properties)も考慮が必要です
7-3.データアクセスをHibernateに「おまかせ」で良いのか?
7-1でデータアクセス時にどのようなSQLが発行されているのかを参照することができますが、多少冗長なSQL処理をしているように見えます。こ
の挙動については、システム要件として処理の最適化や性能が十分であるかや、開発期間などとのバランスを考えることになります。機能として性能条件が厳し
くないものはHibernate Assemblerを使用して生産性向上を図り、SQLを最適化したい機能ではSQL AssemblerやJava
Assemblerで実装するなど、適宜使い分けるのが良いかもしれません。
著者について
河合 信敏氏
FlexBuilder3の新機能により、基本機能が動作するサーバサイドとFlexのコードが自動生成されるようになりました。データベース連携するFlexアプリケーション開発では、初期の開発工数について、より短縮できるようになったと思います。
この文書の内容が、皆さまの作業効率化の助けになればと思います。