S2Daoのサンプルアプリ作成(オートコミットモード)

サンプルアプリの概要(トランザクション制御なしのオートコミットの場合)
「SAMPLE1テーブルに対する登録、更新、削除処理を行う簡単なサンプルアプリです。」
「SAMPLE1テーブルとMASTER1からの参照処理※を行う簡単なサンプルアプリです。」

※
SELECT 
      S.ID, 
      S.NAME,
      M.SALARY,
      M.UTIWAKE
FROM 
      SAMPLE1 S,
      MASTER1 M
WHERE 
      S.ID = M.MASTER_ID(+);

SAMPLE1テーブル

ID(PK) NUMBER(2)
NAME VARCHAR2(10)

MASTER1テーブル

MASTER_ID(PK) NUMBER(2)
SALARY NUMBER(6)
UTIWAKE VARCHAR2(16)


[開発環境]

  • JDK1.5.0_13
  • eclipse3.2
  • Seasar2 2.4.20
    • S2.4.20.zipを解凍し、各jarファイルにクラスパスを通す(詳細設定は他サイトを参考にして下さい)
  • S2Dao 1.0.47
    • s2-dao-1.0.47.zipを解凍し、各jarファイルにクラスパスを通す

[用意するもの]

  • データベースに上記テーブルSAMPLE1、MASTER1をCREATE
  • Seasar2コンテナからDaoを取り出しDBの参照を行うメインクラスDBQuery.java
  • テーブルとの関連付けに使用するJavaBeans(SAMPLE1テーブル用)…MemberInfo.java
  • テーブルとの関連付けに使用するJavaBeans(MASTER1テーブル用)…MasterInfo.java
  • Daoインタフェース(SAMPLE1テーブル用)…MemberInfoDao.javaインタフェース

以下のdiconファイルはクラスパスの通っている場所に配備すること

  • j2ee.dicon(データベースとの接続設定を記述)
  • 自作.dicon(Daoの注入に使用)

[処理の流れその1]
入力値チェックを行う場合

1.メインクラスのDBQueryThreadでSeasar2コンテナからSAMPLE1テーブル参照用のDaoコンポーネントを取得する。

2.Daoのインタフェース経由でSAMPLE1テーブルのデータを参照する。
その際、SAMPLE1テーブルのIDとMASTER1テーブルのMASTER_IDをキーにテーブルが結合され、その結合データがリストの形式で返される。

3.DBQueryThreadで、受け取ったリストをループで回し、テーブルの各カラムの値を取り出す。

DBQuery.java

package jp.co.companyname.app;

import java.sql.SQLException;
import java.util.List;

import jp.co.companyname.dao.MemberInfo;
import jp.co.companyname.dao.MemberInfoDao;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import org.seasar.framework.exception.SQLRuntimeException;

/**
 * S2コンテナとS2Daoを使用して、データベースの参照/更新を行います。
 * 2008/1/16
 * @author shimabukurot
 *
 */
public class DBQuery {

	public static void main(String[] args) {

		System.out.println(Thread.currentThread() + " --------- S2Daoテスト開始");

		// ■1SQLごとにトランザクションが完結する制御(オートコミット)		

		// S2コンテナからDaoコンポーネントを取得
		S2Container container = S2ContainerFactory.create("自作.dicon");
		MemberInfoDao dao = (MemberInfoDao) container.getComponent(MemberInfoDao.class);
		
		// [登録処理実行]
		// クエリ実行時にorg.seasar.framework.exception.SQLRuntimeExceptionが
		// 発生すると処理はtry-catch句で囲まれていない限りそこで終了します。
		dao.insert(new MemberInfo(5, "五郎"));
		dao.insert(new MemberInfo(6, "六郎"));
		dao.insert(new MemberInfo(7, "七郎"));
		dao.insert(new MemberInfo(8, "八郎"));
		System.out.println(Thread.currentThread() + " --------- S2Dao登録テスト終了");
		
		// [更新処理実行]
		dao.update(new MemberInfo(4, "四郎update"));
		System.out.println(Thread.currentThread() + " --------- S2Dao更新テスト終了");
		
		// [削除処理実行]
		dao.delete(new MemberInfo(4, "四郎del"));
		System.out.println(Thread.currentThread() + " --------- S2Dao削除テスト終了");

		// [参照処理実行]
		List mInfoList = dao.findAll();
		for (int i = 0; i < mInfoList.size(); i++) {
			MemberInfo mInfo = (MemberInfo) mInfoList.get(i);
			
			// 該当カラムにデータがない場合
			// 該当カラムがNUMBER型の場合は0、
			// 該当カラムがVARCHAR2型の場合はnullが返ります。
			System.out.println(Thread.currentThread() + "[SAMPLE1.id]    "  + mInfo.getId());
			System.out.println(Thread.currentThread() + "[SAMPLE1.name]  "  + mInfo.getName());
			System.out.println(Thread.currentThread() + "[MASTER1.salary]"  + mInfo.getMasterInfo().getSalary());
			System.out.println(Thread.currentThread() + "[MASTER1.utiwake]" + mInfo.getMasterInfo().getUtiwake());
		}
		System.out.println(Thread.currentThread() + " --------- S2Dao参照テスト終了");
	}
}

