Posted on 2006-11-26 21:08
Zou Ang 閱讀(5441)
評論(8) 編輯 收藏 所屬分類:
由于要求在項目中使用泛型的DAO,所以上網(wǎng)Google了一下,找到了IBM的一篇文章。文章講得不錯,但是有些地方不清楚,如果完全按照那篇文章可能還會遇到一些困難。所以寫了這篇文章,解釋如何在項目中加入泛型的DAO實現(xiàn)。
首先是總的類關(guān)系的UML圖:

然后是在配置文件中的關(guān)系圖:??

其中,IStaffDao是我們自己定義的接口,這個接口類似:
public
?
interface
?IStaffDAO?
extends
?GenericDao
<
Staff,?Integer
>
{?

public
?List?listAll();?

public
?Staff?getByLogonAndId(String?logon,?Integer?id);?

//
more?
?
}
?

?
GenericDao<T , PK extends Serilizable>
是泛型的
Dao
接口:
/**?*/
/**
?*?2006-11-22
?*?范型DAO接口
?*?
@author
?Zou?Ang
?*?Contact?<a?href?="mailto:richardeee@gmail.com">Zou?Ang</a>
?
*/
public
?
interface
?GenericDao
<
T,?PK?
extends
?Serializable
>
?
{


????
/**?*/
/**
?????*?保存一個對象到數(shù)據(jù)庫
?????*?
@param
?newInstance?需要保存的對象
?????*?
@return
?????
*/
????PK?create(T?newInstance);

????
/**?*/
/**
?????*?從數(shù)據(jù)庫讀取一個對象
?????*?
@param
?id?主鍵
?????*?
@return
?????
*/
????T?read(PK?id);
????

????
/**?*/
/**
?????*?更新一個對象
?????*?
@param
?transientObject?被更新的對象
?????
*/
????
void
?update(T?transientObject);
????

????
/**?*/
/**
?????*?刪除一個對象
?????*?
@param
?transientObject?被刪除的對象
?????
*/
????
void
?delete(T?transientObject);
}
GenericDaoHibernateImpl
是
GenericDao
接口的泛型實現(xiàn)
:
/**?*/
/**
?*?2006-11-22
?*?范型DAO實現(xiàn)
?*?
@author
?Zou?Ang
?*?Contact?<a?href?="mailto:richardeee@gmail.com">Zou?Ang</a>
?
*/
public
?
class
?GenericDaoHibernateImpl
<
T,PK?
extends
?Serializable
>
?
????
extends
?HibernateDaoSupport?

