在作管理系統時。一般基於Facade模式的系統持久化層要寫許多Dao。這些dao裏面的方法又是重複的,那麼有沒有什麼好的方法來統一利用一個公共的Dao。
答案是能夠的。這裏咱們接觸到JDK5.0裏面的一個新特性:泛型。
關於泛型的含義我這裏就再也不解釋了。
下面咱們以一個對用戶管理和新聞管理的來示範。
首先是2個POJO。我這裏只列出User POJO。
(基於註釋的Pojo)java
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的接口。 spring
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 sql
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 session
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 代碼: this
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 spa
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; }; //其餘的方法的實現 }
持久化層就是這麼多了。
下面進入業務邏輯層,依然是先定義一個接口。 hibernate
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層的代碼能夠複用,少了很多。 對於大型管理系統,效果更明顯。