調查管理系統 -(4)DAO與Service層的泛型抽取與實現


1、設計 BaseDao 與 BaseDaoImpl

1)設計接口 BaseDao

每個實體都應有一個對應的Dao接口,封裝了對這個實體的數據庫操作。在每個Dao接口中都應有一個基本的增刪改查的方法,但每個Dao接口中都寫一遍就是重復的代碼,可以把這些方法抽取到一個父接口中,定義為:

 1 package com.atguigu.surveypark.dao;
 2 import java.util.List;
 3 /**
 4  * BaseDao接口
 5  */
 6 public interface BaseDao<T> {
 7     //寫操作
 8     public void saveEntity(T t);
 9     public void saveOrUpdateEntity(T t);
10     public void updateEntity(T t);
11     public void deleteEntity(T t);
12     public void batchEntityByHQL(String hql,Object...objects); //按照HQL語句進行批量更新 13     //執行原生的sql語句
14     public void executeSQL(String sql,Object...objects);
15     
16     //讀操作
17     public T loadEntity(Integer id);
18     public T getEntity(Integer id);
19     public List<T> findEntityByHQL(String hql,Object...objects);
20     //單值檢索,確保查詢結果有且只有一條記錄
21     public Object uniqueResult(String hql,Object...objects);
22     //執行原生的sql查詢(可以指定是否封裝成實體)
23     public List executeSQLQuery(Class clazz,String sql,Object...objects);
24 }

2)設計實現類 BaseDaoImpl

每個Dao的接口還要有相應的實現類才可以,在每個DaoImpl中都要實現Dao接口中定義的所有方法,當然也包括公共的增刪改查方法(BaseDao中定義的基本方法)。每個DaoImpl中都實現一遍公共方法顯示是重復的,所以也可以抽取出來為一個父類BaseDaoImpl,在BaseDaoImpl中實現了BaseDao接口的所有方法,我們的DaoImpl只需要繼承他就可以不用重復的寫公共方法的實現了。
聲明如下:

 1 package com.atguigu.surveypark.dao.impl;
 2 import java.lang.reflect.ParameterizedType;
 3 import java.util.List;
 4 import javax.annotation.Resource;
 5 import org.hibernate.SessionFactory;
 6 import com.atguigu.surveypark.dao.BaseDao;
 7 /**
 8  * 抽象的dao實現,專門用於繼承
 9  */
10 @SuppressWarnings("unchecked")
11 public abstract class BaseDaoImpl<T> implements BaseDao<T> {
12     @Resource
13     private SessionFactory sessionFactory ; // 讓Spring注入sessionFactory
14     private Class<T> clazz ;
15     public BaseDaoImpl(){
16         //得到泛型化超類(返回值為參數化類型)
17         ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
18         clazz = (Class<T>) type.getActualTypeArguments()[0];
19     }
20     
21     protected Session getSession() { //獲取Session
22         return sessionFactory.getCurrentSession();
23     }
24     //省略了對接口中方法的實現
25 }

這里用到了泛型技術,需要在程序執行過程中確定泛型T的具體類型clazz獲取clazz時有兩種方法:

方法一:

Ⅰ、把clazz聲明成protected修飾符的,這樣子類中就可以訪問了,
Ⅱ、在每個子類的構造方法中傳遞這個屬性的值,如:
  public RoleDaoImpl() { clazz = Role.class; }
  public UserDaoImpl() { clazz = User.class; }

方法二:使用反射的方式(即上述BaseDaoImpl中使用的方法):

Ⅰ、在BaseDaoImpl的默認構造方法中寫如下代碼就可以了:
  ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
  clazz = (Class) pt.getActualTypeArguments()[0];
Ⅱ、說明:即使BaseDaoImpl沒有被定義為抽象類也不能直接使用,只能使用他的子類,否則這段代碼就無效了。因為只能通過其子類指定了泛型的具體類型之后,才能夠在BaseDaoImpl的構造方法中獲取到clazz的具體類型。

2、設計 BaseService 與 BaseServiceImpl

1)設計接口BaseService

在設計BaseService時有個不成文的規定,就是將BaseDao中的基本方法全部都復制到BaseServic中即可,如有需要擴展的業務方法則再獨立設計相應的Service接口,然后繼承BaseService接口即可。

因此BaseService的定義如下:

 1 package com.atguigu.surveypark.service;
 2 import java.util.List;
 3 /**
 4  * 基本的Service接口
 5  */
 6 public interface BaseService<T> {
 7     //寫操作
 8     public void saveEntity(T t);
 9     public void saveOrUpdateEntity(T t);
10     public void updateEntity(T t);
11     public void deleteEntity(T t);
12     public void batchEntityByHQL(String hql,Object...objects);
13     //執行原生的sql語句
14     public void executeSQL(String sql,Object...objects);
15     
16     //讀操作
17     public T loadEntity(Integer id);
18     public T getEntity(Integer id);
19     public List<T> findEntityByHQL(String hql,Object...objects);
20     //單值檢索,確保查詢結果有且只有一條記錄
21     public Object uniqueResult(String hql,Object...objects);
22     //查詢所有實體
23     public List<T> findAllEntities();
24     public List executeSQLQuery(Class clazz,String sql,Object...objects);
25 }

2)設計實現類 BaseServiceImp

在BaseServiceImpl中同樣采用了泛型技術,方便程序的實現。在BaseServiceImpl中主要是通過Spring注入了dao,然后通過dao調用了BaseDaoImpl中的基本方法的實現,已完成基本的業務操作。

具體實現如下:

 1 package com.atguigu.surveypark.service.impl;
 2 import java.lang.reflect.ParameterizedType;
 3 import java.util.List;
 4 import javax.annotation.Resource;
 5 import com.atguigu.surveypark.dao.BaseDao;
 6 import com.atguigu.surveypark.service.BaseService;
 7 /**
 8  * 抽象的Service實現,專門用於繼承
 9  */
10 public abstract class BaseServiceImpl<T> implements BaseService<T> {
11     private BaseDao<T> dao ;
12     private Class<T> clazz ;
13     @SuppressWarnings("unchecked")
14     public BaseServiceImpl() {
15         ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
16         clazz = (Class<T>) type.getActualTypeArguments()[0];
17     }
18     @Resource //注入dao
19     public void setDao(BaseDao<T> dao) {
20         this.dao = dao;
21     }
22     //省略了對接口中方法的實現
23 }

注意:在這里注入的是BaseDao接口的實現類,並且注解@Resource是添加在setDao方法上的。這是因為,BaseDao有多個實現類,因此在Spring進行dao注入時會有多個匹配的BaseDao的實現類滿足條件,因此不能將@Resource注解添加在屬性上,而是添加到set方法上,這樣,具體的Service實現類中可以覆寫setDao方法,在@Resource注解中添加name屬性指定要注入的具體的Dao實現類。如下所示:

 1 //UserService接口
 2 public interface UserService extends BaseService<User> {}
 3 //UserServiceImpl實現類
 4 @Service("userService")
 5 public class UserServiceImpl extends BaseServiceImpl<User> implements UserService {
 6     /**
 7      * 重寫該方法,目的是為了覆蓋超類中該方法的注解,指明注入指定的Dao對象,否則spring
 8      * 無法確定注入哪個Dao---有多個滿足條件的Dao.
 9      */
10     @Resource(name="userDao")
11     public void setDao(BaseDao<User> dao) {
12         super.setDao(dao);
13     }
14 }         

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM