Spring MVC: DAO and Service Common Classes

I am writing a website in Spring MVC. I wrote all the DAOs using the Generic DAO. Now I would like to rewrite my classes of service. How to write "Generic Service"?

There are my DAOs:

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

and services:

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

The compiler (and Eclipse) does not see the findByName and findByCode . I understand why. But how can I rewrite it?

+6
source share
5 answers

The problem is that you directly enter your GenericDao into your GenericManager, but none of them is a specific Spring bean, and you can never use your specific CountryDao.

You should not auto-detect GenericDao, but only define it and provide a 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; } ... 

}

Then you will need to introduce a specific Spring bean into your specific services. i.e. in 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; } ... } 

You will have a full Spring bean that will be introduced by your specific CountryDao type and its specific methods.

You can see what we did in the RESThub project regarding shared services: https://github.com/resthub/resthub-spring-stack/blob/master/resthub-common/src/main/java/org/resthub/common /service/CrudServiceImpl.java and some specific example: https://github.com/resthub/todo-backbone-example/blob/master/src/main/java/todo/TodoController.java (with a controller instead of a service, but it similar)

Hope this helps.

(and sorry if there are any typos, I can't double check right now)

and, BTW, you should use Spring Data instead of using GenericDaos, but you will still have the same needs for your Services.

+1
source

I still don't know why people actually use archaic DAO / service models with Spring Data; completely unnecessary, error prone and much more.

Spring JPA data has several extremely useful interfaces for this material: JpaRepository and JpaSpecificationExecutor - they encapsulate EVERYTHING you need, you only need your standard entities, and thatโ€™s it - everything else will be processed by spring, you just enter your criteria and get exactly that what you want without reinventing the wheel. Maybe you really have not read the documentation? Its very useful:

official introduction: 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/

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

examples from the genius himself: https://github.com/spring-projects/spring-data-jpa-examples/tree/master/spring-data-jpa-example

class examples:

 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 } 

and now you can just Autowire your repository:

 @Autowired CustomerRepository customerRepo; 

and get the data as follows:

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

it's easy.

+1
source

I think this is just a limitation of Java-OO design. You need a parameterized way to pass predicates for the search, for example:

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

If the predicate class is something like this

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

Therefore, you can express "name =" John ", age> = 21, etc.

This is not an ideal solution, the code becomes less understandable for humans, you will need to convert predicates to database queries, and you need to execute a small number of types that are prone to runtime errors.

You can avoid wheel reuse with a library such as Spring Data. You donโ€™t even need a common DAO, you just need to provide an interface method, for example

 List<Person> findByName(String name); 

and the implementation will be automatically generated when the application loads. Take a look at Spring Data JPA for more.

0
source

Try the following:

 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
source

// Implement GenericDao and 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 } 
0
source

Source: https://habr.com/ru/post/976528/


All Articles