Spring MVC:通用DAO和服务类

时间:2014-10-09 21:40:55

标签: java spring generics dao genericdao

我正在使用Spring MVC编写Web。我使用Generic DAO编写了所有DAO。现在我想重写我的服务类。我怎样才能写出#34;通用服务"?

有我的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方法。我理解为什么。但是我怎么能重写呢?

5 个答案:

答案 0 :(得分:1)

问题是你在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类型及其特定方法注入完整的spring bean。

您可以看看我们在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而不是服务,但它类似)

希望它会有所帮助。

(对不起,如果有一些错别字,我现在不能仔细检查)

而且,顺便说一句,您应该考虑使用Spring Data而不是使用GenericDaos,但您仍然会对服务有相同的需求。

答案 1 :(得分:1)

我仍然不知道为什么人们实际上使用古老的DAO /服务模型与Spring Data;完全没必要,容易出错等等。

Spring Data JPA为这些东西提供了一些极其有用的接口:JpaRepositoryJpaSpecificationExecutor - 这些封装了你想要的一切,你只需要你的标准实体就可以了 - 其他一切都将由春天来处理,您只需输入您的标准并获得您想要的内容,而无需重新发明轮子。 可能是你没有真正阅读文档?它非常有用:

官方介绍: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());

很容易。

答案 2 :(得分:0)

我认为这只是java OO设计的局限性。您需要一种参数化方法来传递谓词以进行搜索,例如:

List<T> findByPredicate(List<Predicate> predicates, Class<T> returnType);

谓词类是这样的

class Predicate {
   String columnName;
   Operator operator;
   String value;
}

因此,你可以表达“name ='John'”,age&gt; = 21等

这不是一个理想的解决方案,代码变得不那么易读,您需要将谓词转换为数据库查询,并且很少需要进行类型转换,这很容易出现运行时错误。

您可以避免像Spring Data这样的库重新发明轮子。您甚至不需要通用DAO,只需要提供类似

的接口方法
List<Person> findByName(String name);

并在应用程序引导程序中自动生成一个实现。请查看Spring Data JPA以获取更多信息。

答案 3 :(得分:0)

试试这个:

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);
    }

}

答案 4 :(得分:0)

//实施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
}