基于Spring、Hibernate的通用DAO层与Service层的兑现
因为DAO层基本的就是CRUD操作,变化不是很大,要是有变化的那就是查询。而确实没有必要为每一个实体写一个完整的DAO,但是没有还不行,那就“抽取”出来吧。而Service依赖与DAO层,有时就是简单调用一下,也确实没有必要每个都写。总之,不爱写多个,那就写一个通用的,而其他的继承或实现这个通用的可以了。
还是用代码说话吧。
package org.monday.dao; import java.io.Serializable; import java.util.List; /** * BaseDAO 定义DAO的通用操作 * * @author Monday */ public interface BaseDao<T> { public void save(T entity); public void update(T entity); public void delete(Serializable id); public T findById(Serializable id); public List<T> findByHQL(String hql, Object... params); }
上面的DAO只定义了一些常见的方法,有需要通用的方法,可以随便加,然后实现它就行了。
以上是BaseDao和它的实现类。 那下面以CustomerDao与OrderDao为例,编写具体的Dao
package org.monday.dao.impl;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.annotation.Resource;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.monday.dao.BaseDao;
/**
* BaseDaoImpl 定义DAO的通用操作的实现
*
* @author Monday
*/
@SuppressWarnings("unchecked")
public class BaseDaoImpl<T> implements BaseDao<T> {
private Class<T> clazz;
/**
* 通过构造方法指定DAO的具体实现类
*/
public BaseDaoImpl() {
ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
clazz = (Class<T>) type.getActualTypeArguments()[0];
System.out.println("DAO的真实实现类是:" + this.clazz.getName());
}
/**
* 向DAO层注入SessionFactory
*/
@Resource
private SessionFactory sessionFactory;
/**
* 获取当前工作的Session
*/
protected Session getSession() {
return this.sessionFactory.getCurrentSession();
}
public void save(T entity) {
this.getSession().save(entity);
}
public void update(T entity) {
this.getSession().update(entity);
}
public void delete(Serializable id) {
this.getSession().delete(this.findById(id));
}
public T findById(Serializable id) {
return (T) this.getSession().get(this.clazz, id);
}
public List<T> findByHQL(String hql, Object... params) {
Query query = this.getSession().createQuery(hql);
for (int i = 0; params != null && i < params.length; i++) {
query.setParameter(i, params);
}
return query.list();
}
}
package org.monday.dao;
import org.monday.domain.Customer;
/**
* 客户DAO继承BaseDAO
*
* @author Monday
*/
public interface CustomerDao extends BaseDao<Customer> {
/**
* 若BaseDAO 没有定义的方法,可以在这里添加
*/
}
package org.monday.dao.impl;
import org.monday.dao.CustomerDao;
import org.monday.domain.Customer;
import org.springframework.stereotype.Repository;
/**
* 客户DAO的实现类 继承BaseDaoImpl 显示客户DAO接口
*
* @author Monday
*/
@Repository(value = "customerDao")
public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao {
/**
* 若CustomerDao 定义了BaseDAO没有的方法,则可以在这里实现
*/
}
package org.monday.dao;
import org.monday.domain.Order;
/**
* 订单DAO继承BaseDAO
*
* @author Monday
*/
public interface OrderDao extends BaseDao<Order> {
/**
* 若BaseDAO 没有定义的方法,可以在这里添加
*/
}
package org.monday.dao.impl;
import org.monday.dao.OrderDao;
import org.monday.domain.Order;
import org.springframework.stereotype.Repository;
/**
* 订单DAO的实现类 继承BaseDaoImpl 显示订单DAO接口
*
* @author Monday
*/
@Repository(value = "orderDao")
public class OrderDaoImpl extends BaseDaoImpl<Order> implements OrderDao {
/**
* 若OrderDao 定义了BaseDAO没有的方法,则可以在这里实现
*/
}
至于具体的Service怎么写呢?看下面:
package org.monday.service; import java.io.Serializable; import java.util.List; /** * BaseService 定义Service的通用操作 * * @author Monday */ public interface BaseService<T> { public void save(T entity); public void update(T entity); public void delete(Serializable id); public T getById(Serializable id); public List<T> getByHQL(String hql, Object... params); }
package org.monday.service.impl; import java.io.Serializable; import java.util.List; import javax.annotation.Resource; import org.monday.dao.BaseDao; import org.monday.service.BaseService; import org.springframework.transaction.annotation.Transactional; /** * BaseServiceImpl 定义Service的通用操作的实现 * * @author Monday */ @Transactional public class BaseServiceImpl<T> implements BaseService<T> { /** * 注入BaseDao */ private BaseDao<T> dao; @Resource public void setDao(BaseDao<T> dao) { this.dao = dao; } public void save(T entity) { dao.save(entity); } public void update(T entity) { dao.update(entity); } public void delete(Serializable id) { dao.delete(id); } public T getById(Serializable id) { return dao.findById(id); } public List<T> getByHQL(String hql, Object... params) { return dao.findByHQL(hql, params); } }
package org.monday.service; import org.monday.domain.Customer; /** * 客户Service继承BaseService * * @author Monday */ public interface CustomerService extends BaseService<Customer> { /** * 若BaseService 没有定义的方法,可以在这里添加 */ }
package org.monday.service.impl; import javax.annotation.Resource; import org.monday.dao.BaseDao; import org.monday.domain.Customer; import org.monday.service.CustomerService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * 客户Service的实现类 继承BaseServiceImpl 显示客户Service接口 * * @author Monday */ @Service("customerService") @Transactional public class CustomerServiceImpl extends BaseServiceImpl<Customer> implements CustomerService { /** * 注入DAO */ @Resource(name = "customerDao") public void setDao(BaseDao<Customer> dao) { super.setDao(dao); } /** * 若CustomerService 定义了BaseService没有的方法,则可以在这里实现 */ }
package org.monday.service; import org.monday.domain.Order; /** * 订单Service继承BaseService * * @author Monday */ public interface OrderService extends BaseService<Order> { /** * 若BaseService 没有定义的方法,可以在这里添加 */ }
package org.monday.service.impl; import javax.annotation.Resource; import org.monday.dao.BaseDao; import org.monday.domain.Order; import org.monday.service.OrderService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * 订单Service的实现类 继承BaseServiceImpl 显示订单Service接口 * * @author Monday */ @Service(value = "orderService") @Transactional public class OrderServiceImpl extends BaseServiceImpl<Order> implements OrderService { /** * 注入DAO */ @Resource(name = "orderDao") public void setDao(BaseDao<Order> dao) { super.setDao(dao); } /** * 若CustomerService 定义了BaseService没有的方法,则可以在这里实现 */ }
这里只是提供了一个思路。可能代码还有不严谨的地方,欢迎补充指正。
容易出现的两个异常:
1.org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
答案:要加@Transactional注解
除了要在这里加注解
@Service("customerService")
@Transactional
public class CustomerServiceImpl extends BaseServiceImpl<Customer> implements CustomerService {}
这里也要加
@Transactional
public class BaseServiceImpl<T> implements BaseService<T> {}
2.org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerService':
Injection of resource fields failed;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [org.monday.dao.BaseDao] is defined:
expected single matching bean but found 2: [customerDao, orderDao]
答案:
(参考)
注入具体的DAO
@Resource(name="customerDao")
public void setDao(BaseDao<Customer> dao) {
super.setDao(dao);
}
PS:画个图好了。
@Transactional
public class OrderServiceImpl extends BaseServiceImpl<Order> implements OrderService {
/**
* 注入DAO
*/
@Resource(name = "orderDao")
public void setDao(BaseDao<Order> dao) {
super.setDao(dao);
}
/**
* 若CustomerService 定义了BaseService没有的方法,则可以在这里实现
*/
如果在这里注入了多个DAO会出错,它总是记录着最后一个被注入的DAO .
求解决 ?