Реализуйте сервлетное приложение для регистрации авиабилетов, соответствующее изложенным ниже требованиям.
Приложение должно использовать следующие сущности:
- Пользователь. Сущность, необходимая для авторизации и определения прав доступа конкретного пользователя системы. Должна содержать логин (email) и хеш пароля, ФИО, роль (пользователь или администратор), дату последнего входа в приложение и флаг блокировки;
- Пассажир. Атрибутивный состав должен описывать конкретного человека, на имя которого будут регистрироваться авиабилеты пользователями. Один пользователь может регистрировать билеты для нескольких пассажиров. Предлагаемые атрибуты: ФИО, пол, дата рождения, паспортные данные;
- Билет. Атрибутивный состав должен давать исчерпывающую информацию о полете: класс обслуживания, посадочное место*, допустимые нормы багажа и ручной клади, информация о рейсе;
- Рейс. Атрибутивный состав должен предоставлять информацию о конкретном рейсе: даты и время отправления и прибытия, аэропорты отправления и прибытия, общее и доступное число билетов;
- Аэропорт. Должен давать информацию о конкретном аэропорте: код, название и адрес;
- Любимые аэропорты пассажира. Данная сущность необходима для хранения топ-3 аэропортов конкретного пассажира.
*Рекомендую использовать обычную числовую нумерацию для облегчения генерации билетов. Более сложные и приближенные к реальности модели нумерации потребуют создание сущности Самолет, что еще больше усложнит реализацию задачи.
Все данные описанных выше сущностей должны храниться в БД. Схема БД должна соответствовать третьей нормальной форме.
Схема данных (DDL) должна быть описана через скрипты миграций (Flyway или Liquibase), применяющиеся при старте приложения.
Взаимодействие Java-приложения с СУБД должно быть реализовано через JDBC с использованием пула соединений (HikariCP или любой другой).
При формировании конечного атрибутивного состава можно использовать наработки из разделов "Базы данных и основы SQL", "JDBC" и других.
Взаимодействие с системой должно быть возможно только для авторизованных пользователь. Модель авторизации - авторизация по сессии.
Для аутентификации должен быть предоставлен HTTP-метод, позволяющий передать логин и пароль. В БД пароль пользователя должен храниться в захешированном (алгоритм хеширования может быть выбран при реализации) виде, чтобы избежать утечки фактических паролей пользователей при утечке данных. При аутентификации у пользователя должна обновиться информация о последнем входе в приложение.
При блокировке пользователя администратором должно его дальнейшая авторизация в системе становится невозможной до момента разблокировки. Опционально - реализация прерывания текущей сессии пользователя при его блокировке.
Доступы пользователя в зависимости от роли должны соответствовать описанным в разделе "Ролевая модель".
В системе должно быть реализовано две роли: Пользователь и Администратор.
- Просмотр, добавление, редактирование и удаление информации о пассажирах, связанных с этим пользователем;
- Просмотр информации о рейсах и аэропортах;
- Регистрация на рейсы, при наличии свободных мест. Выбор места при регистрации. Отмена регистрации, просмотр своих билетов - как всех, так и актуальных (дата и время отправления еще не наступила) на момент запроса;
- Смена пароля своей учетной записи;
- Изменение своих личных данных - ФИО.
- Просмотр информации о пассажирах - как всех, так и связанных с конкретным пользователем;
- Просмотр, добавление, редактирование и удаление рейсов и аэропортов;
- Отмена регистрации пассажиров на рейс, просмотр всех существующих билетов;
- Добавление администраторов;
- Просмотр, блокировка и разблокировка других пользователей (включая администраторов).
Администраторы могут быть зарегистрированы только через добавление нового пользователя администратором. Таким образом первый администратор должен быть добавлен автоматически при первом запуске приложения.
Пользователи могут добавляться только через функциональность регистрации, определенной соответствующим HTTP-методом.
При регистрации пользователь должен указать свой email (должен быть уникальным), пароль и ФИО.
Для каждой функции или блока функций, связанный с определенной сущностью, должен быть определен свой путь запроса.
Например, запросы для взаимодействия с билетами должны в пути иметь префикс /ticket
, для взаимодействия с
пассажирами - /passenger
и т.д.
Методы за пределами базового CRUD могут иметь более сложный путь. Например, блокировку пользователя можно привязать
к пути /user/block
.
Выбор методов HTTP для конкретного эндпоинта (url-адреса запроса) должен опираться на семантику HTTP. Методы
получения данных - GET
, удаления - DELETE
и т.д.
Передача данных в теле запроса и ответа должна осуществляться с помощью JSON.
При получении данных по сущности не требуется передавать связанные сущности - достаточно указать их id
и убедиться,
что существует метод получения данных о связанной сущности по id
.
Сами передаваемые по HTTP объекты не должны напрямую десериализоваться в те классы, которые используются для взаимодействия на уровне домена и/или БД - рекомендую выделить отдельный слой DTO. Это защитит от казусов, вроде передачи хеша пароля при получении информации о пользователях и ряда других проблем.
Все классы логики должны быть покрыты юнит-тестами. Также юнит-тестами должны быть покрыты и методы в классах сущностей,
если поведение сущности шире, чем предоставление getter'ов, setter'ов и методов Object
.
Ветка для PR: for-pr
. Рекомендую добавлять изменения постепенно, по коммиту на отдельную решаемую задачу.