MemberInfo.java

package jp.co.companyname.dao;

public class MemberInfo {

	/* 
	 * [構文]
	 * スキーマ名.テーブル名
	 * テーブル名だけでも可
	 */
	public static final String TABLE = "スキーマ名.SAMPLE1";
	
	// 定数アノテーション
	//public static final String id_COLUMN = "ID";
	//public static final String name_COLUMN = "NAME";
	
	/**
	 * 
	 * RELNOをString型にするとjava.lang.IllegalArgumentExceptionで落ちます。
	 * RELNO定数は、N:1マッピングの連番になるので以下のように0から付けていく必要があります。
	 */
	public static final int masterInfo_RELNO   = 0;
	
	/**
	 * [構文]
	 * 
	 * エンティティ名(JavaBeansのクラス名:先頭は小文字)_RELKEYS = "N側のテーブルのカラム名: 1側のテーブルのカラム名";
	 * ※エンティティ名を間違うとテーブルの結合ができません。
	 */
	public static final String masterInfo_RELKEYS = "ID:MASTER_ID";
	
	private int id;
	private String name;
	
	private MasterInfo abc;// 結合対象のテーブルを表すエンティティ(変数名は任意でよい)
	
	// コンストラクタ
	public MemberInfo(){}
	
	public MemberInfo(int id, String name) {
		this.id = id;
		this.name = name;
	}
	
	public MemberInfo(int id, String name, int salary, MasterInfo masterInfo) {
		this.id = id;
		this.name = name;
		this.abc = masterInfo;
	}
	
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public MasterInfo getMasterInfo() {
		return abc;
	}

	public void setMasterInfo(MasterInfo masterInfo) {
		this.abc = masterInfo;
	}
}

MasterInfo.java

package jp.co.companyname.dao;

public class MasterInfo {

	/* 
	 * [構文]
	 * スキーマ名.テーブル名
	 * テーブル名だけでも可。
	 */
	public static final String TABLE = "スキーマ名.MASTER1";
	
	private int masterId;
	private int salary;
	private String utiwake;
	
	// 空コンストラクタ(DIコンテナがインスタンス生成を行うために必須)
	public MasterInfo(){};
	
	public MasterInfo(int id, int salary) {
		this.masterId = id;
		this.salary = salary;
	}
	

	public int getSalary() {
		return salary;
	}
	public void setSalary(int salary) {
		this.salary = salary;
	}

	public int getMasterId() {
		return masterId;
	}

	public void setMasterId(int masterId) {
		this.masterId = masterId;
	}

	public String getUtiwake() {
		return utiwake;
	}

	public void setUtiwake(String utiwake) {
		this.utiwake = utiwake;
	}
}

MemberInfoDao.javaインタフェース

package jp.co.companyname.dao;

import java.util.List;

/*
 * MemberInfoから情報を取得するDao。
 * 実装はDIコンテナが行います。
 * よって自分で実装クラスの
 * 宣言をする必要はありません。
 */
public interface MemberInfoDao {
	
	public static final Class BEAN = MemberInfo.class;
	
	public int insert(MemberInfo mInfo);
	
	public int update(MemberInfo mInfo);
	
	public int delete(MemberInfo mInfo);
	
	public void doSomething();
	
	public String getText();
	
	public List findAll();

}

j2ee.dicon(抜粋)

<!-- for Oracle -->
<component name="xaDataSource"
	class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
	<property name="driverClassName">
		"oracle.jdbc.driver.OracleDriver"
	</property>
	<property name="URL">
		"jdbc:oracle:thin:@ホスト名:ポート番号:サービス名"
	</property>
	<property name="user">"TEST"</property>
	<property name="password">"TEST"</property>
	<initMethod name="addProperty">
		<arg>"includeSynonyms"</arg>
		<arg>"true"</arg>
	</initMethod>
</component>

自作.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components>
    <include path="dao.dicon" />
    
	  <component name="MemberInfoDaoDesu" class="jp.co.companyname.dao.MemberInfoDao">
         <aspect>dao.interceptor</aspect>
      </component>

</components>

おまけ:テスト用の自作.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components>
    <include path="dao.dicon" />
    
	★MemberInfoDaoTestのモックテスト用。ダミーのgetTextの戻り値を用意。getTextはメソッド名
      <component name="MemberInfoDaoDesu" class="jp.co.companyname.dao.MemberInfoDao">
           <aspect>
           <component class="org.seasar.framework.aop.interceptors.MockInterceptor">
               <initMethod name="setReturnValue">
                 <arg>"getText"</arg>
                 <arg>"テスト用のダミーテキストです。dummy."</arg>
               </initMethod>
           </component>    
        </aspect>
      </component>
      
</components>