在原先的数据层在处理业务数据时,需要对不同的处理对象具备不同的方法来处理,比如客户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>