在做管理系統時。通常基於Facade模式的系統持久化層要寫許多Dao。這些dao里面的方法又是重復的,那么有沒有什么好的方法來統一利用一個公共的Dao。
答案是可以的。這里我們接觸到JDK5.0里面的一個新特性:泛型。
關於泛型的含義我這里就不再解釋了。
下面我們以一個對用戶管理和新聞管理的來示范。
首先是2個POJO。我這里只列出User POJO。
(基於注釋的Pojo)
package com.oa; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "tb_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(name = "username", length = 15) private String username; @Column(name = "password", length = 15) private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
如果按照常規的Facade模式來設計,我們的思路是:
先創建一個UserDao的接口。
package com.oa.dao; import java.util.List; import com.oa.User; public interface UserDao { public void save(User user); public void delete(int id); public void update(User user); public List<User> query(); public User get(int id); }
然后實現這個接口:UserDaoImpl
package com.oa.dao.impl; import java.util.List; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository; import com.oa.User; import com.oa.dao.MyHibernateDaoSupport; import com.oa.dao.UserDao; /** * 從Spring 2.0開始,引入了@Repository注解, * 用它來標記充當儲存庫(又稱 Data Access Object或DAO)角色或典型的類 */ /** * Spring 2.5引入了更多典型化注解(stereotype annotations): @Component、@Service和 @Controller。 * @Component是所有受Spring管理組件的通用形式; 而@Repository、@Service和 @Controller則是@Component的細化, * 用來表示更具體的用例(例如,分別對應了持久化層、 服務層 和 表現層)。 */ //@Scope("singlton") @Repository("userDao")//聲明此類為數據持久層的類 public class UserDaoImpl extends MyHibernateDaoSupport implements UserDao { public void delete(int id) { super.getHibernateTemplate().delete( super.getHibernateTemplate().load(User.class, id)); } public User get(int id) { return (User) super.getHibernateTemplate().get("from User", id); } @SuppressWarnings("unchecked") public List<User> query() { return super.getHibernateTemplate().find("from User"); } public void save(User user) { super.getHibernateTemplate().save(user); } public void update(User user) { super.getHibernateTemplate().update(user); } }
持久化層完畢。
接下來的是事務層
先創建一個UserService的接口
package com.oa.service; import com.oa.User; public interface UserService { public void save(User user); public void update(User user); }
然后實現這個接口:UserServiceImpl。
在UserServiceImpl里引用UserDao來實現業務邏輯。
package com.oa.service.impl; import com.oa.User; import com.oa.service.UserService; import com.oa.dao.UserDao; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 聲明此類為業務邏輯層的類 * 默認bean名稱生成器會返回小寫開頭的非限定(non-qualified)類名 * @Service * userServiceImpl */ @Service("userService") public class UserServiceImpl implements UserService { /** * @Autowired * * @Autowired 注解可以用於"傳統的"setter 方法,如下例: * public void setUserDao(UserDAO userDao) { this.userDao = userDao; } */ /** * @Resource有一個'name'屬性,缺省時,Spring 將這個值解釋為要注射的 bean 的名字。 * @Resource(name="userDao") */ @Autowired // or @Resource(name="userDao") private UserDao userDao; public void save(User user) { userDao.save(user); } public void update(User user) { userDao.update(user); } }
按照上面的模式:新聞管理也這么寫一遍。
重復的工作使得我們覺得好煩。
這個時候是泛型出場的時候了。
基於Facade的設計模式,dao和service還是要的。 這里我們就要設計一個公共的Dao.. 我們稱之為:GenericDao
package com.oa.dao; import java.io.Serializable; import java.util.*; /** * * * * @param <T> * 泛型,指實體類 type * @param <PK> * 泛型,指實體類主鍵的數據類型,如Integer,Long */ public interface GenericDao<T, PK> { /** * 保存指定實體類 * * @param entityobj * 實體類 */ public void save(T entity); /** * 刪除指定實體 * * @param entityobj * 實體類 */ public void delete(T entity); /** * * 刪除實體 * @param entityClass 實體類名 * @param id 實體的ID */ public void deleteById(Class<T> entityClass,PK id); /** * 更新或保存指定實體 * * @param entity 實體類 */ public void saveorupdate(T entity); /** * * 更新實體 * 可用於添加、修改、刪除操作 * @param hql 更新的HQL語句 * @param params 參數,可有項目或多項目,代替Hql中的"?"號 */ public void update(final String hql,final Object[] params); /** * 模糊查詢指定條件對象集合 <br> * 用法:可以實例化一個空的T對象,需要查詢某個字段,就set該字段的條件然后調用本方法<br> * 缺點:目前測試貌似只能支持String的模糊查詢,雖然有辦法重寫,但沒必要,其他用HQL<br> * * @param entity * 條件實體 * @return 結合 */ public List<T> findByExample(T entity); /** * 獲取所有實體集合 * * @param entityClass * 實體 * @return 集合 */ public List<T> findAll(Class<T> entityClass); public List<T> findAll(Class<T> entityClass,String hql,Object[] params,int start, int limit); /** * 查找指定PK實體類對象 * * @param entityClass * 實體Class * @param id * 實體PK * @return 實體對象 */ public T findById(Class<T> entityClass, PK id); /** * * 按HQL條件查詢列表 * @param hql 查詢語句,支持連接查詢和多條件查詢 * @param params 參數數組,代替hql中的"?"號 * @return 結果集List */ public List<T> findByHql(String hql,Object[] params); /** * 查找指定屬性的實體集合 * * @param entityClass * 實體 * @param propertyName * 屬性名 * @param value * 條件 * @return 實體集合 */ public List<T> findByProperty(Class<T> entityClass, String propertyName,Object value); /** * 查詢指定HQL語句的分頁數據集合 * * @param hsql * HQL語句 * @param start * 開始記錄號 * @param limit * 最大記錄號 * @return 分頁數據集合 * @throws Exception * 拋出異常 */ public List<T> findByPage(Class<T> entityClass,int start,int limit) ; /** * 獲得總記錄數 */ public T getTotalCount(Class<T> entityClass); public T getPageCount(String hql,Object[] params); }
看到,我們不再是具體的User , News
。。而是用 T 來取代實體。
因為我這個是基於 注解的,所以附上MyHibernateDaoSupport的代碼。
package com.oa.dao; import javax.annotation.Resource; import org.hibernate.SessionFactory; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; /** * 我們之所以要改寫 * HibernateDaoSupport,是因我為,我們要為DAO層的類注入SessionFactory這個屬性。 * 以后,我們開發的DAO類,就可以直接重用這個MyHibernateDaoSupport了。 * 其實,這樣做是相當於配置文件方式的代碼: * <bean id="userDao" class="com.oa.dao.UserDaoImpl"> * <property * name="sessionFactory" ref="sessionFactory"/> * </bean> * * @author Administrator * */ public class MyHibernateDaoSupport extends HibernateDaoSupport { @Resource(name="sessionFactory") //為父類HibernateDaoSupport注入sessionFactory的值 public void setSuperSessionFactory(SessionFactory sessionFactory){ super.setSessionFactory(sessionFactory); } }
到現在位置genericdao的接口有了,也就是我們要做什么。。現在就是實現它,就是怎么做。
GenericDaoImpl 代碼:
package com.oa.dao.impl; import java.io.Serializable; import java.util.List; import org.hibernate.Query; import org.springframework.stereotype.Repository; import com.oa.dao.GenericDao; import com.oa.dao.MyHibernateDaoSupport; @SuppressWarnings("unchecked") @Repository("genericDao") //聲明此類為數據持久層的類 public class GenericDaoImpl<T, PK extends Serializable> extends MyHibernateDaoSupport implements GenericDao<T, PK> { public void delete(T entity) { super.getHibernateTemplate().delete(entity); } public void deleteById(Class entityClass, PK id) { super.getHibernateTemplate().delete(findById(entityClass, id)); } public void save(T entity) { super.getHibernateTemplate().save(entity); } public void saveorupdate(T entity) { super.getHibernateTemplate().saveOrUpdate(entity); } public void update(String hql, Object[] params) { Query query = super.getSession().createQuery(hql); for(int i=0; i<params.length; i++){ query.setParameter(i, params[i]); } query.executeUpdate(); } public List<T> findAll(Class entityClass) { return super.getHibernateTemplate().loadAll(entityClass); } public List<T> findAll(Class entityClass, String hql, Object[] params,int start, int limit) { Query query = super.getSession().createQuery(hql); if(params!=null&¶ms.length>0){ for(int i = 0;i<params.length;i++){ query.setParameter(i, params[i]); } } if(start!=0&&limit!=0){ query.setFirstResult(start).setMaxResults(limit); } return query.list(); } public List<T> findByExample(T entity) { return super.getHibernateTemplate().findByExample(entity); } public List<T> findByHql(String hql, Object[] params) { Query query = super.getSession().createQuery(hql); if(null!= params && params.length>0){ for(int i = 0; i<params.length;i++){ query.setParameter(i, params[i]); } } return query.list(); } public T findById(Class entityClass, PK id) { return (T)super.getHibernateTemplate().get(entityClass, id); } public List<T> findByProperty(Class entityClass, String propertyName,Object value) { String queryString = "from "+entityClass.getName()+ " as model where model." + propertyName + "=?"; return super.getHibernateTemplate().find(queryString, value); } //分頁使用 public List<T> findByPage(Class<T> entityClass,int start,int limit) { Query query=super.getSession().createQuery("select o from "+entityClass.getName()+" o"); query.setFirstResult(start).setMaxResults(limit); return query.list(); } public T getTotalCount(Class entityClass) { return (T)super.getSession().createQuery("select count(o) from "+entityClass.getName()+" o").uniqueResult(); } public T getPageCount(String hql, Object[] params) { Query query = super.getSession().createQuery(hql); if(null!= params && params.length>0){ for(int i = 0; i<params.length;i++){ query.setParameter(i, params[i]); } } return (T)query.list(); } }
至此 泛型就告一個段落。
接下來日子就好過了。
我們不是有user news 等等一系列的curd管理。
以User為例子;
定義一個user的接口,
UserDao.Java
package com.oa.dao; import com.oa.User; public interface UserDao extends GenericDao<User, Integer> { public int login(User user); //其他的方法的 } 然后就是實現它 UserDaoImpl package com.oa.dao.impl; import com.oa.User; import com.oa.dao.UserDao; public class UserDaoImpl extends GenericDaoImpl<User, Integer> implements UserDao { public int login(User user){ //登陸判斷的方法 return XX; }; //其他的方法的實現 }
持久化層就是這么多了。
下面進入業務邏輯層,依然是先定義一個接口。
package com.oa.service; import com.oa.User; public interface UserService { public void save(User user); public void update(User user); public int login(User user); //其他的方法 }
接下來是實現
package com.oa.service.impl; import com.oa.User; import com.oa.dao. UserDao; import com.oa.service.TestUserService; public class UserService implements UserService { private UserDao UserDao; public void save(User user) { UserDao.save(user); } public void updasaveorupdatete(User user) { UserDao.saveorupdate(user); } public int login(User user) { return UserDao.login(user); } //其他的方法。。。。 }
Ok。。到現在我們就利用泛型dao來設計就完畢了
兩者相對比,發現dao層的代碼可以復用,少了不少。
對於大型管理系統,效果更明顯。