????????
implements
?GenericDao
<
T,?PK
>
?,FinderExecutor
{
????
????
private
?Class
<
T
>
?type;
????
private
?FinderNamingStrategy?namingStrategy?
=
?
new
?SimpleFinderNamingStrategy();?
//
?Default.?Can?override?in?config
????
private
?FinderArgumentTypeFactory?argumentTypeFactory?
=
?
new
?SimpleFinderArgumentTypeFactory();?
//
?Default.?Can?override?in?config
????

????
public
?GenericDaoHibernateImpl(Class
<
T
>
?type)
{
????????
this
.type?
=
?type;
????}
????
/**/
/*
?(non-Javadoc)
?????*?@see?com.gdnfha.atcs.common.service.dao.GenericDao#create(java.lang.Object)
?????
*/
????
public
?PK?create(T?newInstance)?
{
????????
return
?(PK)getHibernateTemplate().save(newInstance);
????}
????
/**/
/*
?(non-Javadoc)
?????*?@see?com.gdnfha.atcs.common.service.dao.GenericDao#delete(java.lang.Object)
?????
*/
????
public
?
void
?delete(T?transientObject)?
{
????????getHibernateTemplate().delete(transientObject);
????}
????
/**/
/*
?(non-Javadoc)
?????*?@see?com.gdnfha.atcs.common.service.dao.GenericDao#read(java.io.Serializable)
?????
*/
????
public
?T?read(PK?id)?
{
????????
return
?(T)getHibernateTemplate().get(type,?id);
????}
????
/**/
/*
?(non-Javadoc)
?????*?@see?com.gdnfha.atcs.common.service.dao.GenericDao#update(java.lang.Object)
?????
*/
????
public
?
void
?update(T?transientObject)?
{
????????getHibernateTemplate().update(transientObject);
????}
????
public
?List
<
T
>
?executeFinder(Method?method,?
final
?Object[]?queryArgs)

????
{
????????
final
?Query?namedQuery?
=
?prepareQuery(method,?queryArgs);
????????
return
?(List
<
T
>
)?namedQuery.list();
????}
????
public
?Iterator
<
T
>
?iterateFinder(Method?method,?
final
?Object[]?queryArgs)

????
{
????????
final
?Query?namedQuery?
=
?prepareQuery(method,?queryArgs);
????????
return
?(Iterator
<
T
>
)?namedQuery.iterate();
????}
????
????
private
?Query?prepareQuery(Method?method,?Object[]?queryArgs)

????
{
????????
final
?String?queryName?
=
?getNamingStrategy().queryNameFromMethod(type,?method);
????????
final
?Query?namedQuery?
=
?getSession().getNamedQuery(queryName);
????????String[]?namedParameters?
=
?namedQuery.getNamedParameters();
????????
if
(namedParameters.length
==
0
)

????????
{
????????????setPositionalParams(queryArgs,?namedQuery);

????????}
?
else
?
{
????????????setNamedParams(namedParameters,?queryArgs,?namedQuery);
????????}
????????
return
?namedQuery;
????}
????
private
?
void
?setPositionalParams(Object[]?queryArgs,?Query?namedQuery)

????
{
????????
//
?Set?parameter.?Use?custom?Hibernate?Type?if?necessary
????????
if
(queryArgs
!=
null
)

????????
{
????????????
for
(
int
?i?
=
?
0
;?i?
<
?queryArgs.length;?i
++
)

????????????
{
????????????????Object?arg?
=
?queryArgs[i];
????????????????Type?argType?
=
?getArgumentTypeFactory().getArgumentType(arg);
????????????????
if
(argType?
!=
?
null
)

????????????????
{
????????????????????namedQuery.setParameter(i,?arg,?argType);
????????????????}
????????????????
else
????????????????
{
????????????????????namedQuery.setParameter(i,?arg);
????????????????}
????????????}
????????}
????}
????
private
?
void
?setNamedParams(String[]?namedParameters,?Object[]?queryArgs,?Query?namedQuery)

????
{
????????
//
?Set?parameter.?Use?custom?Hibernate?Type?if?necessary
????????
if
(queryArgs
!=
null
)

????????
{
????????????
for
(
int
?i?
=
?
0
;?i?
<
?queryArgs.length;?i
++
)

????????????
{
????????????????Object?arg?
=
?queryArgs[i];
????????????????Type?argType?
=
?getArgumentTypeFactory().getArgumentType(arg);
????????????????
if
(argType?
!=
?
null
)

????????????????
{
????????????????????namedQuery.setParameter(namedParameters[i],?arg,?argType);
????????????????}
????????????????
else
????????????????
{

????????????????????
if
(arg?
instanceof
?Collection)?
{
????????????????????????namedQuery.setParameterList(namedParameters[i],?(Collection)?arg);
????????????????????}
????????????????????
else
????????????????????
{
????????????????????????namedQuery.setParameter(namedParameters[i],?arg);
????????????????????}
????????????????}
????????????}
????????}
????}
????
????
public
?FinderNamingStrategy?getNamingStrategy()

????
{
????????
return
?namingStrategy;
????}
????
public
?
void
?setNamingStrategy(FinderNamingStrategy?namingStrategy)

????
{
????????
this
.namingStrategy?
=
?namingStrategy;
????}
????
public
?FinderArgumentTypeFactory?getArgumentTypeFactory()

????
{
????????
return
?argumentTypeFactory;
????}
????
public
?
void
?setArgumentTypeFactory(FinderArgumentTypeFactory?argumentTypeFactory)

????
{
????????
this
.argumentTypeFactory?
=
?argumentTypeFactory;
????}
}
FinderNamingStrategy
是查找方法的命名規(guī)范:
public
?
interface
?FinderNamingStrategy

{
????
public
?String?queryNameFromMethod(Class?findTargetType,?Method?finderMethod);
}
目前有兩個命名查找策略,使用的是
Simple
的,也就是直接是
<
類型名
>.<
方法名
>
的形式。
public
?
class
?SimpleFinderNamingStrategy?
implements
?FinderNamingStrategy

{
????
public
?String?queryNameFromMethod(Class?findTargetType,?Method?finderMethod)

????
{
????????
return
?findTargetType.getSimpleName()?
+
?
"
.
"
?
+
?finderMethod.getName();
????}
}
FinderArgumentTypeFactory
目前還沒有什么作用,主要是返回自定義的
Hibernate
類型:
?
public
?
class
?SimpleFinderArgumentTypeFactory?
implements
?FinderArgumentTypeFactory

{
????
public
?Type?getArgumentType(Object?arg)

????
{
//
????????if(arg?instanceof?Enum)
//
????????{
//
????????????return?getEnumType(arg.getClass());
//
????????}
//
????????else
//
????????{
????????????
return
?
null
;
//
????????}
????}
//
????private?Type?getEnumType(Class<??extends?Object>?argClass)
//
????{
//
????????Properties?p?=?new?Properties();
//
????????p.setProperty("enumClassName",?argClass.getName());
//
????????Type?enumType?=?TypeFactory.heuristicType("org.hibernate.demo.EnumUserType",?p);
//
????????return?enumType;
//
????}
}
?
FinderIntroductionAdvisor
和
FinderIntroductionInterceptor:
?
public
?
class
?FinderIntroductionAdvisor?
extends
?DefaultIntroductionAdvisor

{
????
public
?FinderIntroductionAdvisor()

????
{
????????
super
(
new
?FinderIntroductionInterceptor());
????}
}
public
?
class
?FinderIntroductionInterceptor?
implements
?IntroductionInterceptor

