簡體   English   中英

Spring MVC:通用DAO和服務類

[英]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)沒有看到findByNamefindByCode方法。 我理解為什么。 但是我怎么能重寫呢?

問題是你在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有一些非常有用的接口: JpaRepositoryJpaSpecificationExecutor - 這些封裝了你想要的一切,你只需要你的標准實體就可以了 - 其他一切都將由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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM