Javaee的Dao层的抽取
有时候我们在实现不同功能的时候回看到很多的Dao层的增加、修改、删除、查找都很相似,修改我们将他们提取BaseDao
一、提取前
1. 提取前的LinkDao层:
public interface LinkManDao { Integer findCount(DetachedCriteria detachedCriteria); List<LinkMan> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize); void save(LinkMan linkMan); LinkMan findById(Long lkm_id); void update(LinkMan linkMan); void delete(LinkMan linkMan); }
2. 提取前的LinkDaoImpl:
@Repository public class LinkManDaoImpl implements LinkManDao { @Autowired private HibernateTemplate hibernateTemplate; @Override public Integer findCount(DetachedCriteria detachedCriteria) { //select count(*) from LinkMan detachedCriteria.setProjection(Projections.rowCount()); List<Long> list = (List<Long>) hibernateTemplate.findByCriteria(detachedCriteria); if(list != null && list.size() > 0) { return list.get(0).intValue(); } return null; } @Override public List<LinkMan> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize) { detachedCriteria.setProjection(null); return (List<LinkMan>) hibernateTemplate.findByCriteria(detachedCriteria, startIndex, pageSize); } @Override public void save(LinkMan linkMan) { hibernateTemplate.save(linkMan); } //Dao层根据id查找联系人 @Override public LinkMan findById(Long lkm_id) { return hibernateTemplate.get(LinkMan.class, lkm_id); } //Dao层更新联系人信息 @Override public void update(LinkMan linkMan) { hibernateTemplate.update(linkMan); } //Dao层删除联系人 @Override public void delete(LinkMan linkMan) { hibernateTemplate.delete(linkMan); } }
3. 提取前的CustomerDao
public interface CustomerDao{ void save(Customer customer); Integer findCount(DetachedCriteria detachedCriteria); List<Customer> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize); Customer findById(Long cust_id); void delete(Customer customer); void update(Customer customer); List<Customer> findAll(); }
4.提取前的CustomerDaoImpl
@Repository public class CustomerDaoImpl implements CustomerDao { //注入hibernateTemplate模板 @Autowired private HibernateTemplate hibernateTemplate; /** * Dao层保存客户信息实现方法 * <p>Title: CustomerDaoImpl</p> * <p>Description: </p> * @param customer * @see com.sshcrm.dao.CustomerDao#saveCustomer(com.sshcrm.pojo.Customer) */ @Override public void saveCustomer(Customer customer) { hibernateTemplate.save(customer); } //根据条件查询结果集的总记录数 @Override public Integer findCount(DetachedCriteria detachedCriteria) { //select count(*) from Customer detachedCriteria.setProjection(Projections.rowCount()); List<Long> list = (List<Long>) hibernateTemplate.findByCriteria(detachedCriteria); if(list != null && list.size() > 0) { return list.get(0).intValue(); } return null; } //根据查询条件查询总页数 @Override public List<Customer> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize) { //由于在统计总记录数的时候已经修改了发送的SQL语句,在此需要需要清空 detachedCriteria.setProjection(null); return (List<Customer>) hibernateTemplate.findByCriteria(detachedCriteria, startIndex, pageSize); } @Override public Customer findById(Long cust_id) { return hibernateTemplate.get(Customer.class, cust_id); } @Override public void delete(Customer customer) { hibernateTemplate.delete(customer); } @Override public void update(Customer customer) { hibernateTemplate.update(customer); } @Override public List<Customer> findAll() { return (List<Customer>) hibernateTemplate.find("from Customer"); } }
5.可以看到CustomerDaoImpl和LinkManDaoImpl方法很相似,所以需要提取
二、利用在子类中传递真正的Class类型来提取BaseDao,编写泛型
1. BaseDao层
public interface BaseDao<T> { void save(T t); void update(T t); void delete(T t); public T findById(Serializable id); public List<T> findAll(); public Integer findCount(DetachedCriteria detachedCriteria); public List<T> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize); }
2. BaseDaoImpl层
public class BaseDaoImpl<T> implements BaseDao<T> { private Class clazz; //提供构造方法,在构造方法中让继承的子类向方法中传入具体类型Class public BaseDaoImpl(Class clazz) { this.clazz = clazz; } //注入HibernateTemplate模板 @Autowired private HibernateTemplate hibernateTemplate; //保存信息 @Override public void save(T t) { hibernateTemplate.save(t); } //更新信息 @Override public void update(T t) { hibernateTemplate.update(t); } //删除信息 @Override public void delete(T t) { hibernateTemplate.delete(t); } //根据id查询信息 @Override public T findById(Serializable id) { return (T) hibernateTemplate.get(this.clazz, id); } //查询所有信息 @Override public List<T> findAll() { return (List<T>) hibernateTemplate.find("from "+ this.clazz.getSimpleName()); } //查询Count(*)行记录数 @Override public Integer findCount(DetachedCriteria detachedCriteria) { detachedCriteria.setProjection(Projections.rowCount()); List<Long> list = (List<Long>) hibernateTemplate.findByCriteria(detachedCriteria); if(list != null && list.size() > 0) { return list.get(0).intValue(); } return null; } //分页查询信息 @Override public List<T> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize) { detachedCriteria.setProjection(null); return (List<T>) hibernateTemplate.findByCriteria(detachedCriteria, startIndex, pageSize); } }
3. 提取后的LinkManDao
public interface LinkManDao extends BaseDao<LinkMan>{ }
4. 提取后的LinkManDaoImpl
@Repository public class LinkManDaoImpl extends BaseDaoImpl<LinkMan> implements LinkManDao {
//提供构造参数,在构造方法中传入具体类型的Class
public LinkManDaoImpl() { super(LinkMan.class); } @Autowired private HibernateTemplate hibernateTemplate; }
4.提取后的CustomerDao
public interface CustomerDao extends BaseDao<Customer> { }
5. 提取后的CustomerDaoImpl
@Repository public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao {
//提供构造参数,在构造方法中传入具体的Class
public CustomerDaoImpl() { super(Customer.class); // TODO Auto-generated constructor stub } //注入hibernateTemplate模板 @Autowired private HibernateTemplate hibernateTemplate; }
6. 如果这样抽取完成以后,那么在编写DAO的时候如果里面都是一些CRUD的操作,在DAO中只需要提供构造方法即可。
三、如果将通用的DAO编写的更好,连构造方法都不想要了!!!需要怎么做??? 泛型反射
1 解决方案二:通过泛型的反射抽取通用的DAO
l 如果现在将DAO中的构造方法去掉,将父类的通用的DAO中提供无参数的构造即可,但是需要在无参数的构造中需要获得具体类型的Class才可以-----涉及到泛型的反射了。
l 回顾一下泛型:
泛型 :通用的类型。
<> :念为 typeof
List<E> :E称为类型参数变量
ArrayList<Integer> :Integer称为是实际类型参数
ArrayList<Integer> :ArrayList<Integer>称为参数化类型
需要做的时候在父类的构造方法中获得子类继承父类上的参数化类型中的实际类型参数
泛型反射的步骤:
第一步:获得代表子类对象的Class
第二步:查看API
Type[] getGenericInterfaces(); :获得带有泛型的接口,可以实现多个接口。
Type getGenericSuperclass(); :获得带有泛型的父类,继承一个类。
第三步:获得带有泛型的父类
第四步:将带有泛型的父类的类型转成具体参数化的类型
第五步:通过参数化类型的方法获得实际类型参数
2. 代码实现
2.1 修改BaseDaoImpl里面的无参构造方法:
public class BaseDaoImpl<T> implements BaseDao<T> { private Class clazz; //提供构造方法,在构造方法中让继承的子类向方法中传入具体类型Class /** * 不想子类上有构造方法,必须在父类中提供无参的构造,在无参构造中获取具体的类型Class * 具体类型中的Class是参数类型中的实际类型 参数 */ public BaseDaoImpl() { //反射:第一步获得Class Class clazz = this.getClass();//正在被调用的那个类的Class,CustomerDaoImpl或LinkManDaoImpl //具体查看JDK的API Type type = clazz.getGenericSuperclass();//参数化类型BaseDaoImpl<Customer>,BaseDaoImpl<LinkMan> //得到的type就是一个参数化类型,将type强转为参数化类型 ParameterizedType pType = (ParameterizedType) type; //通过参数化类型获得实际类型参数,得到一个实际类型参数的数组 Type[] types = pType.getActualTypeArguments(); //只获得第一参数类型即可 this.clazz = (Class) types[0];//得到Customer,LinkMan } //注入HibernateTemplate模板 @Autowired private HibernateTemplate hibernateTemplate; //保存信息 @Override public void save(T t) { hibernateTemplate.save(t); } //更新信息 @Override public void update(T t) { hibernateTemplate.update(t); } //删除信息 @Override public void delete(T t) { hibernateTemplate.delete(t); } //根据id查询信息 @Override public T findById(Serializable id) { return (T) hibernateTemplate.get(this.clazz, id); } //查询所有信息 @Override public List<T> findAll() { return (List<T>) hibernateTemplate.find("from "+ this.clazz.getSimpleName()); } //查询Count(*)行记录数 @Override public Integer findCount(DetachedCriteria detachedCriteria) { detachedCriteria.setProjection(Projections.rowCount()); List<Long> list = (List<Long>) hibernateTemplate.findByCriteria(detachedCriteria); if(list != null && list.size() > 0) { return list.get(0).intValue(); } return null; } //分页查询信息 @Override public List<T> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Integer pageSize) { detachedCriteria.setProjection(null); return (List<T>) hibernateTemplate.findByCriteria(detachedCriteria, startIndex, pageSize); } }
2.2 现在LinkDao和CustomerDao不用改变,修改LinkDaoImpl和CustomerDaoImpl
@Repository public class LinkManDaoImpl extends BaseDaoImpl<LinkMan> implements LinkManDao { //提供构造参数,在构造方法中传入具体的Class /* public LinkManDaoImpl() { super(LinkMan.class); }*/ @Autowired private HibernateTemplate hibernateTemplate; }
@Repository public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao { //提供构造参数,在构造方法中传入具体的Class /*public CustomerDaoImpl() { super(Customer.class); // TODO Auto-generated constructor stub }*/ //注入hibernateTemplate模板 @Autowired private HibernateTemplate hibernateTemplate; }
2.3 后面如果Dao层有特殊方法是可以在比如CustomerDaoImpl中去实现,相似的就不需要了,以此来到达抽取Dao层