锁定老帖子 主题:基于泛型DAO的Facade设计模式.
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (2)
|
|
---|---|
作者 | 正文 |
发表时间:2009-06-06
最后修改:2009-06-06
答案是可以的。这里我们接触到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层的代码可以复用,少了不少。 对于大型管理系统,效果更明显。 Junit Test方法我这里就不提供了。 参考:rongxh7 吼吼。谢谢! 欢迎大家提出意见,但是拒绝人身攻击。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-06-06
最后修改:2009-06-06
谢谢,值得借鉴和学习。getTotalCount()与getPageCount()返回的不是数值?
|
|
返回顶楼 | |
发表时间:2009-06-08
支持LZ一下,跟我那个泛型DAO设计的差不多,不过感觉总是缺少点什么。等我把我的项目做起来,在做总结吧。
|
|
返回顶楼 | |
发表时间:2009-06-20
泛型在减少dao,service类或代码量上很有用,很强大, 楼主的设计思路不错。
|
|
返回顶楼 | |
发表时间:2009-06-21
首先,这种方式确实不错,但是,说真话,这种设计在JAVAEYE里都能搜索到很多,泛滥了!都是一个意思!
|
|
返回顶楼 | |
发表时间:2009-06-21
g81997842 写道 首先,这种方式确实不错,但是,说真话,这种设计在JAVAEYE里都能搜索到很多,泛滥了!都是一个意思!
je上确实是蛮多了。现在就是看大家标新立异能出点什么新东西了。。。 |
|
返回顶楼 | |
发表时间:2009-06-21
我觉得这也算楼主开发经验的一个升华吧。我个人也有过开发此类泛型Dao,当时就是为了简化Dao层开发的目的,参考的是Spring自带的PetStore里面JPA的实现。
|
|
返回顶楼 | |
发表时间:2009-06-22
g81997842 写道 首先,这种方式确实不错,但是,说真话,这种设计在JAVAEYE里都能搜索到很多,泛滥了!都是一个意思!
支持这个。大同小异而已。 |
|
返回顶楼 | |
发表时间:2009-06-23
这个思路深入人心了
|
|
返回顶楼 | |
发表时间:2009-06-24
这绝不是泛型的最佳实践!
|
|
返回顶楼 | |