在上一篇文章中已经配置好struts2+spring+jpa+dwr,这篇我们来讲下通用DAO设计。
设计思路:利用spring对dao层的支持,使用泛行方式对它进行一次包装,此通用DAO只实现最基本的增删改查功能,具体的特殊实现有它的子类实现
接口设计,在原来的工程中建立一个源代码包,名称为common,然后建立包结构,我的包结构如图:
照片名称:包结构
在dao目录下创建BaseDao.java文件,此文件是一个接口,代码如下:
/**
* 基本的CRUD实现,使用方式:
* 比如您有个DAO叫UserDao,那么UserDao的写法如下:
* UserDao extends BaseDao<Long, User>
* UserDao的实现类的写法是:
* UserDaoImpl extends BaseJpaDaoSupport<Long, User> implements UserDao
* @author HLIN
*
* @param <K>
* @param <V>
*/
public interface BaseDao<K extends Serializable, V> {
void add(V entity) throws GenericDaoException;
void delete(V entity) throws GenericDaoException;
void delete(List<V> entities) throws GenericDaoException;
void delete(K id) throws GenericDaoException;
void update(V entity) throws GenericDaoException;
V find(K id) throws GenericDaoException;
V findSingle(String hql, Object... params) throws GenericDaoException;
List<V> find(String ql, Object... params) throws GenericDaoException;
List<V> findAll() throws GenericDaoException;
List<V> pageQuery(PageBean pageBean, String hql, Object... params) throws GenericDaoException;
}
这个接口中,我们使用了泛型,第一个参数是表的主键,必须是对象类型的;第二个参数是实体类型,不首限制。
接下来就用hibernate和jpa两种方式实现这个接口
hibernate实现,代码如下:
public class BaseHibernateDaoSupport<K extends Serializable, V> extends
HibernateDaoSupport implements BaseDao<K, V> {
public void add(V entity) {
getHibernateTemplate().save(entity);
}
public void delete(V entity) {
getHibernateTemplate().delete(entity);
}
public void delete(List<V> entities) {
getHibernateTemplate().deleteAll(entities);
}
public void delete(K id) {
getHibernateTemplate().delete(find(id));
}
@SuppressWarnings("unchecked")
public V find(K id) {
return (V) getHibernateTemplate().get(getEntityType(), id);
}
public V findSingle(final String hql, final Object... params) {
List<V> list = find(hql, params);
if (list.size() > 0)
return list.get(0);
return null;
}
@SuppressWarnings("unchecked")
public List<V> find(String hql, Object... params) {
return getHibernateTemplate().find(hql, params);
}
public void update(V entity) {
getHibernateTemplate().update(entity);
}
@SuppressWarnings("unchecked")
public List<V> findAll() {
return getHibernateTemplate().loadAll(getEntityType());
}
@SuppressWarnings("unchecked")
public List<V> pageQuery(final PageBean pageBean, final String hql,
final Object... params) {
List<V> list = getHibernateTemplate().executeFind(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
Query query = session.createQuery(hql);
for (int i = 0; i < params.length; i++) {
query.setParameter(i, params[i]);
}
return query.setFirstResult(
(pageBean.getCurrentPage() - 1)
* pageBean.getPageSize())
.setMaxResults(pageBean.getPageSize()).list();
}
});
pageBean.setTotalRecords(getRowCount(hql, params));
return list;
}
private Integer getRowCount(String sql, Object... params) {
sql = "select count(*) " + CommonUtil.removeSelect(CommonUtil.removeOrders(sql));
return new Integer(findSingle(sql, params).toString());
}
@SuppressWarnings("unchecked")
private Class<V> getEntityType() {
return (Class<V>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[1];
}
}
然后是JPA的实现,代码如下:
public class BaseJpaDaoSupport<K extends Serializable, V> extends JpaDaoSupport implements BaseDao<K, V> {
public void add(V entity) {
getJpaTemplate().persist(entity);
}
public void delete(V entity) {
getJpaTemplate().remove(entity);
}
public void delete(List<V> entities) {
for (V entity : entities)
getJpaTemplate().remove(entity);
}
public void delete(K id) {
getJpaTemplate().remove(find(id));
}
@SuppressWarnings("unchecked")
public List<V> findAll() {
String name = getEntityType().getName();
return getJpaTemplate().find("from " + name.substring(name.lastIndexOf(".")+1));
}
public V find(K id) {
return getJpaTemplate().find(getEntityType(), id);
}
@SuppressWarnings("unchecked")
public List<V> find(String hql, Object... params) {
return getJpaTemplate().find(hql, params);
}
@SuppressWarnings("unchecked")
public V findSingle(final String hql, final Object... params) {
return (V) getJpaTemplate().execute(new JpaCallback() {
public Object doInJpa(EntityManager em)
throws PersistenceException {
Query query = em.createQuery(hql);
return query.getSingleResult();
}
});
}
@SuppressWarnings("unchecked")
public List<V> pageQuery(final PageBean pageBean, final String hql, final Object... params) {
return getJpaTemplate().executeFind(new JpaCallback() {
public Object doInJpa(EntityManager em) throws PersistenceException {
List<V> result = em.createQuery(hql).setFirstResult(
(pageBean.getCurrentPage() - 1)).setMaxResults(
pageBean.getPageSize()).getResultList();
pageBean.setTotalRecords(getRowCount(hql, params));
return result;
}
});
}
public void update(V entity) {
getJpaTemplate().merge(entity);
}
private Integer getRowCount(String sql, Object... params) {
sql = "select count(*) " + CommonUtil.removeSelect(CommonUtil.removeOrders(sql));
return new Integer(findSingle(sql, params).toString());
}
@SuppressWarnings("unchecked")
private Class<V> getEntityType() {
return (Class<V>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[1];
}
}
好了,大功告成,我们来写个单元测试一下,这里的测试类使用的是spring的mock包,可以大大简化我们的spring测试
首先写一个测试基类,名称为BaseTestCase,代码如下:
public class BaseTestCase extends AbstractDependencyInjectionSpringContextTests {
protected String[] getConfigLocations() {
return new String[]{"classpath:spring-main.xml"};
}
}
这里继承的基类是AbstractDependencyInjectionSpringContextTests ,如果是在实际运行系统中测试,则需要继承AbstractTransactionalSpringContextTests,代码如下:
public class BaseTestCase extends AbstractDependencyInjectionSpringContextTests {
protected String[] getConfigLocations() {
return new String[]{"classpath:spring-main.xml"};
}
}