イントロダクション
Seasar2もよくわかってないのだけど、簡単らしいので作ってみる。Seasar2とS2Daoを公式サイトからとってきてクラスパスに配置。あとはJDBCドライバ(今回もPostgreSQLで試しています)。
まずはテスト用に次のテーブルを作る。
/* テーブル */ CREATE TABLE MEMBER ( MEMBER_ID integer DEFAULT NEXTVAL('"MEMBER_MEMBER_ID_SEQ"'::TEXT) NOT NULL, LAST_NAME varchar(64) NOT NULL, FIRST_NAME varchar(64), HANDLE_NAME varchar(128) NOT NULL, MAIL varchar(64), ACCOUNT varchar(16) NOT NULL, PASSWORD varchar(16), COMMENT text ) ; /* プライマリキー */ ALTER TABLE MEMBER ADD CONSTRAINT PK_MEMBER PRIMARY KEY (MEMBER_ID) ; /* シーケンス */ CREATE SEQUENCE MEMBER_MEMBER_SEQ;
で、まずはEntityをつくる。
package sample; import java.io.Serializable; public class Member implements Serializable { public static String memberId_ID = "sequence, sequenceName=MEMBER_MEMBER_ID_SEQ"; public static final String lastName_COLUMN = "last_name"; public static final String firstName_COLUMN = "first_name"; public static final String handleName_COLUMN = "handle_name"; public static final String memberId_COLUMN = "member_id"; private Integer memberId; private String lastName; private String firstName; private String handleName; private String mail; private String account; private String password; public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getHandleName() { return handleName; } public void setHandleName(String handleName) { this.handleName = handleName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getMail() { return mail; } public void setMail(String mail) { this.mail = mail; } public Integer getMemberId() { return memberId; } public void setMemberId(Integer memberId) { this.memberId = memberId; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
アンダーバーを取って比較してくれると思ってたんですが、うまくいかなかったので、lastName_COLUMN = などというアノテーション記法で対処。なお、DB側にある一部のカラムは省略してます。全部をマッピングするとなるとめんどい作業ですが、Eclipseはsetter/getterを生成してくれるので、とりあえずフィールドだけがんばればよい。このへんはじめだけでも自動化できないかな。たとえば、Middlegenのプラグインとかを作ればいいのだけど。
次はDao。AOPなのでインタフェースだけでいいらしい。とりあえず基本CRUDだけできるようにしてみる。
package sample; public interface MemberDao { public static final Class BEAN = Member.class; public int insert(Member member); public int update(Member member); public int delete(Member member); public Member[] getAll(); }
それからこれらのクラスをDIな感じにするための設定ファイルをつくる。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <include path="dao.dicon" /> <component class="sample.MemberDao"> <aspect>dao.interceptor</aspect> </component> </components>
次にdao.diconというファイルをルートに配置。サンプルのコピーそのまま。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN" "http://www.seasar.org/dtd/components.dtd"> <components namespace="dao"> <include path="j2ee.dicon"/> <component class="org.seasar.dao.impl.DaoMetaDataFactoryImpl"/> <component name="interceptor" class="org.seasar.dao.interceptors.S2DaoInterceptor"/> </components>
j2ee.diconというファイルでDB接続の設定をするらしい。サンプルをコピーしていらんところを消す。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN" "http://www.seasar.org/dtd/components.dtd"> <components namespace="j2ee"> <component class="org.seasar.extension.jdbc.impl.BasicResultSetFactory"/> <component class="org.seasar.extension.jdbc.impl.BasicStatementFactory"/> <component name="xaDataSource" class="org.seasar.extension.dbcp.impl.XADataSourceImpl"> <property name="driverClassName">"org.postgresql.Driver"</property> <property name="URL">"jdbc:postgresql://localhost:5432/test"</property> <property name="user">"user"</property> <property name="password">"pass"</property> </component> <component name="connectionPool" class="org.seasar.extension.dbcp.impl.ConnectionPoolImpl"> <property name="timeout">600</property> <property name="maxPoolSize">10</property> <destroyMethod name="close"/> </component> <component name="dataSource" class="org.seasar.extension.dbcp.impl.DataSourceImpl"/> <component name="transactionManager" class="org.seasar.extension.jta.TransactionManagerImpl"/> </components>
"user"とかなっているのは間違いではなく、OGNLという記述方式のルールのようです。ちなみにこれはJDBCを直接たたいてますが、JNDIからもらうことができるようですね。こんなふうにするらしいです。今回はアプリサーバ使ってないので、直接とることにしてます(はじめtransactionManagerタグを忘れててうまくいかなかった。transactionManagerはJNDIなしでもあたりまえですが、必要。書き方が違うんですな)。
<component name="initialContext" class="javax.naming.InitialContext"/> <component name="transactionManager" class="org.seasar.extension.j2ee.JndiTransactionManager"> <arg>initialContext</arg> <arg>"javax.transaction.TransactionManager"</arg> </component> <component class="org.seasar.extension.j2ee.JndiDataSource"> <arg>initialContext</arg> <arg>"jdbc/PostgreSQL"</arg> </component>
これでクライアントを作って、実行してみる。うまくいくかなっ?
package sample; import java.text.SimpleDateFormat; import java.util.Date; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.S2ContainerFactory; public class Cliant { public static void main(String args[]) { S2Container d2 = S2ContainerFactory.create("sample/MemberDao.dicon"); d2.init(); try { MemberDao dao = (MemberDao) d2.getComponent(MemberDao.class); Member mem = new Member(); mem.setLastName("テスト"); String account = new SimpleDateFormat("MM.dd-hh:mm:ss").format(new Date()); mem.setAccount(account); mem.setHandleName("テスト君"); mem.setPassword("pass"); mem.setMemberId(new Integer(1)); mem.setMail("test@test.com"); try { dao.insert(mem); } catch (Exception ex) { System.out.println(ex); } mem.setMail("new@test.com"); try { dao.update(mem); } catch (Exception ex) { System.out.println(ex); } try { Member[] members = dao.getAll(); for(int i=0;i < members.length;i++){ System.out.println(members[i]); } } catch (Exception ex) { System.out.println(ex); } try { dao.delete(mem); } catch (Exception ex) { System.out.println(ex); } } finally { d2.destroy(); } } }
結果は下記のとおり。
DEBUG 2005-03-29 11:31:48,172 [main] 物理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,172 [main] 論理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,242 [main] 論理的なコネクションを閉じました DEBUG 2005-03-29 11:31:48,262 [main] 論理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,282 [main] select nextval ('member_member_id_seq') DEBUG 2005-03-29 11:31:48,292 [main] 物理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,292 [main] 論理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,363 [main] 論理的なコネクションを閉じました DEBUG 2005-03-29 11:31:48,363 [main] INSERT INTO Member (last_name, account, handle_name, password, member_id, mail, comment, first_name) VALUES('テスト', '03.29-11:31:48', 'テスト君', 'pass', 20, 'test@test.com', null, null) DEBUG 2005-03-29 11:31:48,433 [main] 論理的なコネクションを閉じました DEBUG 2005-03-29 11:31:48,433 [main] 論理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,433 [main] UPDATE Member SET last_name = 'テスト', account = '03.29-11:31:48', handle_name = 'テスト君', password = 'pass', mail = 'new@test.com', comment = null, first_name = null WHERE member_id = 20 DEBUG 2005-03-29 11:31:48,473 [main] 論理的なコネクションを閉じました DEBUG 2005-03-29 11:31:48,483 [main] SELECT Member.last_name, Member.account, Member.handle_name, Member.password, Member.member_id, Member.mail, Member.comment, Member.first_name FROM Member DEBUG 2005-03-29 11:31:48,483 [main] 論理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,493 [main] 論理的なコネクションを閉じました sample.Member@164dbd5 sample.Member@9cb0f4 DEBUG 2005-03-29 11:31:48,493 [main] 論理的なコネクションを取得しました DEBUG 2005-03-29 11:31:48,493 [main] DELETE FROM Member WHERE member_id = 20 DEBUG 2005-03-29 11:31:48,543 [main] 論理的なコネクションを閉じました DEBUG 2005-03-29 11:31:48,543 [main] 物理的なコネクションを閉じました DEBUG 2005-03-29 11:31:48,543 [main] 物理的なコネクションを閉じました