| 在上一篇文章中已經配置好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"}; ?} } |