Собираем все вместе и создаем весеннее веб-приложение.
Вступление
Итак, мы подошли к концу этого урока. Теперь пришло время применить все, что мы узнали, и создать настоящее веб-приложение, реализующее операции 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.
Спасибо за внимание! Если вам понравилось, похлопайте 👏 за это.