由于要求在项目中使用泛型的DAO,所以上网Google了一下,找到了IBM的一篇文章。文章讲得不错,但是有些地方不清楚,如果完全按照那篇文章可能还会遇到一些困难。所以写了这篇文章,解释如何在项目中加入泛型的DAO实现。
首先是总的类关系的UML图:
![](http://ss.sysu.edu.cn/bbs/UploadFile/2006-11/200611262121381568.jpg)
然后是在配置文件中的关系图:
![](http://ss.sysu.edu.cn/bbs/UploadFile/2006-11/2006112621211252086.jpg)
其中,IStaffDao是我们自己定义的接口,这个接口类似:
public
interface
IStaffDAO
extends
GenericDao
<
Staff, Integer
>
{
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
public List listAll();
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
public Staff getByLogonAndId(String logon, Integer id);
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
// more
}
![](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
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
>
{
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/** */ /**
* 保存一个对象到数据库
* @param newInstance 需要保存的对象
* @return
*/
PK create(T newInstance);
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/** */ /**
* 从数据库读取一个对象
* @param id 主键
* @return
*/
T read(PK id);
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/** */ /**
* 更新一个对象
* @param transientObject 被更新的对象
*/
void update(T transientObject);
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/** */ /**
* 删除一个对象
* @param transientObject 被删除的对象
*/
void delete(T transientObject);
}
GenericDaoHibernateImpl 是 GenericDao 接口的泛型实现 :
/** */
/**
* 2006-11-22
* 范型DAO实现
* @author Zou Ang
* Contact <a href ="mailto:richardeee@gmail.com">Zou Ang</a>
*/
public
class
GenericDaoHibernateImpl
<
T,PK
extends
Serializable
>
extends
HibernateDaoSupport
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
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
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
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)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
final Query namedQuery = prepareQuery(method, queryArgs);
return (List < T > ) namedQuery.list();
}
public Iterator < T > iterateFinder(Method method, final Object[] queryArgs)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
final Query namedQuery = prepareQuery(method, queryArgs);
return (Iterator < T > ) namedQuery.iterate();
}
private Query prepareQuery(Method method, Object[] queryArgs)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
final String queryName = getNamingStrategy().queryNameFromMethod(type, method);
final Query namedQuery = getSession().getNamedQuery(queryName);
String[] namedParameters = namedQuery.getNamedParameters();
if (namedParameters.length == 0 )
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
setPositionalParams(queryArgs, namedQuery);
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} else
{
setNamedParams(namedParameters, queryArgs, namedQuery);
}
return namedQuery;
}
private void setPositionalParams(Object[] queryArgs, Query namedQuery)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// Set parameter. Use custom Hibernate Type if necessary
if (queryArgs != null )
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
for ( int i = 0 ; i < queryArgs.length; i ++ )
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Object arg = queryArgs[i];
Type argType = getArgumentTypeFactory().getArgumentType(arg);
if (argType != null )
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
namedQuery.setParameter(i, arg, argType);
}
else
{
namedQuery.setParameter(i, arg);
}
}
}
}
private void setNamedParams(String[] namedParameters, Object[] queryArgs, Query namedQuery)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// Set parameter. Use custom Hibernate Type if necessary
if (queryArgs != null )
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
for ( int i = 0 ; i < queryArgs.length; i ++ )
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Object arg = queryArgs[i];
Type argType = getArgumentTypeFactory().getArgumentType(arg);
if (argType != null )
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
namedQuery.setParameter(namedParameters[i], arg, argType);
}
else
{
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (arg instanceof Collection)
{
namedQuery.setParameterList(namedParameters[i], (Collection) arg);
}
else
{
namedQuery.setParameter(namedParameters[i], arg);
}
}
}
}
}
public FinderNamingStrategy getNamingStrategy()
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return namingStrategy;
}
public void setNamingStrategy(FinderNamingStrategy namingStrategy)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this .namingStrategy = namingStrategy;
}
public FinderArgumentTypeFactory getArgumentTypeFactory()
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return argumentTypeFactory;
}
public void setArgumentTypeFactory(FinderArgumentTypeFactory argumentTypeFactory)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this .argumentTypeFactory = argumentTypeFactory;
}
}
FinderNamingStrategy 是查找方法的命名规范:
public
interface
FinderNamingStrategy
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public String queryNameFromMethod(Class findTargetType, Method finderMethod);
}
目前有两个命名查找策略,使用的是
Simple 的,也就是直接是 < 类型名 >.< 方法名 > 的形式。
public
class
SimpleFinderNamingStrategy
implements
FinderNamingStrategy
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public String queryNameFromMethod(Class findTargetType, Method finderMethod)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return findTargetType.getSimpleName() + " . " + finderMethod.getName();
}
}
FinderArgumentTypeFactory 目前还没有什么作用,主要是返回自定义的 Hibernate 类型:
public
class
SimpleFinderArgumentTypeFactory
implements
FinderArgumentTypeFactory
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public Type getArgumentType(Object arg)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// 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
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public FinderIntroductionAdvisor()
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
super ( new FinderIntroductionInterceptor());
}
}
public
class
FinderIntroductionInterceptor
implements
IntroductionInterceptor
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
public Object invoke(MethodInvocation methodInvocation) throws Throwable
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
FinderExecutor executor = (FinderExecutor) methodInvocation.getThis();
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
String methodName = methodInvocation.getMethod().getName();
if (methodName.startsWith( " get " ) || methodName.startsWith( " list " ))
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Object[] arguments = methodInvocation.getArguments();
return executor.executeFinder(methodInvocation.getMethod(), arguments);
}
else if (methodName.startsWith( " iterate " ))
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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
好了,大公告成了!现在可以跟以前一样使用
appContext.getBean("staffDao");
这样进行测试了
staffDao.read(new Integer(1));
staffDao.getByLogonAndId("abc",new Integer(2));