{

????
public
?Object?invoke(MethodInvocation?methodInvocation)?
throws
?Throwable

????
{

????????FinderExecutor?executor?
=
?(FinderExecutor)?methodInvocation.getThis();

????????String?methodName?
=
?methodInvocation.getMethod().getName();
????????
if
(methodName.startsWith(
"
get
"
)?
||
?methodName.startsWith(
"
list
"
))

????????
{
????????????Object[]?arguments?
=
?methodInvocation.getArguments();
????????????
return
?executor.executeFinder(methodInvocation.getMethod(),?arguments);
????????}
????????
else
?
if
(methodName.startsWith(
"
iterate
"
))

????????
{
????????????Object[]?arguments?
=
?methodInvocation.getArguments();
????????????
return
?executor.iterateFinder(methodInvocation.getMethod(),?arguments);
????????}
//
????????else?if(methodName.startsWith("scroll"))
//
????????{
//
????????????Object[]?arguments?=?methodInvocation.getArguments();
//
????????????return?executor.scrollFinder(methodInvocation.getMethod(),?arguments);
//
????????}
????????
else
????????
{
????????????
return
?methodInvocation.proceed();
????????}
????}
????
public
?
boolean
?implementsInterface(Class?intf)

????
{
????????
return
?intf.isInterface()?
&&
?FinderExecutor.
class
.isAssignableFrom(intf);
????}
}
然后就到了配置文件了:
??????
<!--
??Start?:范型DAO配置??
-->
?
?????
<
?bean??
id?
="abstractDaoTarget"
?
????????class?
="com.gdnfha.atcs.common.service.dao.hibernate.GenericDaoHibernateImpl"
?
????????abstract?
="true"
?
>
?
?????????
<
?property??
name?
="sessionFactory"
?
>
?
?????????????
<
?ref??
local?
="sessionFactory"
???
/>
?
?????????
</
?property?
>
?
?????????
<
?property??
name?
="namingStrategy"
?
>
?
?????????????
<
?ref??
bean?
="simpleFinderNamingStratrgy"
???
/>
?
?????????
</
?property?
>
?
?????
</
?bean?
>
?
?
?????
<
?bean??
id?
="abstractDao"
?
????????class?
="org.springframework.aop.framework.ProxyFactoryBean"
?
????????abstract?
="true"
?
>
?
?????????
<
?property??
name?
="interceptorNames"
?
>
?
?????????????
<
?list?
>
?
?????????????????
<
?value?
>
?finderIntroductionAdvisor?
</
?value?
>
?
?????????????
</
?list?
>
?
?????????
</
?property?
>
?
?????
</
?bean?
>
?
?
?????
<
?bean??
id?
="finderIntroductionAdvisor"
?
????????class?
="com.gdnfha.atcs.common.service.dao.finder.FinderIntroductionAdvisor"
???
/>
?
?
?????
<
?bean??
id?
="namingStrategy"
?
????????class?
="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"
?
>
?
?????????
<
?property??
name?
="staticField"
?
>
?
?????????????
<
?value?
>
?org.hibernate.cfg.ImprovedNamingStrategy.INSTANCE?
</
?value?
>
?
?????????
</
?property?
>
?
?????
</
?bean?
>
?
?
?????
<
?bean??
id?
="extendedFinderNamingStrategy"
?
????????class?
="com.gdnfha.atcs.common.service.dao.finder.impl.ExtendedFinderNamingStrategy"
???
/>
?
????????
?????
<
?bean??
id?
="simpleFinderNamingStratrgy"
??class?
="com.gdnfha.atcs.common.service.dao.finder.impl.SimpleFinderNamingStrategy"
?
/>
?
??????
<!--
??End:?范型DAO配置??
-->
?
?
?????
<!--
??Start:?測試范型DAO??
-->
?
??
?????
<
?bean??
id?
="staffDao"
??parent?
="abstractDao"
?
>
?
?????????
<
?property??
name?
="proxyInterfaces"
?
>
?
?????????????
<
?value?
>
?com.gdnfha.atcs.maintain.service.dao.IStaffDAO?????
</
?value?
>
?
?????????
</
?property?
>
?
?????????
<
?property??
name?
="target"
?
>
?
?????????????
<
?bean??
parent?
="abstractDaoTarget"
?
>
?
?????????????????
<
?constructor-arg?
>
?
?????????????????????
<
?value?
>
?com.gdnfha.atcs.common.pojo.Staff?
</
?value?
>
?
?????????????????
</
?constructor-arg?
>
?
?????????????
</
?bean?
>
?
?????????
</
?property?
>
?
?????
</
?bean?
>
?
?
?????
<!--
???End:測試范型DAO??
-->
?
還要在Staff.hbm.xml中配置:
<
?query??
name?
="Staff.getByLogonAndId"
?
>
??
????????
<![CDATA[
?select?s?from?Staff?s?where?s.staffLogon?=???and?s.staffId?=????
]]>
??
</
?query?
>
?
這里要特別注意<query></query>這個要寫在<class></class>的外面,否則會提示Mapping Exception:No Named Query
好了,大公告成了!現(xiàn)在可以跟以前一樣使用
appContext.getBean("staffDao");
這樣進行測試了
staffDao.read(new Integer(1));
staffDao.getByLogonAndId("abc",new Integer(2));