您的位置:首页 > 其它

泛型/类型安全DAO编写

2008-06-09 14:33 453 查看
由于要求在项目中使用泛型的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   name  ="namingStrategy"   >  


              <  ref   bean  ="simpleFinderNamingStratrgy"     />  


           


       


 


      <  bean   id  ="abstractDao"  


        class  ="org.springframework.aop.framework.ProxyFactoryBean"  


        abstract  ="true"   >  


          <  property   name  ="interceptorNames"   >  


              <  list  >  


                  <  value  >  finderIntroductionAdvisor   


               


           


       


 


      <  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   


           


       


 


      <  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       


           


          <  property   name  ="target"   >  


              <  bean   parent  ="abstractDaoTarget"   >  


                  <  constructor-arg  >  


                      <  value  >  com.gdnfha.atcs.common.pojo.Staff   


                   


               


           


       


 


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

 


<  query   name  ="Staff.getByLogonAndId"   >   


           


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

好了,大公告成了!现在可以跟以前一样使用
appContext.getBean("staffDao"); 这样进行测试了 staffDao.read(new Integer(1));
staffDao.getByLogonAndId("abc",new Integer(2));
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: