Posted on 2006-11-26 21:08 
Zou Ang 阅读(5467) 
评论(8)  编辑  收藏  所属分类: 
 
			
			
		 
		
		由于要求在项目中使用泛型的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));