在做管理系统时。通常基于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层的代码可以复用,少了不少。
对于大型管理系统,效果更明显。