泛型/类型安全DAO编写

news/2024/8/26 8:51:30

由于要求在项目中使用泛型的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 是泛型的 Dao 接口:

/**
 * 2006-11-22
 * 范型DAO接口
 * 
@author  Zou Ang
 * Contact  Zou Ang
 
*/

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  Zou Ang
 
*/

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  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);
    }

}


然后就到了配置文件了:

 

        
     
<  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"   />  
      
 
 
     
 
  
     
<  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  >  
 
     
 


还要在Staff.hbm.xml中配置:

 

 

<  query   name  ="Staff.getByLogonAndId"   >   
        
 select s from Staff s where s.staffLogon = ? and s.staffId = ?   ]]>   
 query  >  

这里要特别注意 这个要写在 的外面,否则会提示Mapping Exception:No Named Query

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

appContext.getBean("staffDao"); 这样进行测试了

staffDao.read(new Integer(1));

staffDao.getByLogonAndId("abc",new Integer(2));

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1575463



http://www.niftyadmin.cn/n/3660494.html

相关文章

sizeof输出各种内置类型所占空间的大小

#include <iostream> using namespace std; int main() {cout << sizeof(int)<<endl;cout << sizeof(char)<<endl;cout << sizeof(double)<<endl;return 0; }

博大精深!

中国文化貌似平平,可骨子里透着那么一股子的博大精神,看看吧.... 有一次&#xff0c;我参加接待了一个由欧洲贵族组成的参访团。他们中的大多数跟王族有亲戚关系&#xff0c;非常有学问和修养&#xff0c;待人彬彬有礼&#xff0c;但他们的修养背后隐藏着一种傲慢。最后一天聚餐…

Linux操作系统的目录结构

Linux继承了unix操作系统结构清晰的特点。在linux下的文件结构非常有条理。但是&#xff0c;上述的优点只有在对linux相当熟悉时&#xff0c;才能体会到。/vmlinuz  我们已经知道&#xff0c;每一个linux都有一个内核&#xff08;vmlinuz&#xff09;&#xff0c;我们在这个内…

INT_MAX 和INT_MIN

INT_MAX 2^31 - 1 2147483647&#xff0c; INT_MIN - 2^31 -2147483648

可替换系统(alternatives system)的应用浅议

[rootBlueSky tv2.0]# javaUsage: gij [OPTION] ... CLASS [ARGS] ... to invoke CLASS.main, or gij -jar [OPTION] ... JARFILE [ARGS] ... to execute a jar fileTry gij --helpfor more information.于是&#xff1a;[rootBlueSky tv2.0]# which j…

三种不同的方式将数字成绩转换为字母成绩

#include <iostream> #include<vector> #include<string> using namespace std; int main() {//switch语句int score,scor;cin >> score;scor score / 10;switch (scor){case 0:cout << "成绩不合格为F";break;case 1:cout << …

J2ME程序开发全方位基础讲解汇总

J2ME程序开发全方位基础讲解汇总一、J2ME中需要的Java基础知识现在有大部分人&#xff0c;都是从零开始学J2ME的&#xff0c;学习J2ME的时候&#xff0c;总是从Java基础开始学习&#xff0c;而且现在讲Java基础的书籍中都是以J2SE来讲基础&#xff0c;这就给学习造成了一些不必…