Spring MVC:通用DAO和服务类

mar*_*tin 7 java generics spring dao genericdao

我正在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 ################################ */
Run Code Online (Sandbox Code Playgroud)

和服务:

/* ################################# 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 ################################ */
Run Code Online (Sandbox Code Playgroud)

编译器(和Eclipse)没有看到findByNamefindByCode方法.我理解为什么.但是我怎么能重写呢?

ger*_*tan 0

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

List<T> findByPredicate(List<Predicate> predicates, Class<T> returnType);
Run Code Online (Sandbox Code Playgroud)

谓词类是这样的

class Predicate {
   String columnName;
   Operator operator;
   String value;
}
Run Code Online (Sandbox Code Playgroud)

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

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

您可以避免使用 Spring Data 这样的库重新发明轮子。你甚至不需要通用的 DAO,你只需要提供一个接口方法,比如

List<Person> findByName(String name);
Run Code Online (Sandbox Code Playgroud)

并且将在应用程序引导时自动生成一个实现。查看 Spring Data JPA 了解更多信息。