跟数据库打交道,我习惯先设计接口,然后慢慢用HQL或者Criteria实现每个表具体的动作,引入Spring后再将实现类注入到各个接口,放在Spring容器中供上层调用。每个表总有一些通用的增删改查操作需要编写,为了提高编程效率我们将一些常见的操作抽象出来设计一个通用基本接口,这个接口定义了一些最最基本的操作,比如通过主键寻找记录,通过Criteria寻找记录集,添加/修改对象,通过主键删除对象等。原则上每个数据表都有一套自己的接口,这些接口将继承自通用接口,在各自的接口中定义每个表特有的一些操作,比如用户表,将定一个通过用户名和密码来check用户存不存在的方法,而这个方法是用户表特有的,所以要在UserDao中单独定义出来,而UserDao继承自BaseDao,那它当然具备BaseDao中所定义的所有方法。
在编写通用数据接口BaseDao之前,需要先准备一个分页模型。我们知道实用的系统肯定不会一下子把结果集从数据库中全部取出来的,尤其是Entry(用户发表的文章)这个表,取结果集之前需要准备一些分页参数,比如取多少条记录,从什么地方开始取,根据条件返回的总数有多少等等,这时候我们就需要一个分页模型PagingSupport。在Blog系统中,需要分页的数据集大概只有Entry这一个,但是为了项目更好的扩展,也为了今后遇到别的项目时能够复用,我们将PagingSupport定义成泛型,下面贴出这个分页模型的代码,供大家参考:
public class PagingSupport<T> {
//---------------static variables--------------------
// 默认每页显示的最大条数
public static final int DEFAULT_MAX_PAGE_ITEMS = 10;
// 默认开始记录条数
public static final int DEFAULT_OFFSET = 0;
// 默认显示页码最大数
public static final int DEFAULT_MAX_INDEX_PAGES = 10;
//---------------member variables------------------
// 每页显示最大条数
private int maxPageItems = DEFAULT_MAX_PAGE_ITEMS;
// 开始记录条数
private int offset=DEFAULT_OFFSET ;
//页码最大数
private int maxIndexPages=DEFAULT_MAX_INDEX_PAGES;
// 总记录数
private int totalCount;
//记录内容列表,理论上items.size应该小于maxPageItems
private List<T> items;
//总页数
private int totalPage;
//当前页
private int currentPage;
// 页数数组
private int[] pages = new int[0];
//设置记录总数,并根据记录总数计算页面数
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
int count = totalCount / this.maxPageItems;
if (this.totalCount % this.maxPageItems > 0) {
count++;
}
this.totalPage = count;
}
//以下省略全部的getter&setter
}
有了分页模型,就可以设计BaseDao通用数据接口了,正如一开始所讲的,这个接口定义了一些通用的数据操作方法,BaseDao同样也是使用泛型的,代码粘贴出来,供大家参考:
public interface BaseDao<T> {
/**
* Save or Update the domain
* @param domain
*/
public void saveOrUpdate(T domain);
/**
* Remove the domain from database
* @param domain
*/
public void remove(T domain);
/**
* Get the domain by the index id
* @param id
*/
public T get(Serializable id);
/**
* 使用Hiberante的Criteria查询返回结果集
* @param detachedCriterial
* @return resultset
*/
public List<T> getListByCriteria(DetachedCriteria detachedCriterial);
/**
* 使用Hibernate的Criteria返回结果集,设置起始位置和容量大小
* @param detachedCriteria
* @param offset
* @param size
* @return resultset
*/
public List<T> getListByCriteria(DetachedCriteria detachedCriteria,int offset,int size);
/**
* 根据条件提取结果集,并将结果集构造成一个页面信息
* @param detachedCriteria
* @param pageSize
* @param startIndex
* @return
*/
public PagingSupport<T> findPageByCriteria(DetachedCriteria detachedCriteria, int pageSize, int startIndex);
}
接下来为每个数据表建立一个自己的DAO继承自BaseDao,你可以什么都不定义,仅仅将泛型改为自己所负责的实体类。结构图如下:
OK,下面建立一个Impl包,我们在这个包里存放接口的实现类。首先设计一个BaseDaoImpl实现BaseDao,跟接口的层次类似,我们将为每个数据表设计一个实现类来负责数据操作,这些类继承自BaseDaoImpl。当前我们不一定要将每个方法都详详细细地用代码做好,只要搭个框架,更多的地方用TODO注释标明就可以了。因为这里大量运用了JAVA泛型,所以我原原本本地把文件贴出来,希望能帮助到对泛型不甚理解的朋友。
public class BaseDaoImpl<T> implements BaseDao<T> {
@Autowired
protected SessionFactory sessionFactory;
private Class<T> entityClass;
//关键是是这个构造函数,会将子类定义的实体类型接受进来
@SuppressWarnings("unchecked")
public BaseDaoImpl(){
entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public BaseDaoImpl(Class<T> type){
this.entityClass=type;
}
@Override
public void saveOrUpdate(T domain) {
// TODO Auto-generated method stub
System.out.println("no....");
this.sessionFactory.getCurrentSession().save(domain);
}
@Override
public void remove(T domain) {
// TODO Auto-generated method stub
}
@SuppressWarnings("unchecked")
@Override
public T get(Serializable id) {
T o=(T)this.sessionFactory.getCurrentSession().get(this.entityClass, id);
return o;
}
@Override
public List<T> getListByCriteria(DetachedCriteria detachedCriterial) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<T> getListByCriteria(DetachedCriteria detachedCriteria,
int offset, int size) {
// TODO Auto-generated method stub
return null;
}
@Override
public PagingSupport<T> findPageByCriteria(
DetachedCriteria detachedCriteria, int pageSize,
int startIndex) {
// TODO Auto-generated method stub
return null;
}
}
好了,这一章就到这里,今天主要是做了两个包,一个DAO包,一个Impl包。两个包的层次是一一对应的,BaseDaoImpl实现了BaseDao,DAO包中的其他接口继承自BaseDao;Impl包中的其他实现也继承了BaseDaoImpl。说上去混乱,像绕口令一样,其实一步一步做起来还是很清晰的。下一章我们将在Spring3中集成Struts2,并使用注解的方式配置一个DaoImpl作为Spring中的Bean,在Struts2的Action中获得Spring的Bean,处理结果使用JSP展现出来。