2014-10-09 16 views
6

Tôi đang viết web trong Spring MVC. Tôi đã viết tất cả các DAO sử dụng Generic DAO. Bây giờ tôi muốn viết lại các lớp Dịch vụ của mình. Làm thế nào tôi có thể viết "Dịch vụ chung"?Spring MVC: Các lớp chung DAO và dịch vụ

Có DAO tôi:

/* ################################# 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 ################################ */ 

và dịch vụ:

/* ################################# 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 ################################ */ 

Compiler (và Eclipse) không thấy findByNamefindByCode phương pháp. Tôi hiểu tại sao. Nhưng làm thế nào tôi có thể viết lại nó?

Trả lời

0

Tôi nghĩ đó chỉ là giới hạn của thiết kế OO java. Bạn cần một cách parametrized để vượt qua các vị từ để tìm kiếm, một cái gì đó như:

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

Trường hợp lớp ngữ là một cái gì đó như thế này

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

Do đó bạn có thể bày tỏ "name = 'John'", tuổi tác Đây không phải là một giải pháp lý tưởng, mã trở nên ít người có thể đọc được, bạn sẽ cần phải biến đổi các biến vị ngữ thành các truy vấn cơ sở dữ liệu và có rất ít việc truyền kiểu cần được thực hiện dễ bị lỗi thời gian chạy.

Bạn có thể tránh phát minh lại bánh xe bằng thư viện như Dữ liệu mùa xuân. Bạn thậm chí không cần một DAO chung, bạn chỉ cần cung cấp một phương thức giao diện như

List<Person> findByName(String name); 

và triển khai sẽ được tạo tự động tại trình khởi động ứng dụng. Hãy xem JPA Spring Data để biết thêm.

1

Vấn đề là tiêm trực tiếp GenericDao của bạn trong GenericManager nhưng không ai trong số đó là một Spring bean cụ thể và bạn sẽ không bao giờ có thể sử dụng CountryDao cụ thể của bạn.

Bạn không phải autowire GenericDao nhưng chỉ xác định nó và cung cấp 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; 
    } 

... 

}

Sau đó, bạn sẽ phải tiêm một bean mùa xuân bê tông trong các dịch vụ cụ thể của bạn. ví dụ: trong 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; 
    } 

... 

} 

Bạn sẽ có sau đó một đậu mùa xuân đầy đủ tiêm với loại CountryDao bê tông và phương pháp cụ thể của nó.

Bạn có thể có một cái nhìn vào những gì chúng tôi đã làm cho dự án RESThub về các dịch vụ chung: https://github.com/resthub/resthub-spring-stack/blob/master/resthub-common/src/main/java/org/resthub/common/service/CrudServiceImpl.java và một số ví dụ cụ thể: https://github.com/resthub/todo-backbone-example/blob/master/src/main/java/todo/TodoController.java (với một điều khiển thay vì một dịch vụ nhưng nó là tương tự)

Hy vọng nó sẽ giúp.

(và xin lỗi nếu có một số lỗi chính tả, tôi có thể kiểm tra không tăng gấp đôi ngay bây giờ)

và, BTW, bạn nên xem xét sử dụng dữ liệu mùa xuân thay vì sử dụng GenericDaos nhưng bạn vẫn sẽ có cùng một nhu cầu về dịch vụ của bạn.

+0

Bây giờ tôi có http://pastebin.com/rN1C0i3w và nó vẫn không hoạt động :-( – martin

+0

Vâng, tôi có thể nhìn thấy nhiều sai lầm (một số là của tôi :-)): DAO loại nên được thông qua như là một loại chung trong GenericManager của bạn (xem mã chỉnh sửa trong câu trả lời của tôi) và không quên chú thích @Inject. Tôi đã cập nhật câu trả lời của mình. – bmeurant

+0

Không chắc chắn không quên điều gì đó, bạn thực sự nên xem xét hai liên kết tôi dán trước đây ... – bmeurant

1

tôi vẫn không biết tại sao mọi người thực sự sử dụng DAO/dịch vụ cổ - mô hình với Dữ liệu mùa xuân; hoàn toàn không cần thiết, dễ bị lỗi và không có điều gì.

mùa xuân dữ liệu JPA có một số cực kỳ giao diện hữu ích cho những thứ mà: JpaRepositoryJpaSpecificationExecutor - những đóng gói tất cả mọi thứ bạn muốn, bạn chỉ cần thực thể và thats tiêu chuẩn của bạn nó - mọi thứ khác sẽ được xử lý bởi mùa xuân, bạn chỉ cần đầu vào tiêu chí của bạn và nhận được chính xác những gì bạn muốn, mà không cần phát minh lại bánh xe. Có thể nào bạn chưa thực sự đọc tài liệu? Nó rất hữu ích:

chính thức giới thiệu: 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/

howto nhỏ: http://www.cubrid.org/wiki_ngrinder/entry/how-to-create-dynamic-queries-in-springdata

ví dụ từ các thiên tài mình: https://github.com/spring-projects/spring-data-jpa-examples/tree/master/spring-data-jpa-example

lớp Ví dụ:

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 
} 

và bây giờ bạn chỉ có thể Autowire kho của bạn:

@Autowired 
CustomerRepository customerRepo; 

và lấy dữ liệu như thế này:

List<Customer> customersWithBirthDay = customerRepo.findAll(CustomerSpecifications.customerHasBirthDay()); 

dễ dàng của nó.

+0

Bạn đã thử điều này chống lại các chính sách liên kết phức tạp giữa các bảng? Tôi đã có trải nghiệm rất xấu với API đó. – John

+0

cũng bạn có thể chỉ là người duy nhất trên hành tinh này - API tiêu chuẩn JPA (vì đó là về cơ bản nó là gì; với hàm bao hàm không có chức năng xung quanh nó) rất được chứng minh, được chuẩn hóa và được tôn trọng. Nếu bạn có "kinh nghiệm xấu" với nó, bạn có thể đã phạm một số sai lầm. Rất khó để bắt đầu mô tả logic dữ liệu của bạn thông qua các tiêu chí nếu bạn quen với các câu lệnh SQL - nhưng nó cũng đáng để học nỗ lực. Và: Có, tôi đã "thử" nó "chống lại các chính sách nối phức tạp giữa các bảng", nó hoạt động tốt hơn các câu lệnh SQL được tối ưu hóa DBMS. – specializt

+0

+1 Tôi đồng ý với bản chất của vấn đề ở đây: các cách thức điển hình của DAO và các dịch vụ được sử dụng trong các ứng dụng Spring (Java EE) là không quan tâm đến bẩm sinh. Quá nhiều mã không cần thiết, vô nghĩa mà chỉ bị cản đường. Dữ liệu mùa xuân tốt hơn, mặc dù vẫn không phải là cách tiếp cận ưa thích của tôi, chỉ đơn giản là có một lớp đích chung (ví dụ: "AppDatabase") kết thúc tốt hơn API JPA chuẩn, giúp dễ sử dụng hơn (với các phương pháp như "lưu", "xóa", "tìm (jpql, args)", v.v.). –

0

Hãy thử này:

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

} 
+0

Chào mừng bạn đến với Stack Overflow! Vì đây là một khối mã khá dài, tôi nghĩ câu trả lời của bạn có thể được cải thiện nếu bạn nhận xét về chính xác những gì bạn đã thay đổi để khắc phục vấn đề của OP. – josliber

0

// Thực hiện GenericDao và 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 
} 
Các vấn đề liên quan