您的位置:首页 > 运维架构

使用AOP实现类型安全的泛型DAO

2007-06-17 15:53 841 查看
由于要求在项目中使用泛型的DAO,所以上网Google了一下,找到了IBM的一篇文章。文章讲得不错,但是有些地方不清楚,如果完全按照那篇文章可能还会遇到一些困难。所以写了这篇文章,解释如何在项目中加入泛型的DAO实现。

首先是总的类关系的UML图:



然后是在配置文件中的关系图:



其中,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 >

{






/** */ /**


* 保存一个对象到数据库


* @param newInstance 需要保存的对象


* @return


*/


PK create(T newInstance);




/** */ /**


* 从数据库读取一个对象


* @param id 主键


* @return


*/


T read(PK id);






/** */ /**


* 更新一个对象


* @param transientObject 被更新的对象


*/


void update(T transientObject);






/** */ /**


* 删除一个对象


* @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




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 是查找方法的命名规范:


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

好了,大公告成了!现在可以跟以前一样使用

appContext.getBean("staffDao"); 这样进行测试了
staffDao.read(new Integer(1));

staffDao.getByLogonAndId("abc",new Integer(2));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: