在原先的數據層在處理業務數據時,需要對不同的處理對象具備不同的方法來處理,比如客戶Customer對象的增刪改查基本操作需要一套save(Customer c)、delete(Long cust_id)、update(Customer c)、get(Long cust_id)這些方法,同樣,在聯繫人LinkMan對象的增刪改查有需要這麼一套類似的方法,區別只是操作的對象不一樣。我們苦苦追求如何不去寫重複的代碼!在jdk1.5版本出現之後,我們開發人員接觸到新的概念,叫作泛型。有泛型的出現,纔會有BaseDao的設計,我們的追求終究看到了答案。(在這其中也利用了反射技術)
BaseDao其實就是一個帶有泛型的接口,接口中寫出了一些數據庫操作的基本方法的,代碼如下:
package com.itcast.dao;
import java.io.Serializable;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
public interface BaseDao<T> {
//增
void saveOrUpdate(T t);
//刪
void delete(Serializable id);
//改
void update(T t);
//根據id查
T findById(Serializable id);
//查詢總記錄數
Integer getTotalCount(DetachedCriteria dc);
//查詢所有條目
List getPageList(DetachedCriteria dc, Integer start, Integer pageSize);
}
爲了基於接口編程,我們需要寫它的實現類,對方法進行實現,這個實現代碼基於泛型編寫的可能容易理解,理解不了的可以多看幾遍註釋回味回味其中的意思。
package cn.itcast.dao.impl;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate5.HibernateTemplate;
import cn.itcast.dao.BaseDao;
public class BaseDaoImpl<T> implements BaseDao<T> {
//持有操作數據庫的HibernateTemplate對象
private HibernateTemplate ht;
//持有Class對象,用來接收子類傳入的泛型的class對象
private Class clazz;
//構造函數,用來在通過反射創建該類對象時,經過空參構造代碼塊將
public BaseDaoImpl() {
//java中的反射API
//獲得可獲得泛型類型的父類(就是實際泛型)
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
//獲得泛型類型
clazz = (Class) pt.getActualTypeArguments()[0];
}
//保存對象
@Override
public void save(T t) {
ht.saveOrUpdate(t);
}
//根據id刪除對象
@Override
public void delete(Serializable id) {
T t = this.getById(id);
ht.delete(t);
}
//更新對象
@Override
public void update(T t) {
ht.update(t);
}
//根據id查詢對象
@Override
public T getById(Serializable id) {//id的數據類型Serializable是所有類型的基本數據類型及包裝
//類型的父接口,可以接受上面的所有類型數據
return (T) ht.load(clazz, id); //load加載對象需要傳入對象的字節碼及對象id
}
//根據離線查詢對象得到總記錄數
@Override
public Integer getTotalCount(DetachedCriteria dc) {
//設置查詢總記錄數(count)
dc.setProjection(Projections.rowCount());//select count(*)
List<Long> list = (List<Long>) ht.findByCriteria(dc);
//清空總記錄數條件
dc.setProjection(null);
return list.get(0).intValue();
}
//根據離線查詢對象,初始索引和頁大小,分頁查詢記錄,以list返回
@Override
public List getPageList(DetachedCriteria dc, Integer start, Integer pageSize) {
return ht.findByCriteria(dc, start, pageSize);
}
//注入HibernateTemplate對象
public void setHt(HibernateTemplate ht) {
this.ht = ht;
}
public HibernateTemplate getHt() {
return ht;
}
}
有了BaseDao的實現類BaseDaoImpl,我們就可以在處理不同對象時只需要調用這裏面的方法,傳入實際類型替代泛型,即可進行數據操作,大大減少我們的代碼量。到這裏基本上介紹的差不多了,但是爲了達到完美,我們在處理不同模塊的業務是都定義了數據操作接口,例如:CustomerDao、LinkManDao、UserDao分別管理不同類型的業務,對應這些接口,也具備了各自的實現類,在這裏,與BaseDao關聯就可以毫無顧忌的使用它內部的方法了
,關聯其實很簡單,用各個模塊的接口去繼承BaseDao接口,這樣基本的數據操作需要的方法聲明直接從父類拿來用,各個模塊的實現類一方面實現模塊接口,同時還要繼承BaseDaoImpl,這樣實現類的方法從父類直接拿來去實現接口中的方法,下面我貼出部分模塊的實現類和接口.
1. CustomerDaoImpl
package cn.itcast.dao.impl;
import cn.itcast.dao.CustomerDao;
import cn.itcast.domain.Customer;
public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao {}
基本數據操作的方法從BaseDaoImpl直接拿來用(此時已經將BaseDao中的泛型T置爲Customer)。
2. LinkManDaoImpl
package cn.itcast.dao.impl;
import cn.itcast.dao.LinkManDao;
import cn.itcast.domain.LinkMan;
public class LinkManDaoImpl extends BaseDaoImpl<LinkMan> implements LinkManDao {}
今天介紹BaseDao我所在的環境是Hibernate-struts2-Spring3,dao層用到的操作數據路的技術是HibernateTemplete模板技術,spring爲每個模塊的數據操作類注入了HibernateTemplete,配置代碼段在Application.xml文件中如下:
<!-- 配置Dao -->
<bean name="userDao" class="cn.itcast.dao.impl.UserDaoImpl" >
<property name="ht" ref="hibernateTemplate" ></property>
</bean>
<bean name="customerDao" class="cn.itcast.dao.impl.CustomerDaoImpl" >
<property name="ht" ref="hibernateTemplate" ></property>
</bean>
<bean name="linkManDao" class="cn.itcast.dao.impl.LinkManDaoImpl" >
<property name="ht" ref="hibernateTemplate" ></property>
</bean>