イントロダクション

 Seasar2もよくわかってないのだけど、簡単らしいので作ってみる。Seasar2S2Daoを公式サイトからとってきてクラスパスに配置。あとは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;
MemberTableCreate.sql

 で、まずは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;
    }
    
}
Member.java

  アンダーバーを取って比較してくれると思ってたんですが、うまくいかなかったので、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();    
}
MemberDao.java

 それからこれらのクラスを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>
MemberDao.dicon

次に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>
dao.dicon

 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>
j2ee.dicon

 "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();
        }
    }
}
client.java

結果は下記のとおり。

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 (&#39;member_member_id_seq&#39;)
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(&#39;テスト&#39;, &#39;03.29-11:31:48&#39;, &#39;テスト君&#39;, &#39;pass&#39;, 20, &#39;test@test.com&#39;, 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 = &#39;テスト&#39;, account = &#39;03.29-11:31:48&#39;, handle_name = &#39;テスト君&#39;, password = &#39;pass&#39;, mail = &#39;new@test.com&#39;, 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] 物理的なコネクションを閉じました