[英]Spring MVC: Generic DAO and Service classes
我正在Spring MVC中編寫Web。 我使用Generic DAO編寫了所有DAO。 現在我想重寫我的服務類。 我怎么寫“通用服務”?
有我的DAO:
/* ################################# DAO ################################ */
package net.example.com.dao;
import java.util.List;
public interface GenericDao<T> {
public T findById(int id);
public List<T> findAll();
public void update(T entity);
public void save(T entity);
public void delete(T entity);
}
/* ------------------------------------------------------ */
package net.example.com.dao;
import java.io.Serializable;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
@Scope("prototype")
public abstract class GenericHibernateDaoImpl<T extends Serializable> implements GenericDao<T> {
private Class<T> clazz;
@Autowired
private SessionFactory sessionFactory;
public final void setClazz(Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
@SuppressWarnings("unchecked")
public T findById(int id) {
return (T) getCurrentSession().get(clazz, id);
}
@SuppressWarnings("unchecked")
public List<T> findAll() {
return getCurrentSession().createQuery("FROM " + clazz.getName()).list();
}
public void update(T entity) {
getCurrentSession().update(entity);
}
public void save(T entity) {
getCurrentSession().save(entity);
}
public void delete(T entity) {
getCurrentSession().delete(entity);
}
protected final Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
/* ------------------------------------------------------ */
package net.example.com.dao;
import net.example.com.entity.Country;
public interface CountryDao extends GenericDao<Country> {
public Country findByName(String name);
public Country findByCode(String code);
}
/* ------------------------------------------------------ */
package net.example.com.dao;
import org.springframework.stereotype.Repository;
import net.example.com.entity.Country;
@Repository
public class CountryDaoImpl extends GenericHibernateDaoImpl<Country> implements CountryDao {
@Override
public Country findByName(String name) {
return (Country) getCurrentSession()
.createQuery("FROM Country WHERE name = :name")
.setString("name", name).uniqueResult();
}
@Override
public Country findByCode(String code) {
return (Country) getCurrentSession()
.createQuery("FROM Country WHERE code = :code")
.setString("code", code).uniqueResult();
}
}
/* ################################# DAO ################################ */
和服務:
/* ################################# SERVICE ################################ */
package net.example.com.service;
import java.util.List;
public interface GenericManager<T> { // GenericManager<T> is the same as GenericDao<T>
public T findById(int id);
public List<T> findAll();
public void update(T entity);
public void save(T entity);
public void delete(T entity);
}
/* ------------------------------------------------------ */
package net.example.com.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.example.com.dao.GenericDao;
@Service
public abstract class GenericManagerImpl<T> implements GenericManager<T> {
@Autowired
protected GenericDao<T> dao;
@Override
public T findById(int id) {
return dao.findById(id);
}
@Override
public List<T> findAll() {
return dao.findAll();
}
@Override
public void update(T entity) {
dao.update(entity);
}
@Override
public void save(T entity) {
dao.save(entity);
}
@Override
public void delete(T entity) {
dao.delete(entity);
}
}
/* ------------------------------------------------------ */
package net.example.com.dao;
import net.example.com.entity.Country;
public interface CountryManager extends GenericDao<Country> { // CountryManager is the same as CountryDao
public Country findByName(String name);
public Country findByCode(String code);
}
/* ------------------------------------------------------ */
package net.example.com.service;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.example.com.dao.CountryDao;
import net.example.com.entity.Country;
@Service
@Transactional
public class CountryManagerImpl extends GenericManagerImpl<Country> implements CountryManager {
@Override
public List<Country> findAll() {
return dao.findAll();
}
public Country findById(int id) {
return dao.findById(id);
}
@Override
public Country findByName(String name) {
return dao.findByName(name); // compiler (and Eclipse) do not see findByName !!!!!!!!!
}
@Override
public Country findByCode(String code) {
return dao.findByCode(code); // compiler (and Eclipse) do not see findByCode !!!!!!!!!
}
@Override
public void save(Country country) {
dao.save(country);
}
@Override
public void delete(Country country) {
dao.delete(country);
}
@Override
public void update(Country country) {
dao.update(country);
}
}
/* ------------------------------------------------------ */
/* ################################# SERVICE ################################ */
編譯器(和Eclipse)沒有看到findByName
和findByCode
方法。 我理解為什么。 但是我怎么能重寫呢?
問題是你在GenericManager中直接注入你的GenericDao但是它們都不是一個具體的Spring bean,你永遠無法使用你的特定CountryDao。
你不能自動裝配GenericDao但只能定義它並提供setter:
// Add DAO as a genric parameter
public abstract class GenericManagerImpl<T, D extends GenericDao<T>> implements GenericManager<T> {
private D dao;
protected void setDao (D dao) {
this.dao = dao;
}
...
}
然后,您將必須在您的具體服務中注入一個混凝土彈簧豆。 即在CountryManagerImpl中 :
// Instantiate your concrete service with your concrete DAO
public class CountryManagerImpl extends GenericManagerImpl<Country, CountryDao> implements CountryManager {
// Do not redeclare your dao here in order to keep the inherited one
// Don't forget to inject
@Inject("countryDao")
@Override
protected void setDao (CountryDao dao) {
this.dao = dao;
}
...
}
然后,您將獲得一個完整的春豆注入您的具體CountryDao類型及其特定方法。
您可以看看我們在RESThub項目中對通用服務所做的工作: https : //github.com/resthub/resthub-spring-stack/blob/master/resthub-common/src/main/java/org/resthub/ common / service / CrudServiceImpl.java和一些具體的例子: https : //github.com/resthub/todo-backbone-example/blob/master/src/main/java/todo/TodoController.java (使用Controller而不是a服務但是很相似)
希望它會有所幫助。
(對不起,如果有一些錯別字,我現在不能再仔細檢查)
而且,順便說一句,您應該考慮使用Spring Data而不是使用GenericDaos,但您仍然會對服務有相同的需求。
我仍然不知道為什么人們實際使用古老的DAO /服務模型與Spring Data; 完全不必要,容易出錯等等。
Spring Data JPA有一些非常有用的接口: JpaRepository和JpaSpecificationExecutor - 這些封裝了你想要的一切,你只需要你的標准實體就可以了 - 其他一切都將由spring處理,你只需輸入你的標准並得到什么你想要,而不是重新發明輪子。 可能是你沒有真正閱讀文檔? 它非常有用:
官方介紹: http : //spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
doc: http : //docs.spring.io/spring-data/jpa/docs/1.7.0.RELEASE/reference/html/
小說: http : //www.cubrid.org/wiki_ngrinder/entry/how-to-create-dynamic-queries-in-springdata
來自天才的例子: https : //github.com/spring-projects/spring-data-jpa-examples/tree/master/spring-data-jpa-example
示例類:
public CustomerSpecifications {
public static Specification<Customer> customerHasBirthday() {
return new Specification<Customer> {
public Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb) {
return cb.equal(root.get(Customer_.birthday), today);
}
};
}
public static Specification<Customer> isLongTermCustomer() {
return new Specification<Customer> {
public Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb) {
return cb.lessThan(root.get(Customer_.createdAt), new LocalDate.minusYears(2));
}
};
}
}
public interface CustomerRepository extends JpaRepository<Customer>, JpaSpecificationExecutor {
// Your query methods here
}
現在您可以簡單地自動裝配您的存儲庫:
@Autowired
CustomerRepository customerRepo;
並檢索這樣的數據:
List<Customer> customersWithBirthDay = customerRepo.findAll(CustomerSpecifications.customerHasBirthDay());
這很容易。
我認為這只是java OO設計的局限性。 您需要一種參數化方法來傳遞謂詞以進行搜索,例如:
List<T> findByPredicate(List<Predicate> predicates, Class<T> returnType);
謂詞類是這樣的
class Predicate {
String columnName;
Operator operator;
String value;
}
因此,您可以表達“name ='John'”,年齡> = 21等
這不是一個理想的解決方案,代碼變得不那么人類可讀,您需要將謂詞轉換為數據庫查詢,並且很少需要進行類型轉換,這容易產生運行時錯誤。
您可以避免像Spring Data這樣的庫重新發明輪子。 你甚至不需要通用的DAO,你只需要提供類似的接口方法
List<Person> findByName(String name);
並在應用程序引導程序中自動生成一個實現。 查看Spring Data JPA了解更多信息。
嘗試這個:
public interface GenericDao<T> {
public List<T> loadAll() throws Exception;
public Long saveOrUpdate(T domain) throws Exception;
public void saveOrUpdate(List domainList) throws Exception;
public void delete(T domain) throws Exception;
public T get(Serializable id) throws Exception;
public List<T> getListByCriteria(DetachedCriteria detachedCriteria);
public List<T> getListByCriteria(DetachedCriteria detachedCriteria,
int offset, int size);
public List<T> filterListWithCondition(T domain) throws Exception;
}
public class GenericDaoImpl<T> extends HibernateDaoSupport implements GenericDao<T> {
@Autowired
SessionFactory sessionFactory;
private Class<T> entityClass;
private MySQLIntegrityConstraintViolationException sqlException = new MySQLIntegrityConstraintViolationException("Duplicate Record inserted");
@Autowired
public void setSession(SessionFactory sessionFactory){
this.setSessionFactory(sessionFactory);
}
public GenericDaoImpl() {
entityClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
public List<T> loadAll() throws Exception{
Session session = getHibernateTemplate().getSessionFactory().openSession();
List<T> list = session.createQuery("from "+entityClass.getName()).list();
session.close();
return list;
}
public void delete(T domain) throws Exception {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.delete(domain);
tx.commit();
session.close();
}
public Long saveOrUpdate(T domain) throws Exception {
try {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.saveOrUpdate(domain);
tx.commit();
Serializable ids = session.getIdentifier(domain);
session.close();
return (Long)ids;
} catch (ConstraintViolationException e) {
throw new ConstraintViolationException("Duplicate Record inserted", sqlException, "");
}
}
public void saveOrUpdate(List domainList) throws Exception {
try {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Object dom = null;
for(int i =0; i<domainList.size(); i++) {
dom = domainList.get(i);
session.saveOrUpdate(dom);
if ( i % 10 == 0 ) {
//10, same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
} catch (ConstraintViolationException e) {
throw new ConstraintViolationException("Duplicate Record inserted", sqlException, "");
}
}
public T get(Serializable id) throws Exception{
Session session = getHibernateTemplate().getSessionFactory().openSession();
T o = (T) session.get(entityClass, id);
return (T)o;
}
public List<T> getListByCriteria(DetachedCriteria detachedCriteria,
int offset, int size) {
return (List<T>) getHibernateTemplate().findByCriteria(detachedCriteria, offset, size);
}
public List<T> getListByCriteria(DetachedCriteria detachedCriteria) {
return (List<T>) getHibernateTemplate().findByCriteria(detachedCriteria);
}
public List<T> filterListWithCondition(T domain) throws Exception {
return (List<T>) getHibernateTemplate().findByExample(domain);
}
}
public interface GenericService<T> {
public List<T> loadAll() throws Exception;
public Long saveOrUpdate(T domain) throws Exception;
public void saveOrUpdate(List domainList) throws Exception;
public void delete(T domain) throws Exception;
public T get(Serializable id) throws Exception;
public List<T> getListByCriteria(DetachedCriteria detachedCriteria);
public List<T> getListByCriteria(DetachedCriteria detachedCriteria, int offset, int size);
public List<T> filterListWithCondition(T domain) throws Exception;
}
public class GenericServiceImpl<T, T2 extends GenericDao<T>> implements GenericService<T> {
@Autowired
private T2 genericDao;
@Override
public List<T> loadAll() throws Exception {
return genericDao.loadAll();
}
@Override
public Long saveOrUpdate(T domain) throws Exception{
return genericDao.saveOrUpdate(domain);
}
@Override
public void delete(T domain) throws Exception {
genericDao.delete(domain);
}
@Override
public T get(Serializable id) throws Exception {
return genericDao.get(id);
}
@Override
public List<T> getListByCriteria(DetachedCriteria detachedCriteria) {
return genericDao.getListByCriteria(detachedCriteria);
}
@Override
public List<T> getListByCriteria(DetachedCriteria detachedCriteria,
int offset, int size) {
return genericDao.getListByCriteria(detachedCriteria, offset, size);
}
@Override
public List<T> filterListWithCondition(T domain) throws Exception {
return genericDao.filterListWithCondition(domain);
}
@Override
public void saveOrUpdate(List domainList) throws Exception {
genericDao.saveOrUpdate(domainList);
}
}
//實現GenericDao和GenericService
// StateDaO
public interface StateDao extends GenericDao<State> {
}
// StateDaoImpl
@Repository("stateDao")
public class StateDaoImpl extends GenericDaoImpl<State> implements StateDao {
@Autowired
SessionFactory sessionFactory;
// another specific businness operation perform
}
// StateService
public interface StateService extends GenericService<State> {
}
// StateServiceImpl
@Repository("stateService")
public class StateServiceImpl extends GenericServiceImpl<State, StateDao> implements StateService {
@Resource
StateDao stateDao;
//using stateDao object of another specific operation
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.