Бесплатный курс по Java: от основ до продвинутого уровня
Hibernate CRUD приложение с сервисным уровнем
В прошлом уроке мы построили Crud приложение, но это был не совсем правильный способ его построения. В этом уроке мы немного модернизируем наше CRUD приложение.
В прошлом уроке у нас было всего два уровня в нашем приложении, это:
Уровень контроллера, который принимает запросы пользователя и в котором должна была находиться вся какая-либо бизнес логика нашего приложения
и ДАО уровень, который исключительно для прямого взаимодействия с БД.
Но правильно чтобы бил еще один уровень – сервисный.
Давайте создадим папку service и создадим в ней сервисный класс.
Далее подробнее зачем он нужен.
В сервис классе внедряются все ДАО, которые есть в приложении. Таким образом объект сервиса объединяет все ДАО объекты и в контроллере можно будет работать с ДАО объектами через единственный объект сервиса.
Также важный момент, что вся бизнес логика приложения больше не будет находиться на уровне контроллера, как в прошлой версии приложения, она теперь будет располагаться на уровне сервиса.
Тогда получается, что:
контроллер только получает и отправляет запросы,
вся бизнес-логика приложения в сервисе,
а в ДАО только чисто код для работы с БД.
То есть, как видим, обеспечиваться дополнительная модульность этой прослойкой.
Также еще очень полезный момент, что обеспечивается слабая связность между дао уровнем и уровнем контроллера.
Помним, что согласно DAO паттерну Dao классы нужны только для сокрытия низкоуровневого взаимодействия с ресурсом, в них не должно быть какой-либо сложной бизнес логики, поэтому если мы внедрим все DAO классы в контроллере и будем использовать их методы в сочетании с бизнес логикой без уровня сервиса, то это может вызвать ряд проблем.
Представим, что в контроллере много где вызывается какой-то метод ДАО класса, например, выборки из таблицы, и мы, например, захотим заменить этот метод на другой метод выборки из другой таблицы, тогда придется везде в контроллере его менять вручную. Здесь как раз и пригодиться сервис метод в котором код можно менять как нам вздумается в отличии от ДАО метода, где происходит только прямое взаимодействие с какой-либо конкретной таблицей БД.
Теперь пусть на месте ДАО метода, который мы хотим заменить в контроллере будет метод сервис класса и в этом сервис методе пусть вызывается ДАО метод. В этом сервис методе мы можем менять ДАО метод на любой какой нам вздумается. И в этом вся суть, что поменяв единожды ДАО метод в сервис методе он автоматически поменяется везде в контроллере и менять всё вручную в контроллере нам не придется, только ДАО метод в сервис методе.
Это и есть слабая связность между ДАО и контроллером.
Также очевидно, что если мы пишем всю бизнес логику в одном контроллере и если нам придется повторить эту логику в другом контроллере придется копировать ее полностью в него.
Вместо этого лучше написать отдельный метод в сервисе, который будет содержать эту бизнес логику и будет доступен всем контроллерам.
Для начала, создаем интерфейс на основе которого будет создаваться сервис класс:
package com.MavenWebAps.hibernateCRUDap.service;
import java.util.List;
import com.MavenWebAps.hibernateCRUDap.entity.Actor;
public interface ServiceInterface {
public Actor getActor(int actorId);
public void setActor(Actor actor);
public List getListOfActors();
public void deleteActor(int actorid);
}
Давайте же создадим этот сервис класс.
package com.MavenWebApps.hibernateCRUDap.service;
import java.util.List;
//Также как и @Controller и @Repositiry аннотация
//@Service наследуется от @Component поэтому
//спринг анализирует этот класс как особый бин.
@Service
//Объект (бин) этого класса-сервиса будет внедрен
//в контроллере и через этот объект будем работать
//с ДАО объектами.
public class ServiceInterfaceImpl implements ServiceInterface {
//внедряеться ДАО класса Актера.
@Autowired
private ActorDAO actorDAO;
//На уровне ДАО убираем @Transactional
//на уровне сервиса добавляем @Transactional.
@Transactional
//Метод для выборки актера из базы.
public Actor getActor(int actorId) {
//Здесь просто вызываем соответствующий
//метод ДАО объекта.
return actorDAO.getActor(actorId);
}
@Transactional
//Метод для вставки актера в базу.
public void setActor(Actor actor) {
//Пример слабой связности о которой
//говорилось ранее: допустим
//в контроллере много где вызываеться
//метод setActor этого сервис класса.
//Если мы поменяем дао метод setActor
//в этом методе на другой дао метод
//то он автоматически меняеться везде
//в контроллере где вызываеться setActor
//сервис класса и в контроллере в каждом
//месте использования метода setActor
//сервис класса ничего менять не нужно
//как если бы там вызывался
//setActor ДАО класса.
actorDAO.setActor(actor);
}
//Дальше также в сервисных методах вызываються
//соответствующие методы ДАО класса. Как видим
//здесь простой случай, поскольку приложение
//у нас простое и из-за этого особой бизнес
//логики у нас нет, потому просто вызываем
//Дао методы в сервис методах.
@Transactional
public List getListOfActors() {
return actorDAO.getListOfActors();
}
@Transactional
public void deleteActor(int actorid) {
actorDAO.deleteActor(actorid);
}
}
Поправим контроллер. Уберем из него все ДАО методы и вместо них пусть будут сервис методы.
package com.MavenWebAps.hibernateCRUDap.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.MavenWebAps.hibernateCRUDap.entity.Actor;
import com.MavenWebAps.hibernateCRUDap.service.ServiceInterface;
import org.springframework.ui.Model;
@Controller
@RequestMapping(“/actor”)
public class CRUDController {
//Теперь вместо DAO объекта внедряем сервис
//объект (бин) уже через методы которого
//будет происходить работа с DAO объектом
//для взаимодействия с БД.
@Autowired
private ServiceInterface sertviceObj;
@RequestMapping(“/getListOfActors”)
public String getListOfActors(Model model) {
model.addAttribute(“listofactors”,
//теперь используем sertviceObj
sertviceObj.getListOfActors());
return “ListOfActorsJSP”;
}
@RequestMapping(“/showFormForUpdating”)
public String updateActorsFor(
@RequestParam(“actorId”) int actorid,
Model model) {
model.addAttribute(“someactor”,
//теперь используем sertviceObj
sertviceObj.getActor(actorid));;
return “ActorJSPUpdateForm”;
}
@RequestMapping(“/showFormForSetting”)
public String setActor(Model model) {
model.addAttribute(“someactor”,
new Actor());
return “ActorJSPNewActorForm”;
}
@RequestMapping(“/setActor”)
public String setActor(@ModelAttribute(“someactor”) Actor actor, Model model){
//теперь используем sertviceObj
sertviceObj.setActor(actor);;
return “redirect:/actor/getListOfActors”;
}
@RequestMapping(“/deleteActor”)
public String deleteActor(
@RequestParam(“actorId”) int actorid,
Model model) {
//теперь используем sertviceObj
sertviceObj.deleteActor(actorid);;
return “redirect:/actor/getListOfActors”;
}
}
Также не забываем убрать Transactional в ДАО классе. Эти аннотации теперь в сервис классе.
package com.MavenWebAps.hibernateCRUDap.dao;
import java.util.List;
import javax.transaction.Transactional;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.MavenWebAps.hibernateCRUDap.entity.Actor;
@Repository
public class ActorDAOImpl implements ActorDAO {
@Autowired
private SessionFactory sessionFactory;
//@Transactional
public Actor getActor(int actorId) {
Session session = sessionFactory.getCurrentSession();
return session.get(Actor.class, actorId);
}
//@Transactional
public void setActor(Actor actor) {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(actor);
}
//@Transactional
public List getListOfActors() {
Session session = sessionFactory.getCurrentSession();
return session.createQuery(“from Actor”, Actor.class).getResultList();
}
//@Transactional
public void deleteActor(int actorid) {
Session session = sessionFactory.getCurrentSession();
session.createQuery(
“delete from Actor where id=:actorid”)
.setParameter(“actorid”, actorid).executeUpdate();
}
}
Давайте же перейдем на главную страницу со списком актеров. Как мы помним, на эту страницу можно перейти через обработчик getListOfActors. Сделаем это:
Как видим, страница успешно открылась. Работает здесь всё аналогично предыдущему уроку, только теперь с сервисным уровнем.
Создайте Spring REST API с нуля: настройте контроллеры, конвертацию JSON в объекты и обратно с Jackson. Примеры GET-запросов и тестирование через Rest Client.