Hibernate и Spring - Dao, Услуги
Я читал несколько уроков, и я видел, что большинство реализаций MVC
основаны на:
1) интерфейс dao, например "IUserDao"
2) dao impl этого интерфейса - "mySimpleUserDaoImpl"
3) служебный интерфейс для обеспечения устойчивости: "IUserService"
4) и impl - "UserServiceImpl"
Это лучшая практика? я имею в виду причину, по которой я задаю этот вопрос, потому что кажется избыточным иметь 30 сервисов с методами getXById(), deleteX (x), createX (x), которые делают более или менее одинаковыми.
Пожалуйста, учтите, что я использую spring 3 и hibernate 4, и я решил, что задаю этот вопрос, прежде чем я начну хлопать своей клавиатурой с кодом
спасибо.
Ответы
Ответ 1
Если вы только начинаете разработку, загляните в Spring JPA. Служба должна быть Хранилищем "один-ко-многим" (DAO). Но я бы также не создал весь этот шаблонный код вручную. Spring JPA устраняет основные функции CRUD и поиска, а также разбиение на страницы.
Вот видео, которое просматривает всю конфигурацию для Spring, JPA, Hibernate и заканчивается Spring Data JPA показывает вам весь код шаблона, который исключается.
Чтобы использовать Spring Data JPA, ваш интерфейс репозитория заканчивается:
package com.mysampleapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.wcfgroup.model.Employee;
@Repository("employeeRepository")
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
Employee findBySsn(String ssn);
}
И затем конфигурация XML для использования Spring Data JPA:
<jpa:repositories base-package="com.mysampleapp.repository"/>
Теперь все коды шаблонов обрабатываются для вас. Вам больше не нужно создавать базовый класс репозитория с методами поиска и базовыми функциями CRUD. Интерфейс JpaRepository
предлагает множество приятных функций, и вы ничего не делаете для реализации.
Ответ 2
Для каждой модели необходимо иметь dao, daoImpl, service, serviceImpl.
- UserDao
- UserDaoImpl
- UserService
- UserServiceImpl
Вы можете использовать общий класс EntityDaoImpl и inteface EntityDao, например:
EntityDao:
public interface EntityDao<E> {
void persist(E e) throws Exception;
void remove(Object id) throws Exception;
E findById(Object id) throws Exception;
}
EntityDaoImpl:
public class EntityDaoImpl<E> implements EntityDao<E> {
@PersistenceContext(unitName="UnitPersistenceName")
protected EntityManager entityManager;
protected E instance;
private Class<E> entityClass;
@Transactional
public void persist(E e) throws HibernateException{
getEntityManager().persist(e);
}
@Transactional
public void remove(Object id) throws Exception{
getEntityManager().remove((E)getEntityManager().find(getEntityClass(), id));
}
public E findById(Object id) throws Exception {
return (E)getEntityManager().find(getEntityClass(), id);
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) throws Exception{
this.entityManager = entityManager;
}
public Class<E> getEntityClass() throws Exception{
if (entityClass == null) {
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType)
{
ParameterizedType paramType = (ParameterizedType) type;
if (paramType.getActualTypeArguments().length == 2) {
if (paramType.getActualTypeArguments()[1] instanceof TypeVariable) {
throw new IllegalArgumentException(
"Can't find class using reflection");
}
else {
entityClass = (Class<E>) paramType.getActualTypeArguments()[1];
}
} else {
entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
}
} else {
throw new Exception("Can't find class using reflection");
}
}
return entityClass;
}
}
И вы можете использовать вот так:
public interface UserDao extends EntityDao<User> {
}
и
public class UserDaoImpl extends EntityDaoImpl<User> implements UserDao{
}
Ответ 3
Нет необходимости иметь 30 уровней обслуживания или 30 уровней dao. Вы должны указать слои, не считая Entity wise, но функциональность бизнеса wise.there может быть 5 или 6 объектов, релевантных для определенной функции, и они должны быть в один уровень. Но все же вы должны будете иметь getXById(), deleteX (x), createX (x) в этих избыточных слоях, если они необходимы.
Ответ 4
Создание отдельного сервиса для каждой модели - это один из способов сделать это, и я видел приложения реального мира, которые это делают, но я не рекомендую его. Это избыток для простого случая CRUD и бесполезен для более сложных случаев (когда вы действительно хотите, чтобы транзакция охватывала несколько вызовов DAO). Это оставляет вам много кода, который мало что может сделать. DAO можно указать с помощью Spring Data, сервисы будут шаблонами с каждым методом, который завершает вызов DAO. Spring должен помочь уменьшить шаблон, в отличие от его мандата.
Если у вас есть полностью CRUD-приложение, то вы можете законно обойтись без служб, поместить @Transactional в DAO и вызвать DAO из контроллера. Если сервис не тянет его вес, избавитесь от него.
Если у вас есть реальная бизнес-логика в приложении, тогда, когда пользователь вызывает что-то, что может включать вызовы для разных DAO, эти вызовы обычно должны выполняться в рамках одной и той же транзакции, чтобы, если одна вещь не удалась, все возвращается. (Также создание транзакции относительно дорогое, и если у вас есть контроллер, делающий вызовы для разных сервисов для разных объектов, то это будет медленным.) То есть, когда услуги пригождаются, служба указывает низкоуровневые варианты использования, которые пользователь хочет выполнять и разрешать транзакционное поведение.
В случае с CRUD я бы предпочел использовать такой инструмент, как Grails или Play или Rails, или что-то другое для написания Java с Spring MVC. Например, Grails будет генерировать представления и контроллеры для вас, предоставлять базовый доступ к данным через GORM (поэтому нет DAO для записи), и это позволит вам легко указывать службы для тех случаев, когда вы считаете, что они вам нужны.