我正在使用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)没有看到findByName
和findByCode
方法。我理解为什么。但是我怎么能重写呢?
答案 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为这些东西提供了一些极其有用的接口:JpaRepository和JpaSpecificationExecutor - 这些封装了你想要的一切,你只需要你的标准实体就可以了 - 其他一切都将由春天来处理,您只需输入您的标准并获得您想要的内容,而无需重新发明轮子。 可能是你没有真正阅读文档?它非常有用:
官方介绍: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
}