2010.10.23 追記
ここの記事ですが、将来、書き直すか、削除するかもしれません。
この記事の方法より、普通にBeanPropertySqlParameterSourceを使用するほうが
楽そうだからです。
勉強不足でこのクラスを知りませんでした。すみませんでした。
BeanPropertySqlParameterSourceの使用方法は大まかに以下のとおりです。
//検索キーのクラスの例
public class MemberSearchKey {
private int id;
public int getId(){ return id; }
}
//Daoのメソッドの例
public List<Member> findMember(MemberSearchKey key) {
BeanPropertySqlParameterSource bps = new BeanPropertySqlParameterSource(key);
//検索
List<Member> memberList = this.namedParameterTemplate.query(
sql, bps, new MemberRowMapper()
);
}
参考に、元の記事を残しておきます↓。
---------------------------------------------------------------
前回の記事で、NamedParameterJdbcTemplateの基本的な使い方をみました。
・DBからデータを取得するには?(NamedParameterJdbcTemplateのサンプル)
この記事を読む前に、必ず前回の記事を読んでください。
さて、この記事ではよりうまくこのクラスを使う方法を書きます。
まず、Daoに渡すべき検索キーはMapの方が良いことを前回の記事で書きました。
しかしこれだけではまだ問題があります。
List<Member> find(Map key);
これだと、Mapは設定できる値がObjectになるので、型が間違っているかどうかが分かりません。
例えば IDが数字とします。
しかし、 key.put("id", "0001"); と記述してもエラーにはなりません。
これを解決してみましょう。
※以下の方法はStrutsを使用する場合、もっと便利になります。
ここではStrutsを含めてお話しませんが、後日記事にしたいと思います。
【型を制限するための工夫】
これは、良くやる手です。検索キー設定用のクラスを作るのです。
「わざわざ検索キーのためだけにクラスを作るの?」と思います?
型は重要なのでクラスを作るくらいで少しでも間違いが減るなら安いものです。
しかも、Mapでは会員の検索キーを表しているのか、商品の検索キーを表しているのか、何を意味しているのかまったく分かりません。しかし、専用のクラスがあれば間違いようがありません。
可読性が高くなるおまけつきなんです。
さて、早速いってみましょう。
public class MemberSearchKey extends HashMap<String, Object> {
//マップのキー final static public String ID = "id"; final static public String NAME = "name"; final static public String KANA = "KANA";
public MemberSearchKey() { // }
public int getId() { return (Integer)get(ID); }
public void setId(int id) { put(ID, id); }
public String getName() { return (String)get(NAME); }
public void setName(String name) { put(NAME, name); }
public String getKana() { return (String)get(KANA); }
public void setKana(String kana) { put(KANA, kana); }
/** @deprecated */ public Object put(String key, Object value) { //念のため使用不可にする throw new UnsupportedOperationException("使用してはいけないメソッドです。"); } }
【Daoのメソッド例】
@SuppressWarnings("unchecked") public List<Member> findMember(MemberSearchKey key) { String sql = "select * from t_member "; String where = createWhere(key);
if(!where.equals("")){ sql += " where " + where; }
//検索 List<Member> memberList = this.namedParameterTemplate.query( sql, key, new MemberRowMapper() );
return memberList; }
/** * 会員情報を検索するための条件句を作成する。 * @param params * @return */ protected String createWhere(MemberSearchKey params) {
StringBuffer where = new StringBuffer();
if(!StringUtils.hasLength(params.getId())){ where.append(" and id = :"); where.append(MemberSearchKey.ID); }
if(!StringUtils.hasLength(params.getName())){ where.append(" and name like :"); where.append(MemberSearchKey.NAME); where.append(" || '%'"); } if(!StringUtils.hasLength(params.getKana())){ where.append(" and kana like :"); where.append(MemberSearchKey.KANA); where.append(" || '%'"); } return where.delete(0, 4).toString(); }
【説明】
さて、なんとなく分かるでしょうか?
まず型を制限する工夫はいたって簡単。
MemberSearchKeyをみてください。
HashMapを継承して、setterとgetterをつけています。
これで型がはっきりし、型間違いがあればコンパイラーが教えてくれます。
次に、Daoの工夫です。
findMemberをみてください。
引数はMemberSearchKeyにします。
そして、where句の部分を別のメソッドで作成しています。
そのメソッド内ではMemberSearchKeyの定数を使用して文字列を作ってます。
こうすることで、名称が変わってもeclipseのリファクタリングの機能で変更が容易になります。
※StringUtils.hasLength
は、Springが提供するメソッドです。
NULLか""のいずれかのときにtrueを返します。
他にもStringUtilsには機能がいろいろあるので見てみてください!
どうでしょう。こうすることで、型の制限ができ、リファクタリングが容易になり、
可読性がよくなります。
まだ、工夫の方法はあるかもしれません。
是非、工夫してみてください!
【補足】
ちなみに、上記のcreateWhereメソッド内ではnameとkanaは前方一致にしています。
プレースホルダを使用してlikeなどを使うときは良くやる手です。
name like ? || '%'
というように書きます。
他のプレースホルダと同様に、name like ?
というように記述したのでは、なかなかうまく行きません。
(実際に様々なケースでやってみると分かります。)
”||”は、SQLの文字列連結の記号です。つまり、?が"あいう"とすると
name like 'あいう%'
と同じ意味です。
これはぜひ覚えておきましょう
【補足2】
上記では、複数の検索キーが必要なときに検索キー専用のクラスを作る、という工夫を見ました。
おそらく大丈夫とは思いますが、念のため補足します。
上記のようなことをするのは検索キーが複数になりそうな場合で、1つしか無いような場合に無理に実施する必要は当然ありません。
例えばテーブルのprimaryキーになっているIDのようなものでレコードを検索する場合は
Member findMember(String id);
のようにした方が使いやすいし、分かりやすいです。
また、primaryキーになっているので将来、引数を増やすこともなさそうです。
ですので、そういった場合と複数の検索キーが必要な場合とで判断して使っていきましょう!
参考:
・検索画面を簡単に実現するには? (Strutsで上記工夫を使用する例)
・SpringJDBCで作成したDaoとビジネスロジックを連携するには?
・DBからデータを取得するには?(SimpleJdbcTemplate のサンプル)
・DBからデータを取得するには?(NamedParameterJdbcTemplateのサンプル)