- •Цель работы
- •Теоретическая часть
- •Слоистая архитектура
- •Ключевые понятия
- •Ход выполнения работы
- •Часть 0. Подготовка
- •Часть 1. Подключение Spring Data JPA и PostgreSQL
- •Часть 2. Создание сущностей и перечислений
- •2.1. Создайте перечисления NotificationChannel и NotificationStatus
- •2.2. Создайте сущность User
- •2.3. Создайте сущность Notification
- •Часть 3. Создание DTO и репозиториев
- •3.1. DTO для User
- •3.2. DTO для Notification
- •3.3. Создайте репозитории
- •Часть 4. Реализация CRUD для User
- •4.1. Создайте UserService
- •4.2. Создайте UserController
- •Часть 5. Реализация CRUD для Notification
- •5.1. Создайте NotificationService
- •5.2. Создайте NotificationController
- •5.3. Проверьте работу CRUD-операций для Notification
- •Часть 6. Методы репозитория Spring Data JPA
- •6.1. Запрос по нескольким параметрам
- •6.2. Сортировка в имени метода
- •6.3. Использование @Query
- •Часть 7. Транзакции
- •Часть 8. Проверка работы приложения в Postman
- •Часть 9. Валидация данных
- •Самостоятельные задания
- •Контрольные вопросы
@Param("channel")
NotificationChannel channel);
Аннотация @Param() связывает имя параметра в методе репозитория с именем параметра, указанного внутри запроса после двоеточия. Например, @Param("status") передает значение переменной status в выражение :status внутри JPQL-запроса. Это делает код более читаемым и позволяет не зависеть от порядка параметров.
Native SQL-запрос:
@Query(value = """
select *
from notifications where status = :status
and channel = :channel
""", nativeQuery = true)
List<Notification> findNativeByStatusAndChannel(@Param("status") String status,
@Param("channel") String
channel);
JPQL работает с сущностями и полями Java, а native SQL работает напрямую с таблицами и колонками базы данных.
Часть 7. Транзакции
Если во время выполнения метода возникает ошибка, в базе данных могут остаться частично сохраненные данные. Рассмотрим это на примере метода создания уведомления.
Измените createNotification() следующим образом:
public Notification createNotification(NotificationDto request) { User user =
userRepository.findById(request.getRecipientId()).orElseThrow();
Notification notification = new Notification(); notification.setTitle(request.getTitle()); notification.setMessage(request.getMessage()); notification.setChannel(request.getChannel()); notification.setStatus(NotificationStatus.CREATED); notification.setCreatedAt(LocalDateTime.now()); notification.setRecipient(user);
notificationRepository.save(notification);
if (true) {
throw new RuntimeException("Искусственная ошибка");
}
18
return notification;
}
Запустите приложение и попробуйте создать уведомление. Вы увидите, что ошибка возникла, но запись при этом могла сохраниться.
Добавьте аннотацию @Transactional :
@Transactional
public Notification createNotification(NotificationDto request) {
...
}
Аннотация @Transactional гарантирует, что изменения будут зафиксированы в базе данных только в случае успешного завершения метода. Если в процессе возникнет исключение, транзакция будет откатана.
Часть 8. Проверка работы приложения в Postman
1.Запустите приложение.
2.Откройте Postman.
3.Проверьте создание пользователя запросом POST http://localhost:8080/users/add .
4.Проверьте получение списка пользователей запросом
GET http://localhost:8080/ users/all
.
5.Проверьте получение пользователя по идентификатору запросом
GET http:// localhost:8080/users/{id}
.
6.Проверьте обновление пользователя запросом
PUT http://localhost:8080/users/ {id}
.
7.Проверьте удаление пользователя запросом
DELETE http://localhost:8080/users/ {id}
.
8.Проверьте создание уведомления запросом
POST http://localhost:8080/ notifications/add
.
9.Проверьте получение списка уведомлений запросом
GET http://localhost:8080/ notifications/all
.
10.Проверьте получение уведомления по идентификатору запросом
GET http:// localhost:8080/notifications/{id}
.
11.Проверьте обновление уведомления запросом
PUT http://localhost:8080/ notifications/{id}
.
12.Проверьте удаление уведомления запросом
DELETE http://localhost:8080/ notifications/{id}
.
13.Проверьте дополнительные методы поиска:
◦GET http://localhost:8080/notifications/status/{status}
◦GET http://localhost:8080/notifications/channel/{channel}
◦GET http://localhost:8080/notifications/recipient/{recipientId}
14.Убедитесь, что ответы приходят корректно и данные сохраняются в базе данных.
19
Часть 9. Валидация данных
Для работы с валидацией используется модуль jakarta.validation . Аннотации валидации добавляются в DTO, а в контроллере используется аннотация @Valid .
Измените UserDto следующим образом:
package org.example.model.dto;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.Setter;
import java.time.LocalDateTime;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor public class UserDto {
@NotBlank(message = "Имя не должно быть пустым")
@Size(max = 100, message = "Имя не должно быть длиннее 100 символов") private String name;
@NotBlank(message = "Email обязателен") @Email(message = "Некорректный формат email") @Pattern(
regexp = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$", message = "Email не соответствует требуемому шаблону"
)
private String email;
private String phone;
private String deviceToken;
private String telegramChatId;
private LocalDateTime createdAt;
}
Пример использования @Valid в контроллере:
20
