Собираем все вместе и создаем весеннее веб-приложение.

Вступление

Итак, мы подошли к концу этого урока. Теперь пришло время применить все, что мы узнали, и создать настоящее веб-приложение, реализующее операции CRUD.

Мы будем создавать систему отслеживания для заказов. Это простое приложение, чтобы получить четкое представление о :

  • Настройка веб-приложения с нуля
  • Структурирование вашего веб-приложения MVC
  • Рабочий процесс веб-приложения MVC
  • Реализация операций CRUD
  • Подключение к базе данных (мы используем Hibernate, но вы можете следовать Spring Data Access для использования JDBC).
  • Работа с данными HTML-форм и страницами просмотра (JSP)
  • … и многое другое.

Настройка среды 💪

Как обычно, вам нужно создать новый «Динамический веб-проект» и добавить все файлы jar в папку «WEB-INF / lib» или использовать Maven для определения всех зависимостей.

Зависимости, которые нам понадобятся:

  • Spring Framework
  • Hibernate, драйвер JDBC и C3PO (база данных)
  • Сервлет Java + JSP + JSTL

Если вы используете Maven, ваш «pom.xml» должен иметь следующее:

Когда вы закончите, создайте таблицу заказов и сгенерируйте фальшивые данные для тестирования.

Конфигурации

Диспетчерский сервлет (ы)

Создайте файл XML; «Web.xml» для определения и настройки диспетчерских сервлетов Spring MVC.

💡 Мы можем добавить страницу приветствия. Таким образом, всякий раз, когда мы вводим корневой URL-адрес, сервер будет искать файл приветственной страницы (если он определен) в корневом каталоге веб-приложения: «WebContent / index.jsp».

Диспетчерский сервлет Dispatcher

Конфигурация нашего диспетчера находится в файле «WEB-INF / spring-mvc-demo-servlet.xml».

Конфигурации базы данных

В этом приложении мы собираемся использовать Hibernate.

Вместо использования файла «hibernate.cfg.xml» конфигурации для подключения к базе данных могут быть определены как bean-компонент DataSource в файле конфигурации XML.

Hibernate использует пул соединений для подключения к базе данных. Мы используем стороннее программное обеспечение для пула подключений.

Помните, когда нам нужно было создать объект сеанса с помощью SessionFactory? - Теперь мы можем определить SessionFactory как bean-компонент в файле конфигурации XML, который имеет DataSource в качестве зависимости.

Помните, когда нам приходилось писать код для запуска и закрытия транзакции? - Этого можно избежать, определив bean-компонент для диспетчера транзакций (который имеет SessionFactory в качестве зависимости) и включив аннотацию @Transactional, если вы не хотите выполнять код транзакции (начало, конец, и т. д.) вручную.

Эта аннотация автоматически волшебным образом начинает и завершает транзакцию в вашем коде Hibernate (как мы увидим позже).

Структура

Есть много способов структурировать ваше приложение MVC и добавить слои для разделения операций и задач.

Один из наиболее распространенных способов - использовать слой DAO для выполнения операций с базой данных и отображения результата в объекты (сущности / DTO).

💡 DTO (объект передачи данных) - это простые объекты, которые переносят данные между процессами. DTO часто используются вместе с объектами доступа к данным для извлечения данных из базы данных.

Уровень обслуживания - это промежуточный уровень между контроллером и уровнем DAO. Он вызывает DAO и выполняет пользовательскую бизнес-логику. Например, он может интегрировать данные из разных ресурсов (например, репозиториев, DAO и т. Д.).

Упаковка

Итак, сначала давайте сгруппируем классы в группы связанных типов в пакеты, чтобы избежать конфликтов имен и контролировать доступ.

💡 « типы» относятся к классам, интерфейсам, перечислениям и типам аннотаций.

Создайте пакет «com.demo.mvc» в папке «src» и внутри этого пакета создайте:

  • Контроллеры: «com.demo.mvc.controllers».
  • DAO: «com.demo.mvc.dao».
  • Службы: «com.demo.mvc.services».
  • Объекты: «com.demo.mvc.entities».

💡 Классы контроллеров будут находиться в пакете com.demo.mvc.controllers и так далее.

Рабочий процесс

Рабочий процесс выглядит следующим образом:

  • Пользователь отправляет запрос из браузера.
  • Диспетчер получает запрос и пересылает его соответствующему методу контроллера.
  • Контроллер обращается к уровню обслуживания, чтобы завершить требуемую работу (например, запросить некоторые данные).
  • Уровень обслуживания общается с DAO для операций с базой данных и выполнения бизнес-операций.
  • Слой DAO выполняет операции с базой данных, используя отображение данных, возвращаемых с Entities / DTO приложения.
  • Теперь в контроллере мы можем создать объект модели и вернуть страницу просмотра для отображения, перенаправить на другую страницу или вернуть данные JSON и т. Д.

Сущности - Порядок

Заказ - это объект, который представляет заказы в таблице базы данных. Данные, возвращаемые из базы данных, будут сопоставлены с объектами заказа.

Не забудьте определить методы получения и установки для полей объекта класса.

💡 GenerationType.IDENTITY означает, что это поле будет автоматически увеличиваться, и ему автоматически будет назначен идентификатор всякий раз, когда мы сохраняем новый заказ.

💡 Классы с аннотацией @Entity в пакете com.demo.mvc.entities будут сканироваться для сопоставления и создания объекта сеанса.

DAO - OrderDAO и OrderDAOImpl

Интерфейс OrderDAO предоставляет набор операций (список, добавление, обновление, удаление), которые должны быть реализованы классом OrderDAOImpl.

Реализация кода для OrderDAOImpl будет объяснена позже в операциях списка, добавления, обновления и удаления. Но пока давайте посмотрим на его базовую структуру.

Аннотация @Repository наследуется от аннотации @Component (так же, как @Controller). Он используется для определения класса реализации DAO. Это позволяет автоматически сканировать эти классы (благодаря сканированию компонентов, определенному в конфигурации), и любое проверенное исключение, которое будет выдано, преобразуется в непроверенные исключения.

Классам, реализующим DAO, нужен объект Hibernate SessionFactory, который, в свою очередь, нуждается в DataSource в качестве зависимости (определяемой в конфигурации).

Сервис - OrderService и OrderServiceImpl

Интерфейс OrderService имеет набор методов, которые почти аналогичны методам в интерфейсе OrderDAO и будут реализованы классом OrderServiceImpl .

Реализация OrderServiceImpl в нашем примере довольно проста. Уровень сервиса должен взаимодействовать с уровнем DAO и запрашивать запрошенные данные.

Аннотация @Service наследуется от аннотации @Component (так же, как @Controller и @Repository). Он используется для идентификации классов обслуживания. Он будет автоматически просканирован и зарегистрирован как bean-компонент благодаря сканированию компонентов.

Аннотация @Transactional (настроенная и включенная в файле конфигурации XML) заботится обо всем коде транзакции, необходимом для взаимодействия с базой данных в Hibernate.

💡 Если все методы класса будут выполняться внутри транзакции, вы можете аннотировать весь класс аннотацией @Transactional.

📣 Может возникнуть вопрос: «Почему мы используем эту аннотацию на уровне сервиса вместо уровня DAO?

Потому что мы хотим, чтобы классы DAO выполнялись в рамках транзакции, определенной на уровне сервиса. Таким образом, служба запускает транзакцию, выполняет вызовы класса DAO и других ресурсов (при необходимости), а затем завершает транзакцию.

Контроллер - OrderController

💡 Аннотация @GetMapping - это ярлык для @RequestMapping(method = RequestMethod.GET). Та же идея применима к аннотации @PostMapping.

Осуществление операций - список

Первая операция - это список всех заказов. На уровне DAO мы выполним запрос и вернем результат.

На уровне обслуживания просто вызовите метод getOrders(), используя автоматическое подключение orderDAO (зависимость).

В контроллере также выполните вызов getOrders() метода уровня Service. Затем добавьте заказы в атрибут модели, который будет отображаться на странице просмотра.

💡 В конфигурациях мы определили, что все страницы представлений будут располагаться в папке «/ WEB-INF / view». Итак, создайте страницу list-orders.jsp внутри папки просмотра.

Страница просмотра просто перебирает сбор заказов с помощью тега forEach.

💡 Один из основных тегов JSTL (обсужденных ранее) - это тег итерации <c:forEach> , с помощью которого мы можем перебирать коллекцию элементов на наших страницах JSP.

Осуществление операций - Добавить

Следующая операция - добавить новый заказ. Это можно сделать, заполнив форму.

Итак, в основном нам нужно выполнить две операции. В первый раз будет отображаться пустая форма, а затем мы обрабатываем отправленные данные.

На уровне DAO мы добавим новую запись заказа в базу данных.

На уровне обслуживания просто вызовите метод saveOrder(), как и раньше.

В контроллере нам нужно сначала создать объект модели и передать новый пустой объект заказа (без конструктора аргументов).

Этот объект будет использоваться для привязки его к данным при отправке формы. Итак, мы можем получить этот объект после отправки формы и сохранить его в базе данных.

Для страницы просмотра нам нужно создать страницу с HTML-формой для создания нового заказа. Итак, создайте страницу «order-form.jsp» в папке view.

Поскольку отправленные данные являются строковыми. Итак, для дат нам нужно сопоставить отправленную строку и фактическое значение даты.

Решение: либо используйте аннотацию InitBinder, либо @DateTimeFormat. В случае использования аннотации:

- [1] Добавить @DateTimeFormat(pattern = "MM-dd-yyyy") в dateOfOrder в классе Order.

@Column(name="date_of_order")
@DateTimeFormat(pattern = "MM-dd-yyyy")
private Date dateOfOrder;

- [2] Измените поле ввода даты формы в «order-form.jsp» на:

<input type="text" path="dateOfOrder" name="dateOfOrder" value = "<fmt:formatDate value="${order.dateOfOrder}" pattern="MM-dd-yyyy" />"/>

- [3] Добавить ссылку на теги форматирования JSTL

Он используется для форматирования и отображения текста, даты, времени и чисел.

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"  %>

Вы должны использовать тот же формат (ММ-дд-гггг), в противном случае используйте InitBinder.

Реализация операций - Обновление

Операция обновления не так уж отличается от операции добавления. Он также полагается на отправку формы.

Итак, также есть две операции. Во-первых, форма будет заполнена данными заказа, которые необходимо обновить (с заданным идентификатором заказа), а затем обработать отправленные данные.

На уровне DAO, во-первых, нам нужно получить объект заказа с учетом его идентификатора.

Затем мы обновляем существующий объект заказа. Для этого нам просто нужно добавить небольшую модификацию метода saveOrder(), чтобы он работал в обоих случаях; создание и обновление существующего заказа.

💡 Метод saveOrUpdate() добавит новую запись, если объект заказа не имеет идентификатора (первичного ключа), в противном случае он обновит данный порядок в таблице.

Точно так же на уровне обслуживания у нас есть две операции; получить конкретный заказ по его идентификатору и обновить существующий.

Для обновления используйте тот же метод saveOrder() для создания и обновления существующего заказа.

В контроллере нам нужно сначала отобразить HTML-форму, заполненную данными заказа, которые необходимо обновить (с заданным идентификатором заказа). Идентификатор заказа можно отправить в параметре URL (т. Е. / order / viewOrder? OrderId = 125).

Мы будем использовать ту же HTML-форму, которую использовали ранее для создания нового заказа, поэтому отправленные данные будут попадать в тот же метод, saveOrder() который мы использовали для создания нового заказа. Этот метод будет вести себя одинаково в обоих случаях.

На страницах просмотра нам нужно сначала добавить ссылку на обновление для каждого заказа на странице «список заказов».

На странице просмотра «order-form.jsp» добавьте скрытое поле формы ввода в HTML-форму для идентификатора заказа. Итак, когда форма отправлена, мы знаем, в каком порядке нужно обновить.

<form:hidden path="id" />

Выполнение операций - Удалить

Теперь операция удаления должна показаться простой. Все, что нам нужно сделать, это удалить существующий заказ, учитывая его идентификатор в параметре URL.

На слое DAO удалите заказ по его идентификатору.

На уровне Service, как обычно, вызовите метод deleteOrder().

В контроллере вызовите deleteOrder() этого уровня сервиса, чтобы удалить данный заказ и перенаправить на страницу со списком всех заказов.

На странице просмотра «list-orders.jsp» нам нужно добавить ссылку на удаление для каждого отображаемого заказа, как мы это делали с update.

Спасибо за внимание! Если вам понравилось, похлопайте 👏 за это.