Будь ласка, використовуйте цей ідентифікатор, щоб цитувати або посилатися на цей матеріал: https://er.chdtu.edu.ua/handle/ChSTU/6019
Назва: Веб-орієнтований сервіс для пошуку місць відпочинку
Автори: Оксамитна, Любов Павлівна
Кавун, Дмитро Романович
Ключові слова: ПРЕДМЕТНА ОБЛАСТЬ,;ВЕБ-СЕРВІС,;ПОШУК,;ПРОЄКТУВАННЯ,;МІСЦЕ ВІДПОЧИНКУ,;REACT JS,;JAVA,;JAVA SPRING.
Дата публікації: 12-чер-2024
Короткий огляд (реферат): Необхідність вирішення питань пошуку місць відпочинку через веб-сервіси, їх ефективне використання за допомогою сучасних інформаційних технологій обумовлює актуальність обраної теми кваліфікаційної роботи бакалавра. Створений веб-орієнтований сервіс для пошуку місць відпочинку покликаний не лише спростити пошук місць відпочинку, а й популяризувати заклади, аби підняти рівень відпочинку в місті. Мета кваліфікаційної роботи бакалавра – створення веб-орієнтованого сервісу для пошуку місць відпочинку. Основні положення і результати кваліфікаційної роботи бакалавра доповідалися і були обговорені на студентській науково-практичній конференції ЧДТУ (Черкаси, 2024).
URI (Уніфікований ідентифікатор ресурсу): https://er.chdtu.edu.ua/handle/ChSTU/6019
Розташовується у зібраннях:122 Комп’ютерні науки (Комп’ютерні науки та прикладне програмування)

Файли цього матеріалу:
Файл Опис РозмірФормат 
Пояснювальна записка_Кавун Дмитро_КНС-2201_2023-24.pdf
  Restricted Access
4.53 MBAdobe PDFПереглянути/Відкрити    Запит копії


Усі матеріали в архіві електронних ресурсів захищено авторським правом, усі права збережено.

Extracted text
 
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИЧЕРКАСЬКИЙ ДЕРЖАВНИЙ 
ТЕХНОЛОГІЧНИЙ УНІВЕРСИТЕТ 
 
Факультет інформаційних технологій і систем 
 
Кафедра комп’ютерних наук та системного аналізу 
 
 
 
 
 
Пояснювальна записка 
до кваліфікаційної роботи 
бакалавра 
 (освітньо-кваліфікаційний рівень) 
 
на тему: «Веб-орієнтований сервіс для пошуку місць відпочинку» 
 
 
 
 
 
    Виконав: студент 4 курсу, групи КНС-2201 
                                                              
спеціальності  122  «Комп’ютерні науки» 
                                                                         (шифр і назва спеціальності) 
  
освітня програма «Комп’ютерні науки та                                                                                                                               
(назва освітньої програми) 
прикладне програмування                                                                                                                                                              
                                                                       
 
Кавун Дмитро Романович 
 
Керівник __________   Оксамитна Л.П.        
                                                                          (прізвище та ініціали) 
 
Рецензент __________  Стась С.В.   
                                                                          (прізвище та ініціали) 
    
 
 
 
 
 
Черкаси 2024 року
 
 2 
Бланк завдання на кваліфікаційну роботу бакалавра студенту 
 
Черкаський державний технологічний університет 
Факультет Інформаційних технологій і систем 
Кафедра Комп’ютерних наук та системного аналізу 
Освітньо-кваліфікаційний рівень Бакалавр 
Спеціальність 122  – Комп’ютерні науки 
Освітня програма Комп’ютерні науки та прикладне програмування 
 
 
 
ЗАТВЕРДЖУЮ 
Завідувач кафедри КНСА  
_______________ Юрій ТРИУС 
«____» _____________ 2024 р. 
 
 
 
ЗАВДАННЯ 
на кваліфікаційну роботу бакалавра студенту 
Кавуну Дмитру Романовичу 
(прізвище, ім‘я, по батькові) 
1. Тема роботи  «Веб-орієнтований сервіс для пошуку місць відпочинку» 
                                  
 
Керівник роботи     Оксамитна Л.П., к.т.н., доцент                    
(прізвище, ім’я, по батькові, науковий ступінь, вчене звання) 
затверджені наказом університету від «26» лютого 2024 р. №60/04. 
 
2. Строк подання студентом роботи до 10 червня 2024 року 
3. Вихідні дані до роботи:  
Практичні навики роботи з інформаційними ресурсами. Робота з базами даних. 
Звіт з виробничої практики. Звіт з переддипломної практики. 
4. Зміст пояснювальної записки (перелік питань, що їх належить розробити): 
Вступ 
4.1. Дослідження предметної області. 
4.2. Проєктування та розробка веб-орієнтованого сервісу для пошуку місць відпочинку.  
 
4.3. Тестування веб-орієнтованого сервісу для пошуку місць відпочинку. 
Висновки.  
 5. Перелік додатків (з точним зазначенням назв додатків): 
5.1. Додаток А. Специфікація 482.ЧДТУ. 42291-01. 
 5.2. Додаток Б. Текст програми. 
5.3. Додаток В. Інструкція користувача. 
5 .4. Додаток Г. Структура бази даних.  
5.5. Додаток Д. Публікація по темі кваліфікаційної роботи бакалавра. 
5.6. Презентація у вигляді 28 слайдів. 
 
 
 3 
6. Консультанти розділів роботи 
Прізвище, ініціали та Підпис, дата 
Розділ 
посада консультанта завдання видав завдання прийняв 
    
    
 
7. Дата видачі завдання 15.01.2024 
  
 
КАЛЕНДАРНИЙ ПЛАН 
Строк виконання 
№ з/п Назва етапів кваліфікаційної роботи бакалавра Примітка 
етапів роботи 
1 Видача завдання на кваліфікаційну роботу 
15.01.2024 Виконано 
бакалавра. 
2 Аналіз літературних джерел, об’єкту та предмету 
до 12.02.2024 Виконано 
дослідження. 
3 Написання теоретичного розділу кваліфікаційної 
до 18.03.2024 Виконано 
роботи бакалавра. 
4 Написання аналітичного розділу кваліфікаційної 
до 01.04.2024 Виконано 
роботи бакалавра. 
5 Написання практичних розділів й висновків до 
до 01.05.2024 Виконано 
кваліфікаційної роботи бакалавра. 
6 Передзахист кваліфікаційної роботи бакалавра 
03.06.2024 Виконано 
на засіданні кафедри КНСА. 
7 Подання роботи завідувачу кафедри КНСА. до 10.06.2024 Виконано 
8 Захист кваліфікаційної роботи бакалавра. 12.06.2024 Виконано 
    
    
    
 
 
 
Студент                                   _____________________________     Дмитро КАВУН 
                                                                            (підпис)                                                                     
 
Керівник роботи                     ____________________________       Любов ОКСАМИТНА 
                                           (підпис)      
 
                                                              
 
 4 
РЕФЕРАТ 
Кваліфікаційна робота бакалавра містить: 102 с., 46 рис., 1 таблицю, 18 
використаних джерел, 5 додатків. 
Актуальність теми. Необхідність вирішення питань пошуку місць відпочинку 
через веб-сервіси, їх ефективне використання за допомогою сучасних інформаційних 
технологій обумовлює актуальність обраної теми кваліфікаційної роботи бакалавра. 
Створений веб-орієнтований сервіс для пошуку місць відпочинку покликаний не 
лише спростити пошук місць відпочинку, а й популяризувати заклади, аби підняти 
рівень відпочинку в місті.  
Мета роботи і задачі дослідження. Мета кваліфікаційної роботи бакалавра – 
створення веб-орієнтованого сервісу для пошуку місць відпочинку. 
Для досягнення мети були поставлені такі завдання: 
 дослідити сферу організації відпочинку; 
 виконати порівняльний аналіз існуючих сервісів для пошуку місць відпочинку; 
 обрати програмно-технічні засоби для розробки веб-орієнтованого сервісу для 
пошуку місць відпочинку; 
 розробити веб-орієнтований сервіс для пошуку місць відпочинку; 
 провести тестування веб-орієнтованого сервісу для пошуку місць відпочинку. 
Об’єкт дослідження: процеси  пошуку місць відпочинку через веб-сервіси. 
Предмет дослідження: веб-орієнтований сервіс для пошуку місць відпочинку.  
Методи дослідження.  
 теоретичний (аналіз літератури з проблеми дослідження); 
 емпіричний – полягав у створенні та налаштуванні веб-орієнтованого сервісу 
для пошуку місць відпочинку;  
 порівняльний – застосовувався при порівнянні існуючих сервісів для пошуку 
місць відпочинку. 
Апробація результатів роботи. Основні положення і результати 
кваліфікаційної роботи бакалавра доповідалися і були обговорені на студентській 
науково-практичній конференції ЧДТУ (Черкаси, 2024). 
 
 5 
Публікації. Результати кваліфікаційної роботи бакалавра опубліковані у  
збірнику тез доповідей студентської науково-практичної конференції ЧДТУ:  
Кавун Д.Р., Оксамитна Л.П. Розробка веб-орієнтованого сервісу для пошуку 
місць відпочинку. Тези доповідей студентської науково-практичної конференції 
ЧДТУ, 23-24 квітня 2024 р. Черкаси : ЧДТУ, 2024. С. 
Перелік ключових слів: ПРЕДМЕТНА ОБЛАСТЬ, ВЕБ-СЕРВІС, ПОШУК, 
ПРОЄКТУВАННЯ, МІСЦЕ ВІДПОЧИНКУ, REACT JS, JAVA, JAVA SPRING. 
 
ABSTRACT 
Master’s work contains: 102 pages, 46 figures, 1 table, 18 sources used, 5 
attachments. 
Actuality of theme: The need to solve the issues of finding places of rest through 
web services, their effective use with the help of modern information technologies 
determines the relevance of the chosen topic of the bachelor's qualification work. The 
created web-oriented service for finding places of rest is designed not only to simplify the 
search for places of rest, but also to popularize establishments in order to raise the level of 
recreation in the city. 
Purpose and tasks of the research: The purpose of the bachelor's thesis is to create 
a web-based service for finding vacation spots. 
To achieve the goal, the following tasks were set: 
– explore the field of recreation organization; 
– perform a comparative analysis of existing services for finding places of rest; 
– choose software and technical means for the development of a web-oriented service 
for finding places of rest; 
– develop a web-oriented service for finding places of rest; 
– conduct testing of a web-oriented service for finding places of rest. 
Object of research: processes of finding places of rest through web services. 
The subject of research:  web-oriented service for finding places of rest. 
Research methods:  
– theoretical (analysis of the literature on the research problem); 
 
 6 
– empirical – consisted in the creation and configuration of a web-oriented service for 
finding places of rest; 
– comparative – for making comparisons of existing services for finding places of rest. 
Approbation of work results. The main provisions and results of the bachelor's 
qualification work were reported and discussed at the student scientific and practical 
conference of ChDTU (Cherkasy, 2024). 
Publications. The results of the bachelor's qualification work are published in the 
collection of abstracts of reports of the student scientific-practical conference of ChDTU: 
Watermelon D.R., Oksamytna L.P. Development of a web-oriented service for 
finding vacation spots. Abstracts of reports of the student scientific and practical conference 
of ChDTU, April 23-24, 2024. Cherkasy: ChDTU, 2024. P. 
The list of keywords: SUBJECT FIELD, WEB SERVICE, SEARCH, DESIGN, 
REST, REACT JS, JAVA, JAVA SPRING. 
  
 
 7 
ЗМІСТ 
 
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ, СИМВОЛІВ, СКОРОЧЕНЬ І ТЕРМІНІВ .. ..9 
1 ДОСЛІДЖЕННЯ ПРЕДМЕТНОЇ ОБЛАСТІ .......................................................... 12 
1.1 Аналіз сучасного стану пошуку місць відпочинку через веб-сервіси ........... 12 
1.2 Огляд існуючих аналогів веб-орієнтованих сервісів для пошуку місць 
відпочинку .................................................................................................................. 14 
1.3 Аналіз порівнянь існуючих рішень розглянутих реалізацій та постановка 
завдання …………………………………………………………………………….21 
Висновки до розділу 1 ............................................................................................... 22 
2 ПРОЄКТУВАННЯ ТА РОЗРОБКА ВЕБ-ОРІЄНТОВАНОГО СЕРВІСУ ДЛЯ 
ПОШУКУ МІСЦЬ ВІДПОЧИНКУ .............................................................................. 23 
2.1  Опис функціонального програмного середовища для розробки ................... 23 
2.1.1 Опис програмного середовища IntelliJ Idea………………………………. 23 
2.1.2 Опис програмного середовища WebStorm………………………………...25 
2.1.3 Опис мови програмування Java та фреймворку Spring …………………..27 
2.1.4 Опис бібліотеки React ………………………………………………………29 
2.2 Основні принципи розробки веб-орієнтованого сервісу ................................. 31 
2.3 Архітектура веб-орієнтованого сервісу ............................................................. 33 
2.3.1 Опис frontend частини сервісу………………………………………………34 
2.3.2 Опис backend частини сервісу………………………………………………35 
2.4 Розробка діаграми варіантів використання ....................................................... 36 
2.6 Опис процесу проєктування структури веб-орієнтованого сервісу для пошуку 
місць відпочинку ........................................................................................................ 40 
Висновки до розділу 2 ............................................................................................... 47 
3 ПРОГРАМНА РЕАЛІЗАЦІЯ ТА ТЕСТУВАННЯ ВЕБ-ОРІЄНТОВАНОГО 
СЕРВІСУ ДЛЯ ПОШУКУ МІСЦЬ ВІДПОЧИНКУ................................................... 48 
3.1 Постановка завдання ........................................................................................... 48 
3.2 Інтерфейс веб-орієнтованого сервісу для пошуку місць відпочинку ............ 50 
 
 8 
3.3 Програмна реалізація веб-орієнтованого сервісу для пошуку місць 
відпочинку……………………….. ............................................................................ 56 
3.4 Тестування backend частини веб-орієнтованого сервісу для пошуку місць 
відпочинку .................................................................................................................. 56 
Висновки до розділу 3 ............................................................................................... 60 
ВИСНОВКИ ................................................................................................................... 61 
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ ..................................................................... 62 
ДОДАТОК А. Специфікація 482.ЧДТУ. 42291-01 .................................................... 66 
ДОДАТОК Б. Текст програми ..................................................................................... 66 
ДОДАТОК В. Інструкція користувача ........................................................................ 93 
ДОДАТОК Г. Структура бази даних ........................................................................... 98 
ДОДАТОК Д. Публікація по темі кваліфікаційної роботи бакалавра ................... 101 
 
 
 
 
 9 
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ, СИМВОЛІВ, СКОРОЧЕНЬ І ТЕРМІНІВ 
БД – база даних; 
API – прикладний програмний інтерфейс; 
ПЗ – програмне забезпечення; 
CRUD-операції – акронім, який означає чотири основні операції при роботі з БД: 
створення (Create), читання (Read), оновлення (Update), видалення (Delete); 
IDE – комплексне програмне рішення для розробки програмного забезпечення; 
HTML – мова розмітки гіпертексту; 
CSS – каскад таблиці стилів; 
JS – мова написання сценаріїв веб-сторінок; 
JSON – запис об’єктів JavaScript; 
DOM – Document Object Model; 
СКБД – система керування базами даних. 
 
 
 10 
ВСТУП 
На сьогоднішній день відпочинок є невід'ємною частиною життя кожної 
людини, особливо в цьому метушливому світі. Він є важливим компонентом 
сучасного життя, які допомагають зберегти баланс та відновити енергію. Щоб 
відновити енергію та зарядитися позитивом, багато людей знаходять втіху на 
прекрасних пляжах, в заміських комплексах, базах відпочинку та інших місцях, що 
пропонують різноманітні форми відпочинку. Вибір місця відпочинку залежить від 
смаку та бажань кожного відпочивальника: від кришталевих пляжів до зелених 
заміських комплексів, від бань та саун до гарячих джерел.  
Україна – це країна з багатою історією, чарівною природою та 
багатим культурним спадком. В Україні, попри війну, можна знайти безліч 
неймовірно красивих місць для відпочинку та подорожей. Це й гірські краєвиди 
Карпат, сині озера Закарпаття, піщані дюни на півдні України, стародавні замки та 
фортеці, а також багато іншого. Україна також славиться своєю гостинністю та 
смачною кухнею. Подорожуючи, можна спробувати національні страви, притаманні 
тим чи іншим регіонам. В Україні можна знайти незабутні враження та зарядитися 
позитивною енергією [1]. У зв’язку з обмеженнями на міжнародні поїздки в Україні 
люди продовжують більше цікавитися відпочинком всередині країни. У цьому році 
найпопулярнішими напрямками відпочинку в Україні стали Бердянськ, Залізний 
Порт і Коблево.  
Незалежно від вибору, важливо знайти час для себе і насолодитися моментом, 
осяяний спокоєм та релаксацією. Нині на ринку відпочинку проявляються тенденції 
активного використання можливостей сучасних інформаційних технологій для 
пошуку місць відпочинку. Тому сьогодні велика увага приділяється процесам  
пошуку місць відпочинку за допомогою веб-орієнтованих сервісів. 
           Актуальність  теми кваліфікаційної роботи бакалавра.   
Необхідність вирішення питань пошуку місць відпочинку через веб-сервіси, їх 
ефективне використання за допомогою сучасних інформаційних технологій 
обумовлює актуальність обраної теми кваліфікаційної роботи бакалавра.  
 
 11 
Створений веб-орієнтований сервіс для пошуку місць відпочинку покликаний 
не лише спростити пошук місць відпочинку, а й популяризувати заклади, аби підняти 
рівень відпочинку в місті.  
Мета кваліфікаційної роботи бакалавра – створення веб-орієнтованого сервісу 
для пошуку місць відпочинку. 
Для досягнення мети були поставлені такі завдання: 
 дослідити сферу організації відпочинку; 
 виконати порівняльний аналіз існуючих сервісів для пошуку місць відпочинку; 
 обрати програмно-технічні засоби для розробки веб-орієнтованого сервісу для 
пошуку місць відпочинку; 
 розробити веб-орієнтований сервіс для пошуку місць відпочинку; 
 провести тестування веб-орієнтованого сервісу для пошуку місць відпочинку. 
Об’єкт і предмет дослідження.  
Об’єктом дослідження є процеси  пошуку місць відпочинку через веб-сервіси. 
Предметом дослідження є веб-орієнтований сервіс для пошуку місць 
відпочинку.  
Для вирішення поставлених завдань були застосовані наступні методи 
дослідження: 
 теоретичний (аналіз літератури з проблеми дослідження); 
 емпіричний – полягав у створенні та налаштуванні веб-орієнтованого сервісу 
для пошуку місць відпочинку;  
 порівняльний – застосовувався при порівнянні існуючих сервісів для пошуку 
місць відпочинку. 
Для створення програмного забезпечення використано новітні технології, а 
саме: Java, Spring Framework, React, PostgreSQL, REST API. Обрані технології 
задовольняють всім функціональним і не функціональним вимогам до такого типу 
програмного забезпечення (ПЗ). 
 
 
 
 12 
1 ДОСЛІДЖЕННЯ ПРЕДМЕТНОЇ ОБЛАСТІ 
1.1 Аналіз сучасного стану пошуку місць відпочинку через веб-сервіси 
В Україні, як і в усьому світі, Інтернет став незамінним інструментом для 
планування подорожей та відпочинку, а з його розвитком пошук місць відпочинку 
стає все більш доступним та зручним. Веб-сервіси пошуку місць відпочинку 
пропонують широкий спектр можливостей, що дозволяють користувачам знаходити 
ідеальні місця для відпочинку, проведення вільного часу, місць для зупинки на ніч, 
заклади харчування та інші послуги. Ці сервіси враховують інтереси користувачів, 
бюджет, місцевість, в якій користувач хоче відпочити та інші фактори. Популярність 
та необхідність даного сектору веб-сервісів обумовлюється такими тенденціями та 
аспектами: 
– Зростання популярності онлайн-пошуку. За останні 10 років спостерігається 
збільшення кількості людей, які шукають місця для відпочинку через Інтернет. 
Онлайн-сервіси стають все популярнішими для планування поїздок та проведення 
часу в нових та незнайомих місцях. 
– Роль соціальних мереж. Користувачі часто звертають увагу на відгуки та 
рекомендації від інших людей в соціальних мережах. Враження та фотографії, 
розміщені іншими користувачами, можуть суттєво впливати на вибір місця 
відпочинку. 
– Конкуренція серед платформ. Зростає кількість веб-сервісів для пошуку місць 
відпочинку. Конкуренція між ними може призводити до появи нових функцій та 
покращень для залучення нових користувачів. 
– Аналіз вартості та зручностей. Користувачі часто порівнюють ціни та відгуки 
перед тим, як зробити вибір. Онлайн-сервіси сприяють зручному та ефективному 
аналізу доступних опцій. 
– Візуальний контент. Фото та відео відіграють важливу роль у представленні 
місць відпочинку. 
 
 13 
– Економія часу. Веб-сервіси дозволяють швидко порівняти різні варіанти та 
знайти найкращий для себе. 
– Широкий вибір. Веб-сервіси пропонують широкий спектр місць відпочинку, в 
залежності від побажань та можливостей користувача. 
Розглянемо головні характеристики веб-сервісу для пошуку місця відпочинку. 
При створенні такого веб-сервісу реалізується клієнтська версія з наступними 
функціями та можливостями: 
– Особистий кабінет, в якому можна переглянути та змінити персональні дані, 
переглянути збережені місця в розділі «Обране». 
– Перегляд списків з місцями для відпочинку в різних містах України або з різних 
категорій. Серед них: готелі, кінотеатри, театри, квест-кімнати, ресторани та інші 
заклади та місця відпочинку. 
– Перегляд детальної інформації про місце відпочинку та перехід на сторінку 
самого закладу для замовлення послуг. 
– Можливість додавання місця відпочинку в «обране» для подальшого 
відображення в особистому кабінеті. 
Для управління контентом сервісу необхідний додатковий функціонал 
адміністратора. В адміністратора повинна бути можливість додавати інформацію про 
нові місця та заклади для відпочинку, редагувати та видаляти вже існуючу 
інформацію, мати доступ до профілів користувачів для зміни чи видалення необхідної 
інформації. Для цього потрібні додаткові сторінки, які доступні тільки 
адміністратору. 
Опишемо основні етапи розробки веб-орієнтованого сервісу для пошуку місць 
відпочинку. 
Розробка веб-сервісу для пошуку місць відпочинку – це складний та довгий 
процес, який включає 5 основних кроків: 
1. Дослідження сфери пошуку місць відпочинку. Для того, щоб перевершити 
аналогічні сервіси, необхідно бути проінформованим щодо актуальності даних 
сервісів. Зазвичай існують окремі сервіси для пошуку інформації про заклади у 
кожному напрямку в сфері відпочинку. Ідея кваліфікаційної роботи бакалавра 
 
 14 
полягає саме в тому, щоб створити сервіс, який об’єднує в собі інформацію про місця 
відпочинку з різних напрямків. 
2. Вивчення цільової аудиторії. Щоб створити якомога якісніший сервіс, потрібно 
краще знати хто буде користуватись цим сервісом, які їхні потреби та очікування. 
3. Функціонал сервісу. Потрібно знати які функції буде мати й виконувати веб-
сервіс та які дані він буде використовувати. Все це залежить від потреб потенційних 
користувачів та того, що необхідно для роботи адміністратора. 
4. Вибір технологій для реалізації. Перед реалізацією важливою частиною 
являється вибір технологій, які будуть використовуватись для створення БД, back-end 
частини та front-end частини. 
5. Реалізація та підтримка. Для повноцінної роботи сервісу необхідно продумати 
правильну структуру БД, наповнити її даними, створити back-end частину та API для 
отримання даних через запити до серверу, створити front-end частину, об’єднати back-
end та front-end. Важливо регулярно перевіряти та виправляти помилки, які 
виявляються в роботі веб-сервісу та оновлювати новими функціями та даними. 
1.2 Огляд існуючих аналогів веб-орієнтованих сервісів для пошуку місць 
відпочинку 
У кваліфікаційній роботі бакалавра проведено огляд існуючих аналогів веб-
орієнтованих сервісів для пошуку місць відпочинку, таких як: «UaHotels», «RestOn», 
«Reservble», «Theatre», «QUESTROOM» та «Hotels24». 
         1.2.1 Аналіз сервісу «UaHotels». Першим прикладом аналогів розглянемо 
сервіс «UaHotels». Головна сторінка сервісу представлена на рис. 1.1 [2]. Даний сервіс 
являє собою каталог туристичних об’єктів, розміщених в Україні, який має карту 
готелів та відгуки про них (рис. 1.1).  
Розглянемо його переваги та недоліки. 
Недоліки сервісу «UaHotels»: 
– відсутня українська мова; 
– інформація про деякі готелі застаріла; 
 
 15 
– неповна або неточна інформація про деякі готелі. 
Переваги сервісу «UaHotels»: 
– великий каталог готелів України; 
– зручний пошук готелів за містом, типом, послугами та обладнанням номерів; 
– відгуки користувачів. 
 
Рисунок 1.1 – Головна сторінка сервісу «UaHotels» [2] 
1.2.2 Аналіз сервісу «RestOn». Другим в роботі проаналізовано сервіс 
«RestOn». Він допомагає користувачам шукати ресторани, кафе та інші заклади 
деяких міст України [3]. Тут можна переглядати інформацію про заклади, шукати їх 
за різними критеріями та навіть бронювати столики онлайн. Проте, інформація на 
сервісі може бути не завжди актуальною. Головна сторінка сервісу «RestOn» 
представлена на рис. 1.2. 
Переваги сервісу «RestOn»: 
– широкий вибір закладів. Тут представлено понад 10000 ресторанів, кафе, барів, 
та інших закладів певних міст України; 
– зручний пошук. Тут можна шукати заклади за назвою, районом, кухнею, ціною 
та іншими категоріями; 
 
 16 
– детальна інформація про заклади. На сайті представлені фото, описи, меню, 
відгуки відвідувачів, а також контактна інформація про заклади; 
– актуальні новини та події. На сайті можна знайти інформацію про нові заклади, 
спеціальні пропозиції, акції, фестивалі та інші події. 
 
Рисунок 1.2 – Головна сторінка сервісу «RestOn» [3] 
Недоліки сервісу «RestOn»: 
– мала кількість міст України. На даний момент на сайті можна знайти 
інформацію лише про заклади в Києві, Івано-Франківську, Львові, Одесі та Харкові; 
– не всі заклади представлені на сайті. Деякі ресторани та кафе не співпрацюють 
із сервісом, тому їх не можна знайти на сайті; 
– не завжди актуальна інформація. Іноді інформація про заклади (меню, ціни, 
години роботи) може бути неактуальною; 
– сайт може бути перевантажений інформацією. Через велику кількість закладів 
та інформації сайт може бути трохи перевантаженим, що може ускладнити пошук 
потрібної інформації. 
1.2.3 Аналіз сервісу «Reservble». Наступним в роботі проаналізовано сервіс 
«Reservble». «Reservble» – сервіс бронювання ресторанів, який допоможе знайти 
 
 17 
ресторан за кухнею, рейтингом, відгуками [4]. Зручно шукати столики онлайн та 
бронювати на конкретну годину. Головна сторінка сервісу представлена на рис. 1.3. 
 
Рисунок 1.3 – Головна сторінка сервісу «Reservble» [4] 
Недоліки сервісу «Reservble»: 
– мала кількість міст України. На даний момент на сайті можна знайти 
інформацію лише про заклади в Києві, Львові та Одесі; 
– не всі ресторани представлені. Не всі ресторани України представлені на сайті 
«Reservble»; 
– необхідність реєстрації. Для бронювання столиків через «Reservble» необхідно 
зареєструватися; 
– не завжди актуальна інформація. Іноді інформація про наявність вільних 
столиків може бути неактуальною. 
Переваги сервісу «Reservble»: 
– зручний пошук. Можна шукати ресторани за назвою, кухнею, районом, 
рейтингом, ціною та іншими параметрами; 
– фільтри. Можливість фільтрувати ресторани за наявності вільних столиків, 
тераси, дитячої кімнати, паркування та інших зручностей; 
 
 18 
– відгуки. Можна читати відгуки інших користувачів про ресторани, щоб 
допомогти користувачу зробити вибір; 
– бронювання онлайн. Можливість бронювати столики онлайн без дзвінків до 
ресторану; 
– підтвердження бронювання. Існує можливість отримувати підтвердження 
бронювання на електронну пошту та SMS; 
– безкоштовне бронювання. Бронювання столиків через Reservble безкоштовне. 
1.2.4 Аналіз сервісу «Theatre». Наступним в роботі проаналізовано сервіс 
«Theatre». Даний сервіс представляє собою цифровий архів інформації про українські 
театри. Він пропонує постійно зростаючу базу даних про театри та інформацію про 
вистави. Цей сервіс є цінним ресурсом для будь-кого, хто цікавиться українським 
театром [5]. Головна сторінка сервісу «Theatre» представлена на рис. 1.4. 
 
Рисунок 1.4 – Головна сторінка сервісу «Theatre» [5] 
Недоліки сервісу «Theatre»: 
– неповна інформація. Інформація на веб-сайті не завжди повна; 
– застарілий дизайн. 
Переваги сервісу «Theatre»: 
 
 19 
– цінний ресурс. Даний сервіс пропонує велику кількість інформації про 
український театр, включаючи самі театри, вистави, акторів та історію; 
– зручний пошук. Веб-сервіс має зручний пошук, який дозволяє користувачам 
легко знаходити інформацію; 
– безкоштовний. Веб-сервіс є безкоштовним для використання. 
1.2.5 Аналіз сервісу «QUESTROOM». Наступним в роботі проаналізовано 
сервіс «QUESTROOM». Цей сервіс допоможе бажаючим відпочити знайти квест-
кімнати в Україні. Головна сторінка сервісу представлена на рис. 1.5 [6]. 
 
Рисунок 1.5 – Головна сторінка сервісу «QUESTROOM» [6] 
Недоліки сервісу «QUESTROOM»: 
– неповний каталог. Деякі квест-кімнати не мають сторінок на сайті; 
– сайт може бути переповненим. Через велику кількість квест-кімнат на веб-сайті 
може бути складно знайти ту, яка підходить. 
Переваги сервісу «QUESTROOM»: 
– великий вибір квест-кімнат. На сайті представлено понад 1000 квест-кімнат з 
усієї України, тому існує можливість знайди ту, яка саме найбільше сподобається; 
– зручний пошук. Можна легко знайти квест-кімнати за жанром, містом, 
кількістю гравців та іншими критеріями; 
 
 20 
– детальна інформація. На кожній сторінці квест-кімнати легко знайти опис, 
фотографії, відгуки та іншу корисну інформацію; 
– відгуки та враження інших гравців. Можна прочитати відгуки про квест-
кімнати від інших гравців, щоб допомогти зробити правильний вибір. 
1.2.6 Аналіз сервісу «Hotels24». Наступним в роботі проаналізовано сервіс 
«Hotels24». «Hotels24» – це український сервіс для пошуку та бронювання готелів по 
всій Україні . Головна сторінка сервісу представлена на рис. 1.6 [7]. 
 
Рисунок 1.6 – Головна сторінка сервісу «Hotels24» [7] 
Недоліки сервісу «Hotels24»: 
– не всі готелі представлені. Не всі готелі України представлені на сайті; 
– фільтри пошуку. Система фільтрів пошуку може бути більш досконалою; 
– відгуки. Не всі відгуки про готелі перевірені. 
Переваги сервісу «Hotels24»: 
– великий вибір. Сервіс пропонує понад 4152 готелів в Україні та за кордоном; 
– безкоштовне бронювання. Сервіс не стягує комісію за оформлення і обробку 
бронювання; 
– знижки. Сервіс пропонує готелі зі знижкою до 50%; 
 
 21 
– відгуки. На сайті є 24271 відгуків про готелі, що допоможе вам зробити кращий 
вибір; 
– гнучкість. Сервіс пропонує різні варіанти бронювання, такі як бронювання без 
передоплати; 
– інформативність. На сайті є багато корисної інформації про готелі, такі як: фото, 
опис, карта розташування, відгуки. 
1.3 Аналіз порівнянь існуючих рішень розглянутих реалізацій та 
постановка завдання 
Проаналізувавши існуючі рішення розглянутих реалізацій, в кваліфікаційній 
роботі бакалавра поставлена основна задача – об’єднання функціоналу існуючих 
сервісів в один глобальний сервіс, покращення їх функціоналу та вирішення всіх 
недоліків. 
У таблиці 1.1 представлено порівняльний аналіз розглянутих веб-орієнтованих 
сервісів для пошуку місць відпочинку, а саме: «UaHotels», «RestOn», «Reservble», 
«Theatre», «QUESTROOM» та «Hotels24». 
Таблиця 1.1 – Таблиця порівнянь існуючих рішень розглянутих реалізацій 
Критерії порівняння сервісів 
Дизайн Швидкість Якість представленої 
Назва сервісу 
(0-5) завантаження інформації  
(0-5) (0-5) 
«UaHotels» 3 3.5 4 
«RestOn» 4 3 3.5 
«Reservble» 4 3 3 
«Theatre» 5 5 3.5 
«QUESTROOM» 3.5 3 5 
«Hotels24» 4 3 5 
 
 
 22 
Провівши аналіз існуючих рішень розглянутих реалізацій, в кваліфікаційній 
роботі бакалавра при розробці веб-орієнтованого сервісу для пошуку місць 
відпочинку необхідно звернути увагу на такі моменти: 
– веб-сервіс повинен мати зручний та зрозумілий інтерфейс та приємний дизайн; 
– веб-сервіс повинен мати високу швидкість завантаження; 
– веб-сервіс повинен мати високу швидкість обробки запитів. 
Постановка завдання: 
1. Аналіз роботи, функціональних вимог та використаних засобів користувацьких 
інтерфейсів існуючих веб-орієнтованих сервісів пошуку місць відпочинку. 
2. Дослідження та вибір найактуальніших технологій веб-розробки для створення 
сучасних веб-орієнтованих сервісів. 
3. Розробка веб-орієнтованого сервісу для пошуку місць відпочинку, який 
задовольняє таким функціональним вимогам: 
– реєстрація нових та авторизація існуючих користувачів; 
– перегляд місць та закладів відпочинку у вибраному місті; 
– перегляд місць та закладів відпочинку у вибраній категорії; 
– додавання місць та закладів, які сподобались до списку «обраного»; 
– можливість для адміністратора виконувати CRUD-операції над місцями та 
закладами відпочинку; 
– можливість для адміністратора виконувати CRUD-операції над користувачами. 
Висновки до розділу 1 
У даному розділі досліджено предметну область, а саме: пошук місць 
відпочинку за допомогою веб-орієнтованого сервісу; огляд існуючих аналогів для 
пошуку місць відпочинку.  
Виконано порівняльний аналіз існуючих рішень розглянутих реалізацій для 
пошуку місць відпочинку, таких як: «UaHotels», «RestOn», «Reservble», «Theatre», 
«QUESTROOM» та «Hotels24».  
Визначено постановку завдання кваліфікаційної роботи бакалавра. 
 
 23 
2 ПРОЄКТУВАННЯ ТА РОЗРОБКА ВЕБ-ОРІЄНТОВАНОГО СЕРВІСУ ДЛЯ 
ПОШУКУ МІСЦЬ ВІДПОЧИНКУ 
2.1  Опис функціонального програмного середовища для розробки 
Розробку веб-орієнтованого сервісу для пошуку місць відпочинку було 
розділено на дві основні частини – розробка backend частини та frontend частини. Для 
створення backend частини обрано мову програмування Java та її фреймворк Spring, 
а для frontend частини – JavaScript-бібліотеку React. Для розробки backend частини 
було обрано IntelliJ Idea, для frontend частини – WebStorm. Розглянемо детальніше 
технології, програмні середовища та їх особливості для розробки веб-орієнтованого 
сервісу для пошуку місць відпочинку. 
2.1.1 Опис програмного середовища IntelliJ Idea. IntelliJ IDEA – це 
інтегроване середовище розробки (IDE), створене компанією JetBrains, яке 
використовується для розробки програмного забезпечення на різних мовах 
програмування, включаючи Java, Kotlin, Groovy, Scala, Python, PHP та інші. Система 
поставляється у вигляді урізаної по функціональності безкоштовної версії 
«Community Edition» і повнофункціональної комерційної версії «Ultimate Edition», 
для якої активні розробники відкритих проектів мають можливість отримати 
безкоштовну ліцензію. Програмний код Community-версії поширюються рамках 
ліцензії Apache 2.0. Бінарні збірки підготовлені для Linux, Mac OS X і Windows [10].  
Community-версія IntelliJ IDEA обладнана інструментами у вигляді плагінів для 
тестування з використанням TestNG та JUnit, систем контролю версій, таких як CVS, 
Subversion, Mercurial і Git, інструментів збирання Maven, Ant, Gradle, а також 
підтримкою мов програмування Java, Scala, Clojure, Groovy і Dart. Також вона 
забезпечує розробку додатків для мобільної платформи Android, включаючи модуль 
візуального проєктування GUI-інтерфейсу Swing UI Designer, XML-редактор, 
редактор регулярних виразів, систему перевірки коду на коректність, систему 
контролю виконання завдань і додатки для імпорту та експорту проєктів з Eclipse. 
 
 24 
Крім цього, доступні інструменти інтеграції з системами відстеження помилок, 
такими, як: JIRA, Trac, Redmine, Pivotal Tracker, GitHub, YouTrack і Lighthouse. 
У свою чергу, комерційна версія «Ultimate Edition» відрізняється наявністю 
підтримки додаткових мов програмування, такими, як: PHP, Ruby, Python, JavaScript, 
CoffeeScript, HTML, CSS, SQL, підтримкою технологій Java EE, UML-діаграм, 
підрахунком покриття коду тестами, можливістю роботи з фреймворками, такими, як: 
Rails, Grails, Google Web Toolkit, Spring Framework, Play Framework і Hibernate, а 
також інструментами інтеграції з Perforce, Microsoft Team Foundation Server і Rational 
ClearCase [10]. 
Іншими словами: «Community Edition» – безкоштовна, підходить для основних 
мов програмування та інструментів, «Ultimate Edition» – платна, розширює 
можливості для веб-розробки, Java EE, фреймворків та інтеграції. 
Особливості IntelliJ Idea [11]: 
З кожним оновленням додаються нові функції та розширюються можливості 
цього середовища програмування. На даний момент є такі основні функції: 
– автодоповнення та підказки. IntelliJ IDEA пропонує контекстно-залежне 
автодоповнення та підказки для коду, змінних, методів та інших елементів; 
– перевірка помилок на льоту. IDE перевіряє код користувача на наявність 
помилок під час введення, що допомагає вам писати більш якісний код; 
– рефакторинг коду. IntelliJ IDEA пропонує широкий спектр інструментів для 
рефакторингу коду, що дозволяє користувачу змінювати структуру свого коду без 
порушення його функціональності; 
– форматування коду. IDE може форматувати код користувача згідно певного 
стилю; 
– підсвічування синтаксису. IDE підсвічує код різними кольорами, щоб зробити 
його більш читабельним; 
– покрокове виконання. IntelliJ IDEA дозволяє користувачу покроково 
виконувати код, щоб можна відстежувати його виконання та знаходити помилки; 
– перегляд значень змінних. Користувач може переглядати значення змінних та 
виразів під час налагодження; 
 
 25 
– стеження за виконанням програми. IDE дозволяє користувачу стежити за 
виконанням програми та бачити, які методи та класи використовуються; 
– інтеграція з Git, Subversion та Mercurial. IntelliJ IDEA інтегрується з системами 
контролю версій, що дозволяє користувачу відстежувати зміни у власному коді та 
співпрацювати з іншими розробниками; 
– функції історії версій. IDE пропонує різні функції для роботи з історією версій, 
такі як перегляд змін, відкат змін та злиття гілок; 
– генерація коду. IntelliJ IDEA може генерувати код для різних класів, методів, 
getter-setter methods, та інших елементів; 
– пошук та заміна. IDE пропонує потужні можливості пошуку та заміни тексту; 
– плагіни. Доступні плагіни для багатьох мов програмування, фреймворків та 
інструментів, що робить IntelliJ IDEA універсальним IDE. 
2.1.2 Опис програмного середовища WebStorm. WebStorm – це інтегроване 
середовище розробки (IDE) від JetBrains, спеціально розроблене для веб-розробників. 
Воно базується на платформі IntelliJ IDEA, але пропонує більш 
вузькоспеціалізований набір функцій, орієнтованих на роботу з JavaScript, HTML та 
CSS. WebStorm є спеціалізованою версією PhpStorm, пропонуючи підмножину з його 
можливостей. WebStorm постачається з перед-установленим плаґінами JavaScript 
(такими як для Node.js), котрі доступні для PhpStorm безкоштовно [13]. 
WebStorm пропонує широкий спектр інструментів для веб-розробки, роблячи 
процес створення та налагодження сайтів більш ефективним. Серед його ключових 
можливостей є: 
– автодоповнення коду JavaScript, HTML та CSS, що значно економить час при 
написанні коду; 
– аналіз коду на льоту з попередженням про помилки та потенційні проблеми, що 
допомагає утримувати код в чистоті та без помилок; 
– навігація по коду, що полегшує перехід до потрібних фрагментів коду та пошук 
необхідних функцій; 
– рефакторинг коду JavaScript, що дозволяє безпечно та легко вносити зміни в 
структуру коду, не ризикуючи його пошкодити; 
 
 26 
– налагодження коду JavaScript, що допомагає знаходити та виправляти помилки 
в коді; 
– інтеграція з системами управління версіями, що дозволяє відстежувати зміни в 
коді та спілкуватися з іншими розробниками. 
Важливою перевагою WebStorm є його гнучкість при роботі з проєктами. Він 
може обробляти JavaScript, розміщений у різних файлах, теках та навіть вкладений в 
HTML. WebStorm також підтримує множинну вкладеність кодів, що робить його 
ідеальним інструментом для роботи зі складними проєктами. В результаті WebStorm 
є потужним та багатофункціональним IDE, що може значно підвищити 
продуктивність веб-розробників [14]. 
Особливості WebStorm [14]: 
– автодоповнення та підказки. WebStorm пропонує контекстне автодоповнення та 
підказки для всіх основних веб-технологій, включаючи JavaScript, TypeScript, HTML, 
CSS, JSON та багато інших; 
– перевірка коду на льоту. IDE постійно аналізує код користувача на наявність 
помилок і попереджає про них у міру їх виявлення; 
– рефакторинг: WebStorm пропонує широкий спектр інструментів рефакторингу, 
які допоможуть користувачу покращити структуру та читабельність свого коду; 
– навігація по коду. IDE полегшує перехід до будь-якої частини коду користувача 
за допомогою таких функцій, як швидкий перехід до символу, перехід до оголошення 
та перегляд ієрархії класів; 
– відладка. WebStorm пропонує потужний вбудований відладчик, який дозволяє 
користувачу покроково виконувати код, переглядати значення змінних та стеки 
викликів; 
– системи контролю версій. WebStorm підтримує всі популярні системи 
контролю версій, такі як: Git, SVN та Mercurial; 
– фреймворки та бібліотеки. IDE пропонує вбудовану підтримку для багатьох 
популярних веб-фреймворків та бібліотек, такі як: React, Angular, Vue.js, Node.js та 
багато інших; 
 
 27 
– термінали. IDE має вбудований термінал, який дозволяє користувачу запускати 
команди командного рядка; 
– тестування. WebStorm може допомогти користувачу написати та запустити 
модульні тести для власного коду. 
2.1.3 Опис мови програмування Java та фреймворку Spring. Java – це 
високорівнева, об'єктно-орієнтована мова програмування на основі класів, яка 
розроблена з якомога меншою залежністю реалізації [8]. Це мова програмування 
загального призначення, призначена для того, щоб розробники програм могли писати 
один раз, а запускати їх де завгодно (WORA – Write Once, Run Anywhere), що означає, 
що скомпільований код Java може працювати на всіх платформах, що підтримують 
Java, без необхідності перекомпіляції.  
Програми Java, зазвичай, компілюються в байт-код, який може працювати на 
будь-якій віртуальній машині Java, незалежно від базової архітектури комп'ютера. 
Синтаксис Java подібний до C та C ++, але має менше засобів низького рівня, ніж 
будь-який з них. Час виконання Java забезпечує динамічні можливості (наприклад, 
відображення та модифікацію коду середовища виконання), які, як правило, 
недоступні в традиційних компільованих мовах [8]. 
Java була розроблена Джеймсом Гослінгом у Sun Microsystems, потім була 
придбана Oracle та випущена в 1995 році як основний компонент Java-платформи Sun 
Microsystems. Оригінальні та довідкові реалізатори Javaкомпілятори, віртуальні 
машини та бібліотеки класів були спочатку випущені Sun під власними ліцензіями.  
Станом на травень 2007 року, згідно з вимогами процесу спільноти Java, Sun 
здійснила ліцензію на більшість своїх технологій Java під загальною публічною 
ліцензією GNU. Oracle пропонує власну віртуальну машину HotSpot Java, однак 
офіційним посиланням є OpenJDK JVM, яке є безкоштовним програмним 
забезпеченням з відкритим кодом і використовується більшістю розробників і є JVM 
за замовчуванням для майже всіх дистрибутивів Linux. 
У створенні мови Java було п’ять основних цілей [8]:  
− синтаксис має бути простим, об’єктно-орієнтованим та звичним;  
− Java має бути нейтральною до архітектури та портативною;  
 
 28 
− присутня висока продуктивність;  
− мова повинна бути надійною, інтерпретованою, різьбовою та динамічною. 
Стандартні бібліотеки забезпечують загальний спосіб доступу до особливостей 
хоста, таких як: графіка, створення потоків та створення мереж. Використання 
універсального байт-коду спрощує перенесення. Однак, накладні витрати на 
інтерпретацію байт-коду в машинних інструкціях робили інтерпретовані програми 
майже завжди більш повільними, ніж власні виконувані файли. Компілятори, які 
компілюють байт-коди до машинного коду під час виконання, були введені з ранньої 
стадії [8].  
Сама Java не залежить від платформи і пристосована до конкретної платформи, 
на якій вона повинна працювати віртуальною машиною Java для неї, яка переводить 
байт-код Java на машинну мову платформи. Критика, спрямована на Java, включає 
реалізацію дженериків, швидкість, обробку непідписаних чисел, реалізацію 
арифметики з плаваючою крапкою та історію вразливих місць безпеки у первинній 
реалізації JVM HotSpot [8]. 
Spring Framework, або просто Spring – це дуже популярний фреймворк з 
відкритим кодом для розробки Java-додатків, особливо веб-додатків. Він пропонує 
набір інструментів та функціональних можливостей, які допомагають писати чистий, 
модульний та керований код [9]. 
Spring Framework складається з різних модулів, які надають широкий спектр 
послуг, зокрема: доступ до даних, безпека, обробка транзакцій, тестування та багато 
іншого. У Spring є декілька основних особливостей [9]: 
– контейнер залежностей (Dependency Injection). Spring використовує концепцію 
залежності ін'єкції, яка допомагає керувати залежностями між різними частинами 
вашого додатку. Замість того, щоб вручну створювати об'єкти, Spring керує їх 
життєвим циклом та ін'єктує їх у ваші класи, роблячи ваш код більш вільним та 
придатним для тестування; 
– інверсія управління (Inversion of Control). Тісно пов'язана з залежністю ін'єкції, 
інверсія управління означає, що замість того, щоб код користувача керував тим, як 
 
 29 
створюються та об'єднуються об'єкти, Spring бере на себе цю відповідальність. Це 
робить код користувача більш декларативним та легшим у підтримці; 
– модульність. Spring заохочує модульний підхід до розробки. Додаток можна 
розділити на окремі компоненти, які легко тестувати, повторно використовувати та 
обслуговувати; 
– аспекти (Aspects). Spring підтримує аспектно-орієнтоване програмування 
(AOP), яке дозволяє відокремлювати поперечні функціональні можливості, такі як 
безпека, від основної бізнес-логіки додатку користувача.  
Загалом, Spring Framework пропонує багато переваг для розробників Java. Він 
може допомогти писати більш чистий, модульний та керований код, що призводить 
до більш надійних та масштабованих додатків. 
2.1.4 Опис бібліотеки React. React – це JavaScript-бібліотека з відкритим 
кодом, розроблена компанією Facebook для створення інтерактивних інтерфейсів 
користувача. Вона використовується для побудови веб-додатків з високою 
продуктивністю та зручністю використання.  
React створив Джордан Уолк, програміст з Facebook. На нього вплинув XHP, 
фреймворк HTML для PHP. Вперше React з'явився у новинах Facebook 2011 року, а 
через рік – у блозі Instagram. У травні 2013 року фреймворк представили як проект з 
відкритим кодом на конференції розробників JSConf US у США. У березні 2015 року 
на React.js Conf, організованій Facebook, проект офіційно представили як відкрите 
програмне забезпечення [15]. 
React дає можливість розробникам створювати масштабні веб-застосунки, що 
оновлюються без перезавантаження сторінки. Він прагне бути швидким, простим та 
масштабованим. React оперує виключно користувацьким інтерфейсом у застосунках, 
відповідаючи за "вид" у шаблоні MVC. Його можна використовувати як самостійно, 
так і в поєднанні з іншими JavaScript-бібліотеками чи фреймворками MVC, на кшталт 
AngularJS. React також інтегрується з надбудовами, що роблять за нього рутинну 
роботу з UI. Найчастіше React використовується в тандемі з іншими бібліотеками, як-
от Redux [15]. 
Особливості React [16]: 
 
 30 
– компоненти. React використовує компонентний підхід до побудови 
інтерфейсів. Кожен компонент – це самодостатня частина інтерфейсу, яка має свою 
логіку та візуальне представлення. Це робить код більш модульним, організованим та 
зручним для повторного використання; 
– JSX. React використовує JSX (JavaScript XML) – синтаксичне розширення 
JavaScript, яке дозволяє описувати візуальні елементи інтерфейсу в більш зручному 
та зрозумілому форматі. JSX поєднує HTML-подібний синтаксис з JavaScript, що 
робить код більш читабельним та лаконічним; 
– Virtual DOM. React використовує віртуальний DOM (Document Object Model) – 
уявлення DOM-дерева в пам'яті JavaScript. Це дозволяє React значно оптимізувати 
оновлення інтерфейсу, роблячи його більш плавним і швидким. Virtual DOM 
порівнює віртуальне представлення інтерфейсу з його поточним станом у DOM 
браузера та оновлює лише ті частини, які дійсно змінилися; 
– односторонній потік даних. React використовує односторонній потік даних. 
Дані передаються від батьківських компонентів до дочірніх компонентів через props. 
Це робить код більш зрозумілим, керованим та прогнозованим. Дані не можуть 
змінюватися дочірніми компонентами, що робить код більш стійким до помилок; 
– різноманіття інструментів. Існує багато інструментів, які можна 
використовувати з React, таких як Babel, Webpack, Jest, Storybook та інші. Ці 
інструменти допомагають розробникам писати більш якісний код, тестувати його та 
оптимізувати його для кращої продуктивності; 
– гнучкість. React можна використовувати для створення будь-яких інтерфейсів 
користувача, від простих до складних. React не нав'язує жорстких правил, що робить 
його дуже гнучким та адаптованим до різних потреб; 
– швидкість. React – це дуже швидка бібліотека. Використання віртуального 
DOM та інших оптимізацій робить React-додатки дуже плавними та чутливими. 
У React-компонентів є свій життєвий цикл, який складається з трьох етапів, на 
кожному з яких спрацьовує метод useEffect(): 
– монтування. Це початковий етап, на якому екземпляр компоненту створюється 
та вставляється в DOM. Метод useEffect() викликається після того, як компонент 
 
 31 
відобразився на екрані. Використовується для виконання побічних ефектів після 
першого рендерингу. В цьому методі можна проводити підписки на дані або 
виконувати інші дії, які потребують доступу до DOM; 
– оновлення. Метод useEffect() викликається після кожного оновлення стану 
компоненту або його пропсів. Використовується для виконання побічних ефектів, які 
потрібно провести після кожного оновлення; 
– видалення. При видаленні компонента з DOM цей метод useEffect() 
викликається перед тим, як компонент буде видалено. Використовується для 
очищення підписок на дані або виконання інших дій, необхідних перед видаленням 
компоненту. 
На рис. 2.1 представлено життєвий цикл React-компоненту. 
 
Рисунок 2.1 – Життєвий цикл React-компоненту 
2.2 Основні принципи розробки веб-орієнтованого сервісу 
Створення веб-орієнтованого сервісу ґрунтується на декількох ключових 
принципах. Завдяки цим принципам створюються ефективні та зручні для 
користувачів продукти. 
 
 32 
Основні принципи розробки веб-орієнтованого сервісу включають: 
– визначення цілей та аудиторії. Перш, ніж розпочати розробку додатку, важливо 
чітко визначити його цілі та аудиторію, до якої він призначений. Це допоможе 
зорієнтуватися при виборі функціональності, дизайну та інтерфейсу додатку; 
– клієнт-серверна архітектура. Цей принцип передбачає розділення функцій 
програмного забезпечення між клієнтом (зазвичай браузером або додатком) і 
сервером. Клієнти взаємодіють з сервером через мережу, зазвичай за допомогою 
HTTP протоколу. Це дозволяє ефективно розподіляти завдання та забезпечувати 
масштабованість; 
– REST (Representational State Transfer). REST є архітектурним стилем для 
розробки розподілених веб-систем. Він базується на ряді принципів, таких як 
ідентифікація ресурсів (URL), використання HTTP методів (GET, POST, PUT, 
DELETE) для взаємодії з ресурсами, безстанційність (клієнт не зберігає стан на 
сервері) та кешування; 
– мікросервісна архітектура. Цей підхід полягає в тому, щоб розбити додаток на 
невеликі, незалежні сервіси, які можуть бути розгорнуті, масштабовані та керовані 
окремо. Кожен мікросервіс відповідає за конкретний функціонал, що спрощує 
розробку, тестування та супровід; 
– ідентифікація та аутентифікація. Забезпечення безпеки та захисту інформації є 
ключовим принципом. Для цього використовуються різні методи ідентифікації та 
аутентифікації, такі як JWT (JSON Web Tokens), OAuth, аутентифікація за допомогою 
електронної пошти та паролів тощо; 
– масштабованість. Додаток повинен бути легко масштабованим, щоб 
відповідати зростаючим потребам користувачів. Це може бути досягнуто за 
допомогою горизонтального (додавання більшої кількості серверів) або 
вертикального (покращення ресурсів на існуючому сервері) масштабування; 
– дизайн інтерфейсу користувача. грамотний дизайн інтерфейсу користувача 
допомагає забезпечити зручність та естетичність додатку. Він повинен бути 
інтуїтивно зрозумілим, легким у використанні та відповідати принципам UX-дизайну 
для створення позитивного користувацького досвіду; 
 
 33 
– тестування та автоматизація. Важливо мати набір автоматизованих тестів для 
перевірки функціональності, надійності та безпеки сервісу. Автоматизовані засоби 
CI/CD (Continuous Integration/Continuous Deployment) допомагають забезпечити 
ефективний процес розробки та розгортання; 
– відповідальне використання ресурсів. При розробці веб-сервісу важливо 
враховувати вплив на навколишнє середовище та забезпечувати ефективне 
використання ресурсів, таких як електроенергія та обчислювальна потужність; 
– відкритість та інтеграція. Забезпечення можливості інтеграції з іншими 
системами та сервісами за допомогою API (Application Programming Interface) 
дозволяє розширити функціональність та зручність використання для користувачів. 
2.3 Архітектура веб-орієнтованого сервісу 
Архітектура веб-орієнтованих сервісів – це сукупність принципів, підходів і 
технологій, які використовуються для розробки і підтримки веб-сервісів. Ця 
архітектура, зазвичай, включає розподілені системи, що дозволяють взаємодіяти з 
клієнтами через мережу Інтернет. Веб-орієнтований сервіс складається з двох частин: 
backend та frontend (рис. 2.2). Для створення frontend частини використовується React 
– бібліотека мови JavaScript, а для створення backend частини використовується 
Spring Framework – фреймворк мови Java. 
 
Рисунок 2.2 – Взаємодія frontend з backend 
 
 34 
На рис. 2.3 представлено взаємодію складових backend частини. 
 
Рисунок 2.3 – Взаємодія складових backend частини 
2.3.1 Опис frontend частини сервісу. React використовується для створення 
динамічного та інтерактивного інтерфейсу користувача. Основними елементами 
frontend частини, розробленої за допомогою React, є компоненти.  
Компоненти дозволяють розділити інтерфейс користувача на незалежні 
частини, придатні до повторного використання, і сприймати їх як такі, що 
функціонують окремо один від одного. Компоненти можуть посилатися на інші 
компоненти під час виведення. Це дозволяє користувачу використовувати одну і ту ж 
абстракцію компонентів для будь-якого рівня деталізації. Кнопка, форма, діалогове 
вікно, екран: у React-додатках всі вони, зазвичай, виражаються як компоненти [16]. Є 
два типи компонентів: класові та функціональні. Класові компоненти є застарілими, 
тоді як функціональні – їх заміна. 
Для доповнення роботи компонентів використовуються хуки. Вони дозволяють 
вам використовувати стан та інші можливості React без написання класу. Основними 
хуками та такими, що часто використовуються є хуки useState та useEffect.  
useState – це хук, який викликається, щоб для того, щоб надати внутрішній стан 
компоненту. React буде зберігати цей стан між повторними рендерами. Виклик 
useState повертає дві речі: поточне значення стану та функцію, яка дозволяє 
оновлювати цей стан [16]. 
 
 35 
useEffect – це хук, який може можете виконувати побічні ефекти із функційного 
компонента. Він виконує таку ж саму роль, що і componentDidMount, 
componentDidUpdate та componentWillUnmount у React-класах, об’єднавши їх в 
єдиний API [16].  
2.3.2 Опис backend частини сервісу. В свою чергу Java Spring відповідає за 
обробку запитів від frontend частини, взаємодію з базою даних, забезпечення безпеки, 
автентифікації та авторизації користувачів. Spring складається з таких складових: 
– Spring Boot Application. Це стартова точка, яка налаштовує всю конфігурацію 
Spring, включаючи завантаження всіх бінів та налаштування сервлет-контейнера; 
– REST контролери. Це контролери Spring MVC або альтернативні анотації, які 
визначають HTTP ендпоінти, які обробляють запити від клієнтів. Методи контролерів 
обробляють HTTP-запити, викликають методи сервісів, обробляють дані та 
повертають результати; 
– сервіси. Це класи, які містять бізнес-логіку додатку. Ці сервіси реалізують 
функціональність, необхідну для обробки запитів. Вони можуть виконувати операції, 
такі як обробка даних, виклик зовнішніх API, маніпулювання базою даних тощо; 
– доступ даних. Це шар, компоненти якого відповідають за взаємодію з базою 
даних. Зазвичай використовуються Spring Data JPA або Hibernate для спрощення 
роботи з базою даних, забезпечуючи ORM (Object-Relational Mapping) із базою даних; 
– безпека. Це шар, компоненти якого забезпечують аутентифікацію та 
авторизацію користувачів. Використовується Spring Security для налаштування прав 
доступу до ендпоінтів, обробки аутентифікації користувачів, управління сеансами 
тощо; 
– обробка винятків. Обробка винятків та помилок, що виникають під час обробки 
запитів. Використовується для коректного повернення HTTP статусів та повідомлень 
про помилки клієнту; 
– логування та моніторинг. Логування дій, які відбуваються в системі, для 
налагодження, моніторингу та відстеження проблем. Може використовуватися 
Logback або Log4j для логування подій. 
Взаємодія складових backend частини представлена на рис. 2.4. 
 
 36 
 
Рисунок 2.4 – Взаємодія складових backend частини 
2.4 Розробка діаграми варіантів використання 
Діаграма варіантів використання (Use Case Diagram) є важливим елементом при 
плануванні проєкту, оскільки вона просто демонструє взаємодію між акторами та 
прецедентами. Це найпростіша форма поведінкової діаграми. Створення такої 
діаграми надає інформацію про функціонал майбутньої системи та показує, як актори 
можуть взаємодіяти з цією системою. При створенні діаграми використовується актор 
«User», який описує особу, що обирає певну систему та має намір з нею взаємодіяти. 
Після визначення всіх потенційних користувачів системи формується перелік 
можливих сценаріїв їхньої взаємодії з цією системою. 
У кваліфікаційній роботі бакалавра була створена діаграма Use Case на основі 
інформації про користувачів додатку та потенційних сценаріїв взаємодії. На діаграмі 
представлено два типи користувачів та три типи взаємодій: зеленим кольором 
позначені загальні дії, синім – дії, які може виконувати тільки користувач «Admin». 
Варіанти використання веб-орієнтованого сервісу: 
– реєстрація; 
 
 37 
– авторизація; 
– перегляд списків готелів, кінотеатрів, театрів; 
– пошук за назвою; 
– фільтрація інформації, яка відображається за параметрами; 
– додавати місця, які сподобались до списків улюблених; 
– зміна власної інформації користувача; 
– підтримка сервісу; 
– підтримка користувачів; 
– додавання нової, редагування та видалення існуючої інформації. 
На основі сформованих даних про акторів та всі можливі варіанти використання 
веб-орієнтованого сервісу, побудовано діаграму варіантів використання Use Case 
(рис. 2.5). 
  
Рисунок 2.5 – Діаграма варіантів використання Use Case  
          2.5 Проєктування бази даних 
Проєктування структури бази даних (БД) є невід'ємною частиною розробки 
програмного забезпечення. Ефективна структура бази даних гарантує ефективне 
зберігання, доступ і оновлення даних.  
 
 38 
Потрібно визначити, які дані необхідно буде зберігати в БД, як вони пов'язані 
між собою та як будуть використовуватись. Для цього використовуються сутності – 
основні екземпляри об'єктів, для яких будуть зберігатись дані в БД. Наприклад, якщо 
створюється сайт для перегляду фільмів, то сутностями можуть бути «користувач», 
«фільм», «категорії» і т.д. 
Кожна сутність має свої атрибути, які описують її властивості. Наприклад, у 
сутності «фільм» можуть бути такі атрибути: «назва», «дата випуску», «режисер», 
«актори» і т.д. 
Визначення взаємозв'язків між сутностями є важливим аспектом проєктування 
бази даних. Відношення можуть бути один-до-одного, один-до-багатьох або багато-
до-багатьох. Наприклад, дата випуску може мати відношення один-до-багатьох з 
фільмами, тому що в одну дату може вийти багато фільмів. 
Під час проєктування БД важливо вибрати правильні типи даних для кожного 
атрибуту. Наприклад, дані представлені числами можуть бути представлені типом 
INTEGER або DOUBLE, залежно від типу числа, а текстові дані – типом VARCHAR 
або TEXT, залежно від довжини тексту. Також при проєктуванні структури БД для 
атрибутів можна встановити чи мають вони бути унікальними, чи можуть бути 
пустими, початкове значення, розмір і т.д. На основі визначених сутностей, атрибутів 
та відношень створюються таблиці бази даних. Кожна таблиця представляє сутність, 
а кожен атрибут стає стовпчиком. Зв'язки між таблицями встановлюються за 
допомогою зовнішніх ключів. 
Для поліпшення продуктивності запитів до бази даних створюються 
ідентифікатори. Ідентифікатори допомагають швидко знаходити дані за певними 
стовпчиками і прискорюють операції пошуку. Важливо забезпечити цілісність даних 
в базі даних. Це включає в себе встановлення правил перевірки даних, обмежень 
цілісності та використання транзакцій для збереження консистентності даних. 
Для створення backend частини в кваліфікаційній роботі бакалавра обрано базу 
даних PostgreSQL. 
PostgreSQL також відомий як Postgres – це вільна об'єктно-реляційна система 
керування базами даних (СКБД) з відкритим кодом. Її розробка розпочалася в 1987 
 
 39 
році в Каліфорнійському університеті Берклі, і з того часу вона постійно 
вдосконалюється та доповнюється [17]. 
PostgreSQL може використовуватися для широкого спектру завдань, 
включаючи [17]: 
– веб-сайти та веб-додатки. PostgreSQL може використовуватися для зберігання 
даних для веб-сайтів та веб-додатків; 
– електронна комерція. PostgreSQL може використовуватися для зберігання 
даних про замовлення, продукти та клієнтів для систем електронної комерції; 
– CRM-системи. PostgreSQL може використовуватися для зберігання даних про 
клієнтів та контактів для CRM-систем; 
– системи управління контентом. PostgreSQL може використовуватися для 
зберігання даних для систем управління контентом (CMS); 
– аналітика даних. PostgreSQL може використовуватися для зберігання та аналізу 
даних. 
Переваги PostgreSQL [17]: 
– відкритий код. Доступність коду PostgreSQL дозволяє вільно використовувати, 
модифікувати та розповсюджувати СКБД. Це робить її привабливим вибором для 
організацій, які прагнуть до незалежності від комерційних постачальників 
програмного забезпечення; 
– надійність. PostgreSQL має репутацію надзвичайно стійкої СУБД. Завдяки 
злагодженій роботі та високій доступності, вона може використовуватися для 
критично важливих систем; 
– функціональність. PostgreSQL пропонує широкий спектр функцій; 
– підтримка SQL. PostgreSQL використовує мову SQL для доступу до даних, що 
робить її сумісною з багатьма іншими СУБД; 
– об'єктно-реляційні можливості. PostgreSQL підтримує такі об'єктно-орієнтовані 
концепції, як класи, успадкування та поліморфізм; 
– розширюваність. PostgreSQL можна розширювати за допомогою додаткових 
модулів, що дає можливість додавати нові функції та можливості; 
 
 40 
– потужні інструменти. PostgreSQL пропонує широкий спектр інструментів для 
адміністрування, моніторингу та оптимізації роботи бази даних; 
– гнучкість. PostgreSQL може працювати на різних платформах, включаючи 
Linux, Windows, macOS та Unix; 
– активна спільнота. PostgreSQL має велику та активну спільноту користувачів і 
розробників, які надають підтримку та вносять свій вклад у розвиток СУБД. 
Недоліки PostgreSQL: 
– складність. PostgreSQL може бути складною для вивчення та адміністрування, 
порівняно з деякими іншими СУБД; 
– продуктивність. PostgreSQL може бути не такою швидкою, як деякі інші СКБД; 
– підтримка. Комерційні СКБД, як правило, пропонують кращу підтримку, ніж 
PostgreSQL, яка має децентралізовану модель підтримки. 
В Додатку Г представлено: структуру БД; таблиці – користувачів; областей; 
міст; готелів; кінотеатрів; театрів. 
2.6 Опис процесу проєктування структури веб-орієнтованого сервісу для 
пошуку місць відпочинку 
У кваліфікаційній роботі бакалавра, крім опису предметної області та вибору 
програмно-технічних засобів, важливим аспектом є реалізація веб-орієнтованого 
сервісу для пошуку місць відпочинку. Щоб представити функціонал сервісу, потрібно 
виділити наступні процеси: 
– процес реєстрації користувача; 
– процес авторизації користувача; 
– процес виведення інформації; 
– процес пошуку; 
– процес додавання нової інформації; 
– процес зберігання місця в списку улюблених. 
 
 41 
Процес реєстрації користувача (рис. 2.6) є одним з найголовніших процесів. Для 
реєстрації користувача потрібно: ввести дані; перевірити їх на валідність; зберегти 
дані до БД. 
 
Рисунок 2.6 – Діаграма процесу реєстрації користувача 
Процес авторизації користувача (рис. 2.7) є не менш важливим із процесів 
додатку, так як кожен користувач повинен мати свою сторінку, де він може зберігати 
особисту інформацію. Для авторизації користувача потрібно: ввести дані; перевірити 
їх на валідність; підтвердити авторизацію. 
 
Рисунок 2.7 – Діаграма процесу авторизації користувача 
 
 42 
Провівши аналіз ресурсів для пошуку місць відпочинку, в кваліфікаційній 
роботі бакалавра було обрано структуру веб-орієнтованого сервісу для пошуку місць 
відпочинку, що складається з таких розділів: 
– головна сторінка; 
– сторінка реєстрації користувача; 
– сторінка реєстрації користувача; 
– каталог місць для відпочинку; 
– сторінка з повною інформацією про місце відпочинку; 
– профіль користувача; 
– сторінка адміністратора для додавання та зміни інформації в БД. 
Структура веб-орієнтованого сервісу для пошуку місць відпочинку 
представлена на рисунку 2.8. Зеленим кольором позначені сторінки, які доступні всім 
користувачам, синім – тільки адміністраторам. 
 
Рисунок 2.8 – Структура веб-орієнтованого сервісу для пошуку місць відпочинку 
          2.7 Проєктування інтерфейсу користувача 
Під час виконання кваліфікаційної роботи бакалавра потрібно розробити 
макети сторінок, які забезпечать зручну, зрозумілу та легку роботу з сервісом. Для 
виконання цього завдання було обрано онлайн-інструмент «NinjaMock». 
 
 43 
NinjaMock – це онлайн-інструмент для створення прототипів та макетів 
інтерфейсів користувача, який підходить як для  індивідуальних розробників, так і 
для команд. Він пропонує широкий спектр функцій, що робить його потужним та 
зручним інструментом для візуалізації та тестування дизайну інтерфейсу [18]. 
Основні можливості NinjaMock [18]: 
– векторний редактор. NinjaMock має вбудований векторний редактор, який 
дозволяє використовувати різні форми, криві та інструменти для створення макетів. 
Це дає більше гнучкості та контролю над дизайном інтерфейсу; 
– багата бібліотека іконок. NinjaMock пропонує велику бібліотеку іконок, які 
можна використовувати в ваших макетах. Також можна створювати власні іконки за 
допомогою векторного редактору; 
– співпраця в реальному часі. NinjaMock дозволяє декільком користувачам 
працювати над одним проєктом одночасно. Це робить його ідеальним інструментом 
для команд, які хочуть спільно розробляти інтерфейси; 
– коментарі та зворотний зв'язок. NinjaMock має вбудовану систему коментарів, 
яка дозволяє користувачу отримувати відгуки про його макети від інших 
користувачів; 
– експорт в різні формати. NinjaMock можна експортувати макети користувача в 
різні формати, такі як PDF, PNG та HTML. Це робить їх легкими для демонстрації та 
обговорення. 
Переваги NinjaMock [18]: 
– простота використання. NinjaMock має простий та інтуїтивно зрозумілий 
інтерфейс, який робить його доступним навіть для новачків; 
– гнучкість. NinjaMock пропонує широкий спектр функцій, які дозволяють 
користувачу створювати макети будь-якої складності; 
– співпраця. NinjaMock робить співпрацю над проєктами простою та зручною; 
Недоліки NinjaMock: 
– обмежена функціональність безкоштовного плану. Безкоштовний план 
NinjaMock обмежує користувача 200 елементами в одному проєкті. Це може бути 
недостатньо для більш складних проєктів; 
 
 44 
– немає можливості створювати інтерактивні прототипи. NinjaMock дозволяє 
створювати візуальні макети, але не дає можливості створювати інтерактивні 
прототипи; 
– відсутність деяких поширених функцій. NinjaMock не має деяких функцій, які 
є в інших інструментах для створення прототипів, таких як можливість створювати 
анімації та переходи; 
– невелика спільнота. У NinjaMock не така велика спільнота, як у деяких інших 
інструментів для створення прототипів. Це може ускладнити пошук допомоги та 
підтримки. 
Для реалізації поставленої задачі кваліфікаційної роботи бакалавра за 
допомогою онлайн-інструменту «NinjaMock» були розроблені прототипи макетів для 
сторінок: входу, реєстрації, каталогу, сторінки детальної інформації та сторінки 
профілю користувача (рис. 2.9 – 2.13). 
 
Рисунок 2.9 – Вікно сторінки входу 
При розробці сторінок реєстрації та авторизації зосереджено увагу на простоті 
інтерфейсу, що робить ці процеси зрозумілими у використанні. 
 
 45 
 
Рисунок 2.10 – Вікно сторінки реєстрації 
 
Рисунок 2.11 – Вікно каталогу місць відпочинку 
При розробці сторінок для відображення інформації концентровано увагу на 
зручності пошуку та перегляду інформації. Для цього зроблено інтерфейс з великими 
елементами. 
 
 46 
 
Рисунок 2.12 – Вікно з детальною інформацією про місце відпочинку 
 
Рисунок 2.13 – Вікно сторінки профілю користувача 
Отже, інтерфейс сторінок користувача доволі легкий та інтуїтивно-зрозумілий. 
Тому, користувач з легкістю може користуватись сервісом так шукати місця для 
відпочинку. 
 
 47 
Висновки до розділу 2 
У даному розділі представлено опис функціонального програмного середовища 
для розробки веб-орієнтованого сервісу для пошуку місць відпочинку, а також 
досліджено основні принципи створення веб-орієнтованих сервісів та бази даних. 
Розроблена діаграма Use Case на основі інформації про користувачів веб-
орієнтованого сервісу для пошуку місць відпочинку. 
За допомогою онлайн-інструменту NinjaMock розроблений прототип веб-
орієнтованого сервісу для пошуку місць відпочинку. 
  
 
 48 
3 ПРОГРАМНА РЕАЛІЗАЦІЯ ТА ТЕСТУВАННЯ ВЕБ-ОРІЄНТОВАНОГО 
СЕРВІСУ ДЛЯ ПОШУКУ МІСЦЬ ВІДПОЧИНКУ 
3.1 Постановка завдання 
Завданням кваліфікаційної роботи бакалавра є створення веб-орієнтованого 
сервісу для пошуку місць відпочинку. 
Сервіс буде створено з використанням мови програмування Java для написання 
backend частини сервісу, а для написання frontend частини сервісу буде 
використовуватись мова розмітки гіпертексту HTML, спеціальна мова стилю 
сторінок CSS та мова написання сценаріїв сторінок JavaScript. 
Для цього розроблені сторінки для перегляду каталогів з готелями, 
кінотеатрами та театрами, сторінки для перегляду більш детальної інформації про 
готель, кінотеатри чи театр, сторінки для входу та реєстрації користувача, сторінка 
профілю користувача та «шапка» сайту для зручності навігації між сторінками. Також 
передбачена можливість додавати обрані місця до списків обраного, які 
відображаються на сторінці профілю. 
Для зручності адміністратору створено додаткові сторінки для керування 
вмістом та даними сайту. 
Для користування сервісом потрібний доступ до Інтернету. 
Основні класи, з яких складається backend частина веб-орієнтованого сервісу, 
зображено на рис. 3.1. 
Тут представлено класи, які описують роботу функціоналу користувачів та 
адміністратора, обробки даних та зв’язку з БД. Для зручності навігації класи розділені 
на окремі папки згідно їх функціоналу. 
 
 
 49 
 
Рисунок 3.1 – Класи backend частини 
 
 50 
3.2 Інтерфейс веб-орієнтованого сервісу для пошуку місць відпочинку 
Розглянемо основні компоненти, з яких складається frontend частина веб-
орієнтованого сервісу (рис. 3.2). 
 
Рисунок 3.2 – Компоненти frontend частини 
Весь інтерфейс веб-сервісу записується в компоненти у вигляді .js файлів. 
Кожен компонент знаходиться в папці з такою самою назвою як і в компонента. 
Наприклад, у папці «Cinema» знаходиться компонент з назвою «Cinema.js».  
 
 51 
Кожен компонент описує функціонал елементів сторінки, структуру 
розташування елементів на сторінці, функціонал запитів до серверу для отримання 
інформації та розподіляє, як та в яких елементах буде відображатись інформація 
отримана із запитів. 
Всі компоненти викликаються та відображаються всередині головного 
компоненту під назвою «App». В компоненті «App» вказуються шляхи та 
компоненти, які відображатимуться при введені відповідного шляху. Ці шляхи 
відображаються в адресному рядку браузера. 
3.3 Програмна реалізація веб-орієнтованого сервісу для пошуку місць 
відпочинку 
Всю роботу backend частини веб-орієнтованого сервісу виконують класи та 
інтерфейси. Під час створення backend частини веб-орієнтованого сервісу всі класи 
та інтерфейси було поділено на дев’ять основних директорій відповідно до 
функціоналу класу чи інтерфейсу, а саме: моделі, мапери, репозиторії, контролери, 
сервіси, класи безпеки, винятки, конфігураційні класи та класи з допоміжним 
функціоналом. Також сюди належить основний клас для запуску серверу 
«ApplicationStarter». Основні директорії та основний клас «ApplicationStarter» 
зображено на рис. 3.3. 
 
Рисунок 3.3 – Основні директорії backend частини    
 
 52 
Моделі – це класи, які описують властивості об’єктів для роботи з даними, які 
зберігаються в БД.  
На рис. 3.4 зображено приклад моделі під назвою «User» для роботи з даними 
користувача. 
 
Рисунок 3.4 – Приклад моделі 
Мапери – це інтерфейси та абстрактні класи, які перетворюють об’єкт моделі у 
вигляд об’єкту, який відправляється до frontend частини і навпаки.  
На рис. 3.5 зображено приклад мапера під назвою «CityMapper».  
 
Рисунок 3.5 – Приклад мапера 
Метод toDto перетворює об’єкт моделі в об’єкт, який відправляється до 
клієнтської частини веб-орієнтованого сервісу, а метод toEntity – навпаки, метод 
 
 53 
toEntities перетворює масив об’єктів моделі в масив об’єктів, які підправляються до 
клієнтської частини. 
Репозиторії – це інтерфейси, які відповідають за отримання даних з БД.  
На рис. 3.6 зображено приклад репозиторія під назвою «UserRepository». 
 
Рисунок 3.6 – Приклад  репозиторія 
Метод findFirstByUuid шукає можливого користувача за його унікальним 
ідентифікатором користувача, метод findFirstByEmail шукає можливого користувача 
за адресою його електронної пошти, метод deleteById видаляє користувача з БД. 
Контролери – це класи, які відповідають на запити на сервер.  
На рис. 3.7 зображено приклад контролера під назвою «HotelController». 
 
Рисунок 3.7 – Приклад контролера 
 
 54 
У даному контролері оголошено методи, які відповідають за додавання, зміну, 
отримання та видалення даних про готель або готелі з БД. 
Сервіси – це класи, які відповідають за зв’язок між контролерами та 
репозиторіями, а також реалізують функціонал методів оголошених в контролерах. 
На рис. 3.8 зображено приклад реалізації декількох методів сервісу під назвою 
«HotelService». 
 
Рисунок 3.8 – Приклад сервісу 
Метод getByUuid шукає в БД можливий запис про готель за його унікальним 
ідентифікатором. Якщо запис в БД не існує сервіс повертає про це помилку, якщо 
 
 55 
існує – сервіс отримує об’єкт з даними готелю та за допомогою мапера перетворю на 
об’єкт, який відправляється до клієнтської частини.  
Метод update отримує об’єкт з даними, які необхідно оновити в БД. Якщо 
запису про такий об’єкт в БД не існує, то сервіс повертає про це помилку, якщо існує, 
то сервіс зберігає зміни в БД.  
Метод delete шукає в БД можливий запис про готель за його унікальним 
ідентифікатором. Якщо запису про такий об’єкт в БД не існує, то сервіс повертає про 
це помилку, якщо існує, то сервіс видаляє цей запис. 
Класи безпеки – це класи, в яких описуються методи для шифрування паролів, 
створення токен безпеки, зберігання даних в токенах та отримання даних з токенів, 
налаштування авторизації і т.д. 
Конфігураційні класи – це класи, в яких описуються конфігурації певних 
аспектів веб-орієнтованого сервісу. 
Класи з допоміжним функціоналом – це класи, в яких описуються методи для 
певних дій, які можуть допомогти при роботі backend частини. Наприклад, клас для 
валідації даних. 
Також при створенні backend частини в кваліфікаційній роботі бакалавра 
використано додаткові ресурси для роботи з БД – створено .yaml файли, які 
відповідають за створення таблиць в БД, якщо їх немає під час запуску сервера.  
На рис. 3.9 зображено структуру додаткових ресурсів. 
 
Рисунок 3.9 – Додаткові ресурси 
 
 56 
У папці changeset знаходяться .yaml файли, в яких описана структура 
відповідної таблиці в БД. У файлі db.changelog-master.yaml описана послідовність за 
якою створюються таблиці, а в application.yml – додаткові параметри backend частини 
веб-орієнтованого сервісу, такі як: порт серверу, дані підключення до БД, дані 
створення токенів безпеки і т.д. 
3.4 Тестування backend частини веб-орієнтованого сервісу для пошуку 
місць відпочинку 
Тестування backend частини веб-орієнтованого сервісу є важливим та 
невід’ємним етапом розробки, який допомагає виявити помилки, перевірити 
функціонал та забезпечити якість сервісу перед його випуском. В кваліфікаційній 
роботі бакалавра для тестування backend частини веб-орієнтованого сервісу для 
пошуку місць відпочинку використано сервіс «Swagger». 
«Swagger» – це сервіс з набором інструментів, які дозволяють розробникам 
проектувати, документувати та тестувати АРІ, розроблений компанією SmartBear 
Softwear. На рис. 3.10 зображено сторінку сервісу «Swagger» з розділами для 
тестування запитів та запитами всередині розділів. 
 
Рисунок 3.10 – Сервіс «Swagger» 
 
 57 
Для створення розділів та додавання в них запитів для тестування всередині 
backend частини веб-орієнтованого сервісу створено файл open-api.yaml, в якому 
описано розділи та запити, а саме: шлях для звернення до запиту, розділ до якого він 
належить, що запит повинен отримувати і повертати.  
На рис. 3.11 зображено опис запиту реєстрації користувача. 
 
Рисунок 3.11 – Опис запиту реєстрації 
Запит приймає дані, які користувач вводить при реєстрації, та повертає об’єкт 
моделі User з даними, які збереглись в БД або повідомлення з помилкою в залежності 
від того, що не відповідає необхідним умовам для додавання даних в БД.  
На рис. 3.12 зображено розділ з запитами, які можна виконувати до серверу для 
взаємодії з таблицею користувачів в БД. 
 
 58 
 
Рисунок 3.12 – Розділ «User» з відповідними запитами 
Для тестування запиту реєстрації користувача створюється об’єкт з даними, які 
користувач вводить при реєстрації та надсилається запит на сервер (рис. 3.13).  
 
Рисунок 3.13 – Об’єкт з даними першого користувача 
В результаті отримується відповідь про успіх у вигляді об’єкту з даними, які 
збереглись в БД (рис. 3.14). 
Такий результат отримується при успішних сценаріях. Але для повної 
перевірки правильності роботи backend частини веб-орієнтованого сервісу необхідно 
перевіряти й невдалі сценарії в поверненням помилок. 
Для цього створюється об’єкт з даними іншого користувача, який вирішив 
спробувати використати електронну адресу, з якою вже створено обліковий запис 
(рис. 3.15). 
 
 59 
 
Рисунок 3.14 – Результат вдалого запиту 
 
Рисунок 3.15 – Об'єкт з даними другого користувача 
В такому випадку повертається об’єкт з помилкою, яка означає, що користувач 
з такою електронною адресою вже існує (рис. 3.16). 
За допомогою сервісу «Swagger» виконується тестування правильної роботи 
всіх запитів, які необхідні для повної роботи веб-орієнтованого сервісу, виявлення 
проблем та усунення несправностей перед випуском фінального продукту. 
 
 
 60 
 
Рисунок 3.16 – Результат невданого запиту 
Висновки до розділу 3 
У даному розділі представлена програмна реалізація розробленого веб-
орієнтованого сервісу для пошуку місць відпочинку. Визначено, що програма буде 
створена з використанням мови програмування Java для написання backend частини 
сервісу, а для написання frontend частини сервісу буде використовуватись мова 
розмітки гіпертексту HTML, спеціальна мова стилю сторінок CSS та мова написання 
сценаріїв сторінок JavaScript. 
Описано інтерфейс та програмну реалізацію розробленого веб-орієнтованого 
сервісу для пошуку місць відпочинку. 
Виконано тестування backend частини веб-орієнтованого сервісу для пошуку 
місць відпочинку. Результати тестування дозволяють зробити висновок про розробку 
веб-орієнтованого сервісу та його справну роботу. 
  
 
 61 
ВИСНОВКИ 
Мета кваліфікаційної роботи бакалавра досягнута, тобто в ході її виконання 
було спроєктовано та успішно розроблено веб-орієнтований сервіс для пошуку місць 
відпочинку. 
Для досягнення мети в роботі розглядалися наступні питання: 
– досліджено предметну область; 
– виконано порівняльний аналіз існуючих веб-орієнтованих сервісів, а саме: 
«UaHotels», «RestOn», «Reservble», «Theatre», «QUESTROOM» та «Hotels24»; 
– розроблено базу даних; 
– обрано програмно-технічні засоби та технології для реалізації поставленої 
задачі дослідження; 
– розроблено веб-орієнтований сервіс для пошуку місць відпочинку та виконано 
його тестування. 
Веб-орієнтований сервіс для пошуку місць відпочинку розроблений на мові 
програмування Java з використанням фреймворку Spring для створення backend 
частини та з використанням JavaScript-бібліотеки React для створення frontend 
частини. Створення та робота з базою даних відбувалась із застосуванням 
PostgreSQL. Контроль та написання коду backend частини проєкту здійснювалось у 
середовищі IntelliJ IDEA, frontend частини – у середовищі WebStorm. 
Обрані технології задовольняють всім функціональним і не функціональним 
вимогам до такого типу програмного забезпечення. 
Розроблений веб-орієнтований сервіс має приємний, зручний та інтуїтивно 
зрозумілий інтерфейс. 
 
 62 
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ 
1. Топ-10 найдивовижніших місць для відпочинку в Україні. URL: 
https://1plus1.ua/novyny/top-10-najdivoviznisih-misc-dla-vidpocinku-v-ukraini (дата 
звернення: 03.02.2024). 
2. Сервіс «UaHotels». URL: https://uahotels.info/ (дата звернення: 03.02.2024). 
3. Сервіс «RestOn». URL: https://reston.ua/kyiv_catalog/ (дата звернення: 
03.02.2024). 
4. Сервіс «Reservble». URL: https://www.reservble.com/ (дата звернення: 03.02.2024). 
5. Сервіс «Theatre». URL: https://theatre.com.ua/theaters (дата звернення: 10.02.2024). 
6. Сервіс «QUESTROOM». URL: https://questroom.com.ua/ua (дата звернення: 
10.02.2024). 
7. Сервіс «Hotels24». URL: https://hotels24.ua/ (дата звернення: 10.02.2024). 
8. Теоретичні відомості про мову програмування Java. URL: 
https://uk.wikipedia.org/wiki/Java (дата звернення: 06.04.2024). 
9. Документація для роботи з Java Spring Framework. URL: 
https://spring.io/projects/spring-framework (дата звернення: 06.04.2024). 
10. Теоретичні відомості про IntelliJ Idea. URL: 
https://uk.wikipedia.org/wiki/IntelliJ_IDEA (дата звернення: 06.04.2024). 
11. Розділ IntelliJ Idea на офіційному сайті JetBrains. URL: 
https://www.jetbrains.com/idea/ (дата звернення: 06.06.2024). 
12. Офіційний сайт React. URL: https://react.dev/ (дата звернення: 06.04.2024). 
13. Теоретичні відомості про WebStorm. URL: 
https://uk.wikipedia.org/wiki/WebStorm (дата звернення: 06.04.2024). 
14. Розділ WebStorm на офіційному сайті JetBrains. URL: 
https://www.jetbrains.com/webstorm/ (дата звернення: 06.04.2024). 
15. Теоретичні відомості про React. URL: https://uk.wikipedia.org/wiki/React (дата 
звернення: 06.06.2024). 
16. Офіційний сайт React. URL: https://react.dev/ (дата звернення: 06.04.2024). 
 
 63 
17. Офіційний сайт PostgreSQL. URL: https://www.postgresql.org/ (дата звернення: 
06.04.2024). 
18. Сайт інструменту NinjaMock. URL: https://ninjamock.com/ (дата звернення: 
06.04.2024). 
 
  
 
 64 
ДОДАТОК А 
        Затверджую               
Зав. кафедри КНСА, 
______________ Юрій ТРИУС 
«____»____________2024 р.                                                                                                                                                                              
 
 
 
 
 
 
 
ВЕБ-ОРІЄНТОВАНИЙ СЕРВІС ДЛЯ ПОШУКУ МІСЦЬ ВІДПОЧИНКУ 
 
Специфікація 482.ЧДТУ. 42291-01  
 
Листів 2 
 
 
 
 
 
 
Розробник                          ____________________                Кавун Д.Р. 
 
Керівник                             ____________________               Оксамитна Л.П. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Черкаси – 2024
 
 65 
482.ЧДТУ. 42291-01 
Позначення Найменування Примітка 
   
   
 Документація  
   
   
482.ЧДТУ. 42291-01    12 01 Текст програми  
482.ЧДТУ. 42291-01    34 01 Інструкція користувача  
482. ЧДТУ. 42291-01    90 01 Структура бази даних  
482.ЧДТУ. 42291-01     90 02 Публікація по темі  
кваліфікаційної роботи 
бакалавра 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
 
 66 
ДОДАТОК Б 
 
 
 
 
 
ВЕБ-ОРІЄНТОВАНИЙ СЕРВІС ДЛЯ ПОШУКУ МІСЦЬ ВІДПОЧИНКУ 
 
 
Текст програми 482.ЧДТУ. 42291-01 12 01 
 
Листів 27 
 
 
 
 
 
 
Розробник    _____________                   Кавун Д.Р. 
 
 
 
 
 
 
 
 
 
Черкаси – 2024  
 
 67 
Фрагмент програми 
Клас UserController: 
 
package com.ars.manager.controller; 
import com.ars.manager.service.UserService; 
import lombok.RequiredArgsConstructor; 
import org.openapitools.api.UserApi; 
import org.openapitools.model.JwtDto; 
import org.openapitools.model.UserDto; 
import org.springframework.security.access.prepost.PreAuthorize; 
import org.springframework.web.bind.annotation.CrossOrigin; 
import org.springframework.web.bind.annotation.RestController; 
import java.util.List; 
 
@RestController 
@CrossOrigin(origins = "http://localhost:3000") 
@RequiredArgsConstructor 
public class UserController implements UserApi { 
    private final UserService userService; 
 
    @Override 
    public UserDto addUser(UserDto userDto) { 
        return userService.add(userDto); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public Void deleteUserByUuid(String uuid) { 
        userService.delete(uuid); 
        return null; 
    } 
 
    @Override 
    public UserDto getUserByEmail(String email) { 
        return userService.getByEmail(email); 
    } 
 
    @Override 
    public UserDto getUserByUuid(String uuid) { 
        return userService.get(uuid); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public List<UserDto> getUsers(Integer page, Integer limit) { 
        return userService.getAllPages(page, limit); 
    } 
 
    @Override 
    public JwtDto login(UserDto userDto) { 
        return userService.login(userDto); 
    } 
 
    @Override 
    public UserDto updateUser(String uuid, UserDto userDto) { 
        return userService.updateByUuid(uuid, userDto); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
 
 68 
    public List<UserDto> usersAllGet() { 
        return userService.getAll(); 
    } 
} 
 
Клас HotelController: 
 
package com.ars.manager.controller; 
import com.ars.manager.service.HotelService; 
import lombok.RequiredArgsConstructor; 
import org.openapitools.api.HotelApi; 
import org.openapitools.model.HotelDto; 
import org.springframework.security.access.prepost.PreAuthorize; 
import org.springframework.web.bind.annotation.CrossOrigin; 
import org.springframework.web.bind.annotation.RestController; 
import java.util.List; 
 
@RestController 
@CrossOrigin 
@RequiredArgsConstructor 
public class HotelController implements HotelApi { 
    private final HotelService hotelService; 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public HotelDto addHotel(HotelDto hotelDto) { 
        return hotelService.add(hotelDto); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public Void deleteHotelByUuid(String uuid) { 
        hotelService.delete(uuid); 
        return null; 
    } 
 
    @Override 
    public HotelDto getHotelByUuid(String uuid) { 
        return hotelService.getByUuid(uuid); 
    } 
 
    @Override 
    public List<HotelDto> getHotels(Integer page, Integer limit) { 
        return hotelService.getHotels(page, limit); 
    } 
 
    @Override 
    public List<HotelDto> getAllHotelsByCityUuid(String uuid) { 
        return hotelService.getAllHotelsByCityUuid(uuid); 
    } 
 
    @Override 
    public List<HotelDto> getAllHotelsInDB() { 
        return hotelService.getAllHotelsInDB(); 
    } 
 
    @Override 
    public List<HotelDto> getHotelsByCityUuid(String uuid, Integer page, Integer limit) { 
        return hotelService.getHotelsByCityUuid(uuid, page, limit); 
 
 69 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public HotelDto updateHotelByUuid(String uuid, HotelDto hotelDto) { 
        return hotelService.update(uuid, hotelDto); 
    } 
} 
 
Клас TheaterController: 
 
package com.ars.manager.controller; 
import com.ars.manager.service.TheaterService; 
import lombok.RequiredArgsConstructor; 
import org.openapitools.api.TheaterApi; 
import org.openapitools.model.TheaterDto; 
import org.springframework.security.access.prepost.PreAuthorize; 
import org.springframework.web.bind.annotation.CrossOrigin; 
import org.springframework.web.bind.annotation.RestController; 
import java.util.List; 
 
@RestController 
@CrossOrigin 
@RequiredArgsConstructor 
public class TheaterController implements TheaterApi { 
    private final TheaterService theaterService; 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public TheaterDto addTheater(TheaterDto theaterDto) { 
        return theaterService.add(theaterDto); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public Void deleteTheaterByUuid(String uuid) { 
        theaterService.delete(uuid); 
 
        return null; 
    } 
 
    @Override 
    public List<TheaterDto> getAllTheatersByCityUuid(String uuid) { 
        return theaterService.getAllTheatersByCityUuid(uuid); 
    } 
 
    @Override 
    public List<TheaterDto> getAllTheatersInDB() { 
        return theaterService.getAllTheatersInDB(); 
    } 
 
    @Override 
    public TheaterDto getTheaterByUuid(String uuid) { 
        return theaterService.getByUuid(uuid); 
    } 
 
    @Override 
    public List<TheaterDto> getTheaters(Integer page, Integer limit) { 
        return theaterService.getTheaters(page, limit); 
 
 70 
    } 
 
    @Override 
    public List<TheaterDto> getTheatersByCityUuid(String uuid, Integer page, Integer limit) { 
        return theaterService.getTheatersByCityUuid(uuid, page, limit); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public TheaterDto updateTheaterByUuid(String uuid, TheaterDto theaterDto) { 
        return theaterService.update(uuid, theaterDto); 
    } 
} 
 
Клас CinemaController: 
 
package com.ars.manager.controller; 
import com.ars.manager.service.CinemaService; 
import lombok.RequiredArgsConstructor; 
import org.openapitools.api.CinemaApi; 
import org.openapitools.model.CinemaDto; 
import org.springframework.security.access.prepost.PreAuthorize; 
import org.springframework.web.bind.annotation.CrossOrigin; 
import org.springframework.web.bind.annotation.RestController; 
import java.util.List; 
 
@RestController 
@CrossOrigin 
@RequiredArgsConstructor 
public class CinemaController implements CinemaApi { 
    private final CinemaService cinemaService; 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public CinemaDto addCinema(CinemaDto cinemaDto) { 
        return cinemaService.add(cinemaDto); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public Void deleteCinemaByUuid(String uuid) { 
        cinemaService.delete(uuid); 
 
        return null; 
    } 
 
    @Override 
    public List<CinemaDto> getAllCinemasByCityUuid(String uuid) { 
        return cinemaService.getAllCinemasByCityUuid(uuid); 
    } 
 
    @Override 
    public List<CinemaDto> getAllCinemasInDB() throws Exception { 
        return cinemaService.getAllCinemasInDB(); 
    } 
 
    @Override 
    public CinemaDto getCinemaByUuid(String uuid) { 
        return cinemaService.getByUuid(uuid); 
    } 
 
 71 
 
    @Override 
    public List<CinemaDto> getCinemas(Integer page, Integer limit) { 
        return cinemaService.getCinemas(page, limit); 
    } 
 
    @Override 
    public List<CinemaDto> getCinemasByCityUuid(String uuid, Integer page, Integer limit) { 
        return cinemaService.getCinemasByCityUuid(uuid, page, limit); 
    } 
 
    @Override 
    @PreAuthorize("hasAnyAuthority('ADMIN')") 
    public CinemaDto updateCinemaByUuid(String uuid, CinemaDto cinemaDto) { 
        return cinemaService.update(uuid, cinemaDto); 
    } 
} 
 
 
Клас UserMapper: 
 
package com.ars.manager.mapper; 
import com.ars.manager.model.User; 
import org.mapstruct.Mapper; 
import org.mapstruct.Mapping; 
import org.openapitools.model.UserDto; 
import java.util.List; 
 
@Mapper(componentModel = "spring") 
public interface UserMapper { 
    List<UserDto> toDtos(List<User> entities); 
    UserDto toDto(User entity); 
    User toEntity(UserDto userDto); 
} 
 
Клас HotelMapper: 
 
package com.ars.manager.mapper; 
import com.ars.manager.model.Hotel; 
import com.ars.manager.repository.CityRepository; 
import org.mapstruct.Mapper; 
import org.mapstruct.Mapping; 
import org.openapitools.model.HotelDto; 
import org.springframework.beans.factory.annotation.Autowired; 
import java.util.List; 
 
@Mapper(componentModel = "spring") 
public abstract class HotelMapper { 
    @Autowired 
    protected CityRepository cityRepository; 
 
    public abstract List<HotelDto> toDtos(List<Hotel> entities); 
 
    @Mapping(target = "uuidCity", expression = 
            "java(cityRepository.findById(entity.getIdCity()).map(city-
>city.getUuid()).orElse(null))") 
    public abstract HotelDto toDto(Hotel entity); 
 
 
 72 
    @Mapping(target = "idCity", expression = 
            "java(cityRepository.findFirstByUuid(hotelDto.getUuidCity()).map(city-
>city.getId()).orElse(null))") 
    public abstract Hotel toEntity(HotelDto hotelDto); 
} 
 
Клас TheaterMapper: 
 
package com.ars.manager.mapper; 
import com.ars.manager.model.Theater; 
import com.ars.manager.repository.CityRepository; 
import org.mapstruct.Mapper; 
import org.mapstruct.Mapping; 
import org.openapitools.model.TheaterDto; 
import org.springframework.beans.factory.annotation.Autowired; 
import java.util.List; 
import java.util.Optional; 
 
@Mapper(componentModel = "spring") 
public abstract class TheaterMapper { 
    @Autowired 
    protected CityRepository cityRepository; 
 
    public abstract List<TheaterDto> toDtos(List<Theater> entities); 
 
    @Mapping(target = "uuidCity", expression = 
            "java(cityRepository.findById(entity.getIdCity()).map(city-
>city.getUuid()).orElse(null))") 
    public abstract TheaterDto toDto(Theater entity); 
 
    @Mapping(target = "idCity", expression = 
            "java(cityRepository.findFirstByUuid(theaterDto.getUuidCity()).map(city-
>city.getId()).orElseThrow(()->new IllegalArgumentException(\"Not found hotel by uuid: 
%s\".formatted(theaterDto.getUuidCity()))))") 
    public abstract Theater toEntity(TheaterDto theaterDto); 
} 
 
Клас CinemaMapper: 
 
package com.ars.manager.mapper; 
import com.ars.manager.model.Cinema; 
import com.ars.manager.repository.CityRepository; 
import org.mapstruct.Mapper; 
import org.mapstruct.Mapping; 
import org.openapitools.model.CinemaDto; 
import org.springframework.beans.factory.annotation.Autowired; 
import java.util.List; 
 
@Mapper(componentModel = "spring") 
public abstract class CinemaMapper { 
    @Autowired 
    protected CityRepository cityRepository; 
 
    public abstract List<CinemaDto> toDtos(List<Cinema> entities); 
 
    @Mapping(target = "uuidCity", expression = 
            "java(cityRepository.findById(entity.getIdCity()).map(city-
>city.getUuid()).orElse(null))") 
    public abstract CinemaDto toDto(Cinema entity); 
 
 73 
 
    @Mapping(target = "idCity", expression = 
            "java(cityRepository.findFirstByUuid(cinemaDto.getUuidCity()).map(city-
>city.getId()).orElse(null))") 
    public abstract Cinema toEntity(CinemaDto cinemaDto); 
} 
 
Клас UserRepository: 
 
package com.ars.manager.repository; 
import com.ars.manager.model.User; 
import org.springframework.data.repository.CrudRepository; 
import org.springframework.data.repository.PagingAndSortingRepository; 
import org.springframework.stereotype.Repository; 
import java.util.Optional; 
 
@Repository 
public interface UserRepository extends PagingAndSortingRepository<User, Long>, 
CrudRepository<User, Long> { 
    Optional<User> findFirstByUuid(String uuid); 
 
    Optional<User> findFirstByEmail(String email); 
 
    void deleteById(long id); 
 
} 
 
Клас HotelRepository: 
 
package com.ars.manager.repository; 
import com.ars.manager.model.Hotel; 
import org.springframework.data.domain.Pageable; 
import org.springframework.data.repository.CrudRepository; 
import org.springframework.data.repository.PagingAndSortingRepository; 
import org.springframework.stereotype.Repository; 
import java.util.List; 
import java.util.Optional; 
 
@Repository 
public interface HotelRepository extends PagingAndSortingRepository<Hotel, Long>, 
CrudRepository<Hotel, Long> { 
    Optional<Hotel> findFirstByUuid(String uuid); 
 
    Optional<Hotel> findFirstById(Long id); 
 
    Optional<List<Hotel>> findHotelsByIdCity(long id); 
 
    void deleteById(long id); 
 
    List<Hotel> findAllByIdCity(Pageable pageable, long id); 
} 
 
Клас CinemaRepository: 
 
package com.ars.manager.repository; 
import com.ars.manager.model.Cinema; 
import org.springframework.data.domain.Pageable; 
import org.springframework.data.repository.CrudRepository; 
 
 74 
import org.springframework.data.repository.PagingAndSortingRepository; 
import org.springframework.stereotype.Repository; 
import java.util.List; 
import java.util.Optional; 
 
@Repository 
public interface CinemaRepository extends PagingAndSortingRepository<Cinema, Long>, 
CrudRepository<Cinema, Long> { 
    Optional<Cinema> findFirstByUuid(String uuid); 
 
    Optional<Cinema> findFirstById(Long id); 
 
    Optional<List<Cinema>> findCinemasByIdCity(long id); 
 
    void deleteById(long id); 
 
    List<Cinema> findAllByIdCity(Pageable pageable, long id); 
} 
 
Клас TheaterRepository: 
 
package com.ars.manager.repository; 
import com.ars.manager.model.Theater; 
import org.springframework.data.domain.Pageable; 
import org.springframework.data.repository.CrudRepository; 
import org.springframework.data.repository.PagingAndSortingRepository; 
import org.springframework.stereotype.Repository; 
import java.util.List; 
import java.util.Optional; 
 
@Repository 
public interface TheaterRepository extends PagingAndSortingRepository<Theater, Long>, 
CrudRepository<Theater, Long> { 
    Optional<Theater> findFirstByUuid(String uuid); 
 
    Optional<Theater> findFirstById(Long id); 
 
    Optional<List<Theater>> findTheatersByIdCity(long id); 
 
    void deleteById(long id); 
 
    List<Theater> findAllByIdCity(Pageable pageable, long id); 
} 
 
Клас UserService: 
 
package com.ars.manager.service; 
import com.ars.manager.mapper.UserMapper; 
import com.ars.manager.model.Role; 
import com.ars.manager.model.User; 
import com.ars.manager.repository.UserRepository; 
import com.ars.manager.security.JwtService; 
import com.ars.manager.security.UserDetailsServiceImpl; 
import lombok.RequiredArgsConstructor; 
import lombok.extern.slf4j.Slf4j; 
import org.openapitools.model.JwtDto; 
import org.openapitools.model.UserDto; 
import org.springframework.data.domain.PageRequest; 
import org.springframework.data.domain.Pageable; 
 
 75 
import org.springframework.security.authentication.AuthenticationManager; 
import org.springframework.security.authentication.BadCredentialsException; 
import org.springframework.security.authentication.DisabledException; 
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 
import org.springframework.security.core.userdetails.UserDetails; 
import org.springframework.security.crypto.password.PasswordEncoder; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 
import java.util.List; 
import java.util.Optional; 
import java.util.UUID; 
 
@Service 
@RequiredArgsConstructor 
@Slf4j 
public class UserService { 
    private final UserRepository userRepository; 
    private final UserMapper userMapper; 
    private final PasswordEncoder passwordEncoder; 
 
    private final AuthenticationManager authenticationManager; 
    private final JwtService jwtService; 
    private final UserDetailsServiceImpl userDetailsService; 
 
    public List<UserDto> getAllPages(int page, int limit) { 
        Pageable pageable = PageRequest.of(page, limit); 
 
        List<User> users = userRepository.findAll(pageable) 
                .stream() 
                .toList(); 
 
 
        return userMapper.toDtos(users); 
    } 
 
    public List<UserDto> getAll() { 
        List<User> users = (List<User>) userRepository.findAll(); 
 
        return userMapper.toDtos(users); 
    } 
 
    public UserDto getByEmail(String email) { 
        Optional<User> optionalUser = userRepository.findFirstByEmail(email); 
 
        if (optionalUser.isPresent()) { 
            return userMapper.toDto(optionalUser.get()); 
        } else { 
            throw new IllegalArgumentException("User not found by email"); 
        } 
    } 
 
    public UserDto add(UserDto userDto) { 
        User user = userMapper.toEntity(userDto); 
        Optional<User> optionalUser = userRepository.findFirstByEmail(user.getEmail()); 
 
        if (optionalUser.isPresent()) { 
            throw new IllegalArgumentException("User already exists"); 
        } 
 
        user.setUuid(UUID.randomUUID().toString()); 
        user.setPassword(passwordEncoder.encode(user.getPassword())); 
 
 76 
        user.setRole(Role.USER); 
 
        return userMapper.toDto( 
                userRepository.save(user) 
        ); 
    } 
 
    public UserDto get(String uuid) { 
        User user = userRepository.findFirstByUuid(uuid).get(); 
 
        return userMapper.toDto(user); 
    } 
 
    public void delete(String uuid) { 
        Optional<User> user = userRepository.findFirstByUuid(uuid); 
 
        if (user.isEmpty()) { 
            throw new IllegalArgumentException("User not found by uuid: " + uuid); 
        } 
 
        userRepository.deleteById(user.get().getId()); 
    } 
 
    @Transactional 
    public UserDto updateByUuid(String uuid, UserDto userDto) { 
        Optional<User> userOptional = userRepository.findFirstByUuid(uuid); 
        Optional<User> optionalUserEmail = 
userRepository.findFirstByEmail(userDto.getEmail()); 
 
        if (optionalUserEmail.isPresent() && userOptional.isPresent() && 
!userOptional.get().getUuid().equals(optionalUserEmail.get().getUuid())) { 
            throw new IllegalArgumentException("Email error"); 
        } 
 
        if (userOptional.isEmpty()) { 
            throw new IllegalArgumentException("User not found by uuid: " + uuid); 
        } else { 
            User updated = userMapper.toEntity(userDto); 
            User userToUpdate = userOptional.get(); 
 
            if (updated.getFirstName() != null) { 
                userToUpdate.setFirstName(updated.getFirstName()); 
            } 
            if (updated.getLastName() != null) { 
                userToUpdate.setLastName(updated.getLastName()); 
            } 
            if (updated.getEmail() != null) { 
                userToUpdate.setEmail(updated.getEmail()); 
            } 
            if (updated.getPassword() != null) { 
                userToUpdate.setPassword(passwordEncoder.encode(updated.getPassword())); 
            } 
            if (updated.getRole() != null) { 
                userToUpdate.setRole(updated.getRole()); 
            } 
 
            return userMapper.toDto( 
                    userRepository.save(userToUpdate) 
            ); 
        } 
    } 
 
 77 
 
    public JwtDto login(UserDto userDto) { 
        Optional<User> optionalUser = userRepository.findFirstByEmail(userDto.getEmail()); 
        if (optionalUser.isPresent()) { 
            User user = optionalUser.get(); 
 
            if (!passwordEncoder.matches(userDto.getPassword(), user.getPassword())) { 
                throw new IllegalArgumentException("Wrong password"); 
            } 
        } else { 
            throw new IllegalArgumentException("User not found"); 
        } 
 
        authenticate(userDto.getEmail(), userDto.getPassword()); 
 
        final UserDetails userDetails = 
userDetailsService.loadUserByUsername(userDto.getEmail()); 
        final String token = jwtService.generateToken(userDetails); 
 
        JwtDto jwtDto = new JwtDto(); 
        jwtDto.jwtToken(token); 
        return jwtDto; 
    } 
 
    private void authenticate( 
            String username, 
            String password 
    ) throws DisabledException, BadCredentialsException { 
 
        authenticationManager.authenticate( 
                new UsernamePasswordAuthenticationToken(username, password) 
        ); 
    } 
} 
 
Клас TheaterService: 
 
package com.ars.manager.service; 
import com.ars.manager.classes.TheaterInspector; 
import com.ars.manager.mapper.TheaterMapper; 
import com.ars.manager.model.City; 
import com.ars.manager.model.Theater; 
import com.ars.manager.repository.CityRepository; 
import com.ars.manager.repository.TheaterRepository; 
import lombok.RequiredArgsConstructor; 
import org.openapitools.model.TheaterDto; 
import org.springframework.data.domain.PageRequest; 
import org.springframework.data.domain.Pageable; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 
import java.util.List; 
import java.util.Optional; 
import java.util.UUID; 
 
@Service 
@RequiredArgsConstructor 
public class TheaterService { 
    private final TheaterMapper theaterMapper; 
    private final TheaterRepository theaterRepository; 
 
 
 78 
    private final CityRepository cityRepository; 
 
    public TheaterDto add(TheaterDto theaterDto) { 
        Theater theater = theaterMapper.toEntity(theaterDto); 
 
        theater.setUuid(UUID.randomUUID().toString()); 
 
        return theaterMapper.toDto( 
                theaterRepository.save(theater) 
        ); 
    } 
 
    public List<TheaterDto> getTheaters(int page, int limit) { 
        Pageable pageable = PageRequest.of(page, limit); 
 
        List<Theater> theaters = theaterRepository.findAll(pageable) 
                .stream().toList(); 
 
        return theaterMapper.toDtos(theaters); 
    } 
 
    public List<TheaterDto> getTheatersByCityUuid(String uuid, int page, int limit) { 
        Optional<City> optionalCity = cityRepository.findFirstByUuid(uuid); 
 
        if (optionalCity.isEmpty()) { 
            throw new IllegalArgumentException("City not found by uuid: " + uuid); 
        } 
 
        City city = optionalCity.get(); 
        Pageable pageable = PageRequest.of(page, limit); 
        List<Theater> theaters = theaterRepository.findAllByIdCity(pageable, city.getId()); 
 
        return theaterMapper.toDtos(theaters); 
    } 
 
    public List<TheaterDto> getAllTheatersInDB() { 
        List<Theater> theaters = (List<Theater>) theaterRepository.findAll(); 
 
        return theaterMapper.toDtos(theaters); 
    } 
 
    public List<TheaterDto> getAllTheatersByCityUuid(String uuid) { 
        Optional<City> optionalCity = cityRepository.findFirstByUuid(uuid); 
 
        if (optionalCity.isEmpty()) { 
            throw new IllegalArgumentException("City not found by uuid: " + uuid); 
        } 
 
        City city = optionalCity.get(); 
        Optional<List<Theater>> optionalTheaters = 
theaterRepository.findTheatersByIdCity(city.getId()); 
        List<Theater> theaters = optionalTheaters.get(); 
 
        return theaterMapper.toDtos(theaters); 
    } 
 
    public TheaterDto getByUuid(String uuid) { 
        Optional<Theater> optionalTheater = theaterRepository.findFirstByUuid(uuid); 
 
        if (optionalTheater.isEmpty()) { 
            throw new IllegalArgumentException("Theater not found by uuid: " + uuid); 
 
 79 
        } 
 
        Theater theater = optionalTheater.get(); 
 
        return theaterMapper.toDto(theater); 
    } 
 
    @Transactional 
    public TheaterDto update(String uuid, TheaterDto theaterDto) { 
        Optional<Theater> optionalTheater = theaterRepository.findFirstByUuid(uuid); 
 
        if (optionalTheater.isEmpty()) { 
            throw new IllegalArgumentException("Theater not found by uuid: " + uuid); 
        } else { 
            Theater updated = theaterMapper.toEntity(theaterDto); 
            Theater theater = TheaterInspector.checkUpdatedTheater(optionalTheater, updated); 
 
            return theaterMapper.toDto( 
                    theaterRepository.save(theater) 
            ); 
        } 
    } 
 
    public void delete(String uuid) { 
        Optional<Theater> optionalTheater = theaterRepository.findFirstByUuid(uuid); 
 
        if (optionalTheater.isEmpty()) { 
            throw new IllegalArgumentException("Theater not found by uuid: " + uuid); 
        } 
 
        theaterRepository.deleteById(optionalTheater.get().getId()); 
    } 
} 
 
Клас HotelService: 
 
package com.ars.manager.service; 
import com.ars.manager.classes.HotelInspector; 
import com.ars.manager.mapper.HotelMapper; 
import com.ars.manager.model.City; 
import com.ars.manager.model.Hotel; 
import com.ars.manager.repository.CityRepository; 
import com.ars.manager.repository.HotelRepository; 
import lombok.RequiredArgsConstructor; 
import org.openapitools.model.HotelDto; 
import org.springframework.data.domain.PageRequest; 
import org.springframework.data.domain.Pageable; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 
import java.util.List; 
import java.util.Optional; 
import java.util.UUID; 
 
@Service 
@RequiredArgsConstructor 
public class HotelService { 
    private final HotelRepository hotelRepository; 
    private final HotelMapper hotelMapper; 
 
    private final CityRepository cityRepository; 
 
 80 
 
    public HotelDto add(HotelDto hotelDto) { 
        Hotel hotel = hotelMapper.toEntity(hotelDto); 
 
        hotel.setUuid(UUID.randomUUID().toString()); 
 
        return hotelMapper.toDto( 
                hotelRepository.save(hotel) 
        ); 
    } 
 
    public List<HotelDto> getHotels(int page, int limit) { 
        Pageable pageable = PageRequest.of(page, limit); 
 
        List<Hotel> hotels = hotelRepository.findAll(pageable) 
                .stream() 
                .toList(); 
 
        return hotelMapper.toDtos(hotels); 
    } 
 
    public List<HotelDto> getHotelsByCityUuid(String uuid, int page, int limit) { 
        Optional<City> optionalCity = cityRepository.findFirstByUuid(uuid); 
 
        if (optionalCity.isEmpty()) { 
            throw new IllegalArgumentException("City not found by uuid: " + uuid); 
        } 
 
        City city = optionalCity.get(); 
        Pageable pageable = PageRequest.of(page, limit); 
        List<Hotel> hotels = hotelRepository.findAllByIdCity(pageable, city.getId()); 
 
        return hotelMapper.toDtos(hotels); 
    } 
 
    public List<HotelDto> getAllHotelsInDB() { 
        List<Hotel> hotels = (List<Hotel>) hotelRepository.findAll(); 
 
        return hotelMapper.toDtos(hotels); 
    } 
 
    public List<HotelDto> getAllHotelsByCityUuid(String uuid) { 
        Optional<City> optionalCity = cityRepository.findFirstByUuid(uuid); 
 
        if (optionalCity.isEmpty()) { 
            throw new IllegalArgumentException("City not found by uuid: " + uuid); 
        } 
 
        City city = optionalCity.get(); 
 
        Optional<List<Hotel>> optionalHotels = 
hotelRepository.findHotelsByIdCity(city.getId()); 
 
        List<Hotel> hotels = optionalHotels.get(); 
 
        return hotelMapper.toDtos(hotels); 
    } 
 
    public HotelDto getByUuid(String uuid) { 
        Optional<Hotel> optionalHotel = hotelRepository.findFirstByUuid(uuid); 
 
 
 81 
        if (optionalHotel.isEmpty()) { 
            throw new IllegalArgumentException("Hotel not found by uuid: " + uuid); 
        } 
 
        Hotel hotel = optionalHotel.get(); 
 
        return hotelMapper.toDto(hotel); 
    } 
 
    public HotelDto update(String uuid, HotelDto hotelDto) { 
        Optional<Hotel> optionalHotel = hotelRepository.findFirstByUuid(uuid); 
 
        if (optionalHotel.isEmpty()) { 
            throw new IllegalArgumentException("Hotel not found by uuid: " + uuid); 
        } else { 
            Hotel updated = hotelMapper.toEntity(hotelDto); 
            Hotel hotelToUpdate = HotelInspector.checkUpdatedHotel(optionalHotel, updated); 
 
            return hotelMapper.toDto( 
                    hotelRepository.save(hotelToUpdate) 
            ); 
        } 
    } 
 
    public void delete(String uuid) { 
        Optional<Hotel> optionalHotel = hotelRepository.findFirstByUuid(uuid); 
 
        if (optionalHotel.isEmpty()) { 
            throw new IllegalArgumentException("Hotel not found by uuid: " + uuid); 
        } 
        hotelRepository.deleteById(optionalHotel.get().getId()); 
    } 
} 
 
Клас CinemaService: 
 
package com.ars.manager.service; 
import com.ars.manager.classes.CinemaInspector; 
import com.ars.manager.mapper.CinemaMapper; 
import com.ars.manager.model.Cinema; 
import com.ars.manager.model.City; 
import com.ars.manager.repository.CinemaRepository; 
import com.ars.manager.repository.CityRepository; 
import lombok.RequiredArgsConstructor; 
import org.openapitools.model.CinemaDto; 
import org.springframework.data.domain.PageRequest; 
import org.springframework.data.domain.Pageable; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 
import java.util.List; 
import java.util.Optional; 
import java.util.UUID; 
 
@Service 
@RequiredArgsConstructor 
public class CinemaService { 
    private final CinemaMapper cinemaMapper; 
    private final CinemaRepository cinemaRepository; 
 
    private final CityRepository cityRepository; 
 
 82 
 
    public CinemaDto add(CinemaDto cinemaDto) { 
        Cinema cinema = cinemaMapper.toEntity(cinemaDto); 
 
        cinema.setUuid(UUID.randomUUID().toString()); 
 
        return cinemaMapper.toDto( 
                cinemaRepository.save(cinema) 
        ); 
    } 
 
    public List<CinemaDto> getCinemas(int page, int limit) { 
        Pageable pageable = PageRequest.of(page, limit); 
 
        List<Cinema> cinemas = cinemaRepository.findAll(pageable) 
                .stream().toList(); 
 
        return cinemaMapper.toDtos(cinemas); 
    } 
 
    public List<CinemaDto> getCinemasByCityUuid(String uuid, int page, int limit) { 
        Optional<City> optionalCity = cityRepository.findFirstByUuid(uuid); 
 
        if (optionalCity.isEmpty()) { 
            throw new IllegalArgumentException("City not found by uuid: " + uuid); 
        } 
 
        City city = optionalCity.get(); 
        Pageable pageable = PageRequest.of(page, limit); 
        List<Cinema> cinemas = cinemaRepository.findAllByIdCity(pageable, city.getId()); 
 
        return cinemaMapper.toDtos(cinemas); 
    } 
 
    public List<CinemaDto> getAllCinemasInDB() { 
        List<Cinema> cinemas = (List<Cinema>) cinemaRepository.findAll(); 
 
        return cinemaMapper.toDtos(cinemas); 
    } 
 
    public List<CinemaDto> getAllCinemasByCityUuid(String uuid) { 
        Optional<City> optionalCity = cityRepository.findFirstByUuid(uuid); 
 
        if (optionalCity.isEmpty()) { 
            throw new IllegalArgumentException("City not found by uuid: " + uuid); 
        } 
 
        City city = optionalCity.get(); 
        Optional<List<Cinema>> optionalCinemas = 
cinemaRepository.findCinemasByIdCity(city.getId()); 
        List<Cinema> cinemas = optionalCinemas.get(); 
 
        return cinemaMapper.toDtos(cinemas); 
    } 
 
    public CinemaDto getByUuid(String uuid) { 
        Optional<Cinema> optionalCinema = cinemaRepository.findFirstByUuid(uuid); 
 
        if (optionalCinema.isEmpty()) { 
            throw new IllegalArgumentException("Cinema not found by uuid: " + uuid); 
        } 
 
 83 
 
        Cinema cinema = optionalCinema.get(); 
 
        return cinemaMapper.toDto(cinema); 
    } 
 
    @Transactional 
    public CinemaDto update(String uuid, CinemaDto cinemaDto) { 
        Optional<Cinema> optionalCinema = cinemaRepository.findFirstByUuid(uuid); 
 
        if (optionalCinema.isEmpty()) { 
            throw new IllegalArgumentException("Cinema not found by uuid: " + uuid); 
        } else { 
            Cinema updated = cinemaMapper.toEntity(cinemaDto); 
            Cinema cinemaToUpdate = CinemaInspector.checkUpdatedCinema(optionalCinema, 
updated); 
 
            return cinemaMapper.toDto( 
                    cinemaRepository.save(cinemaToUpdate) 
            ); 
        } 
    } 
 
    public void delete(String uuid) { 
        Optional<Cinema> optionalCinema = cinemaRepository.findFirstByUuid(uuid); 
 
        if (optionalCinema.isEmpty()) { 
            throw new IllegalArgumentException("Cinema not found by uuid: " + uuid); 
        } 
 
        cinemaRepository.deleteById(optionalCinema.get().getId()); 
    } 
} 
 
Клас User: 
 
package com.ars.manager.model; 
import lombok.*; 
import org.springframework.data.annotation.CreatedDate; 
import org.springframework.data.annotation.Id; 
import org.springframework.data.annotation.LastModifiedDate; 
import org.springframework.data.relational.core.mapping.InsertOnlyProperty; 
import java.time.OffsetDateTime; 
 
@NoArgsConstructor 
@Builder 
@Getter 
@Setter 
@AllArgsConstructor 
@EqualsAndHashCode 
@ToString 
public class User { 
    @Id 
    private long id; 
    private String uuid; 
    private String lastName; 
    private String firstName; 
    private String email; 
    private String password; 
    private Role role; 
 
 84 
    @CreatedDate 
    @InsertOnlyProperty 
    private OffsetDateTime createdAt; 
    @LastModifiedDate 
    private OffsetDateTime updatedAt; 
} 
 
Клас Theater: 
 
package com.ars.manager.model; 
import lombok.*; 
import org.springframework.data.annotation.CreatedDate; 
import org.springframework.data.annotation.Id; 
import org.springframework.data.annotation.LastModifiedDate; 
import org.springframework.data.relational.core.mapping.InsertOnlyProperty; 
import java.time.OffsetDateTime; 
 
@NoArgsConstructor 
@Builder 
@Getter 
@Setter 
@AllArgsConstructor 
@EqualsAndHashCode 
@ToString 
public class Theater { 
    @Id 
    private long id; 
    private String uuid; 
    private String name; 
    private String imageUrl; 
    private String address; 
    private Double latitude; 
    private Double longitude; 
    private Long idCity; 
    private String description; 
    private String phoneNumbers; 
    private String socialLink; 
    private String email; 
    @CreatedDate 
    @InsertOnlyProperty 
    private OffsetDateTime createdAt; 
    @LastModifiedDate 
    private OffsetDateTime updatedAt; 
} 
 
Клас Hotel: 
 
package com.ars.manager.model; 
import lombok.*; 
import org.springframework.data.annotation.CreatedDate; 
import org.springframework.data.annotation.Id; 
import org.springframework.data.annotation.LastModifiedDate; 
import org.springframework.data.relational.core.mapping.InsertOnlyProperty; 
import java.time.OffsetDateTime; 
 
@NoArgsConstructor 
@Builder 
@Getter 
@Setter 
 
 85 
@AllArgsConstructor 
@EqualsAndHashCode 
@ToString 
public class Hotel { 
    @Id 
    private long id; 
    private String uuid; 
    private String name; 
    private String imageUrl; 
    private String address; 
    private Double latitude; 
    private Double longitude; 
    private Long idCity; 
    private String socialLink; 
    private String phoneNumbers; 
    private String email; 
    private String description; 
    private String services; 
    private String mealsInformation; 
    private Integer roomsAmount; 
    private Integer minPrice; 
    @CreatedDate 
    @InsertOnlyProperty 
    private OffsetDateTime createdAt; 
    @LastModifiedDate 
    private OffsetDateTime updatedAt; 
} 
 
Клас Cinema: 
 
package com.ars.manager.model; 
import lombok.*; 
import org.springframework.data.annotation.CreatedDate; 
import org.springframework.data.annotation.Id; 
import org.springframework.data.annotation.LastModifiedDate; 
import org.springframework.data.relational.core.mapping.InsertOnlyProperty; 
import java.time.OffsetDateTime; 
 
@NoArgsConstructor 
@Builder 
@Getter 
@Setter 
@AllArgsConstructor 
@EqualsAndHashCode 
@ToString 
public class Cinema { 
    @Id 
    private long id; 
    private String uuid; 
    private String name; 
    private String imageUrl; 
    private String address; 
    private Double latitude; 
    private Double longitude; 
    private String description; 
    private Long idCity; 
    private String socialLink; 
    private String phoneNumbers; 
    @CreatedDate 
    @InsertOnlyProperty 
 
 86 
    private OffsetDateTime createdAt; 
    @LastModifiedDate 
    private OffsetDateTime updatedAt; 
} 
 
Клас TheaterInspector: 
 
package com.ars.manager.classes; 
import com.ars.manager.model.Theater; 
import java.util.Optional; 
 
public class TheaterInspector { 
    public static Theater checkUpdatedTheater(Optional<Theater> optionalTheater, Theater 
updated) { 
        Theater theater = optionalTheater.get(); 
 
        if (updated.getName() != null) { 
            theater.setName(updated.getName()); 
        } 
        if (updated.getLatitude() != null) { 
            theater.setLatitude(updated.getLatitude()); 
        } 
        if (updated.getLongitude() != null) { 
            theater.setLongitude(updated.getLongitude()); 
        } 
        if (updated.getAddress() != null) { 
            theater.setAddress(updated.getAddress()); 
        } 
        if (updated.getIdCity() != null) { 
            theater.setIdCity(updated.getIdCity()); 
        } 
        if (updated.getDescription() != null) { 
            theater.setDescription(updated.getDescription()); 
        } 
        if (updated.getPhoneNumbers() != null) { 
            theater.setPhoneNumbers(updated.getPhoneNumbers()); 
        } 
        if (updated.getEmail() != null) { 
            theater.setEmail(updated.getEmail()); 
        } 
        if (updated.getSocialLink() != null) { 
            theater.setSocialLink(updated.getSocialLink()); 
        } 
 
        return theater; 
    } 
} 
 
Клас HotelInspector: 
 
package com.ars.manager.classes; 
import com.ars.manager.model.Hotel; 
import java.util.Optional; 
 
public class HotelInspector { 
    public static Hotel checkUpdatedHotel(Optional<Hotel> optionalHotel, Hotel updated) { 
        Hotel hotel = optionalHotel.get(); 
         
        if (updated.getName() != null) { 
 
 87 
            hotel.setName(updated.getName()); 
        } 
        if (updated.getAddress() != null) { 
            hotel.setAddress(updated.getAddress()); 
        } 
        if (updated.getLatitude() != null) { 
            hotel.setLatitude(updated.getLatitude()); 
        } 
        if (updated.getLongitude() != null) { 
            hotel.setLongitude(updated.getLongitude()); 
        } 
        if (updated.getIdCity() != null) { 
            hotel.setIdCity(updated.getIdCity()); 
        } 
        if (updated.getSocialLink() != null) { 
            hotel.setSocialLink(updated.getSocialLink()); 
        } 
        if (updated.getPhoneNumbers() != null) { 
            hotel.setPhoneNumbers(updated.getPhoneNumbers()); 
        } 
        if (updated.getEmail() != null) { 
            hotel.setEmail(updated.getEmail()); 
        } 
        if (updated.getDescription() != null) { 
            hotel.setDescription(updated.getDescription()); 
        } 
        if (updated.getServices() != null) { 
            hotel.setServices(updated.getServices()); 
        } 
        if (updated.getMealsInformation() != null) { 
            hotel.setMealsInformation(updated.getMealsInformation()); 
        } 
        if (updated.getRoomsAmount() != null) { 
            hotel.setRoomsAmount(updated.getRoomsAmount()); 
        } 
        if (updated.getMinPrice() != null) { 
            hotel.setMinPrice(updated.getMinPrice()); 
        } 
         
        return hotel; 
    } 
} 
 
Клас CinemaInspector: 
 
package com.ars.manager.classes; 
import com.ars.manager.model.Cinema; 
import java.util.Optional; 
 
public class CinemaInspector { 
    public static Cinema checkUpdatedCinema(Optional<Cinema> optionalCinema, Cinema updated) 
{ 
        Cinema cinema = optionalCinema.get(); 
 
        if (updated.getName() != null) { 
            cinema.setName(updated.getName()); 
        } 
        if (updated.getLatitude() != null) { 
            cinema.setLatitude(updated.getLatitude()); 
        } 
 
 88 
        if (updated.getLongitude() != null) { 
            cinema.setLongitude(updated.getLongitude()); 
        } 
        if (updated.getAddress() != null) { 
            cinema.setAddress(updated.getAddress()); 
        } 
        if (updated.getDescription() != null) { 
            cinema.setDescription(updated.getDescription()); 
        } 
        if (updated.getIdCity() != null) { 
            cinema.setIdCity(updated.getIdCity()); 
        } 
        if (updated.getPhoneNumbers() != null) { 
            cinema.setPhoneNumbers(updated.getPhoneNumbers()); 
        } 
        if (updated.getSocialLink() != null) { 
            cinema.setSocialLink(updated.getSocialLink()); 
        } 
 
        return cinema; 
    } 
} 
 
Компонент UserLogin: 
 
import React, {useEffect, useState} from "react"; 
import {Button, Col, Container, FloatingLabel, Form, Image, Row} from "react-bootstrap"; 
import {Link, useNavigate} from "react-router-dom"; 
import img from "../../Assets/img/login_forest.jpg"; 
import $ from 'jquery'; 
import {getUserByEmail, loginUser} from "../../API/APIService"; 
import {getUserNameFromToken} from "../../Assets/js/token"; 
import {useDispatch} from "react-redux"; 
import {login} from "../../redux/slice/userSlice"; 
 
const UserLogin = () => { 
    const navigate = useNavigate(); 
    const [formData, setFormData] = useState({ 
        email: '', 
        password: '', 
    }); 
    const dispatch = useDispatch(); 
 
    useEffect(() => { 
        const email = getUserNameFromToken(); 
        if (email !== null) { 
            navigate(-1); 
        } 
    }, []); 
 
    const handleInputChange = (e) => { 
        const {name, value} = e.target; 
        setFormData({...formData, [name]: value}); 
    }; 
 
    const handleSubmit = async (e) => { 
        e.preventDefault(); 
 
        try { 
            const token = await loginUser(formData); 
 
 89 
            localStorage.setItem('Authorization', `Bearer ${token}`); 
 
            getUserByEmail(getUserNameFromToken()) 
                .then((user) => { 
                    localStorage.setItem('Role', user.role); 
                    dispatch(login()); 
                }); 
 
            navigate('/'); 
        } catch (error) { 
            console.error('Login error: ', error); 
            if (error.response.data.message === 'User not found') { 
                $("#errorEmail").text('Неправильний email або користувач не існує.') 
            } else { 
                $("#errorEmail").text('') 
            } 
 
            if (error.response.data.message === 'Wrong password') { 
                $("#errorPassword").text('Неправильний пароль'); 
            } else { 
                $("#errorPassword").text(''); 
            } 
        } 
    }; 
 
    const handleShowPassword = () => { 
        let passwordInput = $('#password'); 
 
        if (passwordInput.attr('type') === 'password') { 
            passwordInput.attr('type', 'text'); 
        } else { 
            passwordInput.attr('type', 'password'); 
        } 
    }; 
 
    return ( 
            <Container className='py-5'> 
                <Row className='d-flex align-items-center justify-content-center'> 
                    <Col md={8} lg={7} xl={6}> 
                        <Image className='img-fluid' style={{opacity: 0.8}} src={img} 
alt="Login img"/> 
                    </Col> 
                    <Col md={7} lg={4} xl={5}> 
                        <h2 className='text-center mb-5'>Вхід до облікового запису</h2> 
                        <Form onSubmit={handleSubmit}> 
                            <FloatingLabel label='Email' htmlFor='email' className='mb-4'> 
                                <Form.Control name='email' id='email' type='email' 
value={formData.email} 
                                              onChange={handleInputChange} 
placeholder='Введіть email'/> 
                                <Form.Text className='text-danger' 
id='errorEmail'></Form.Text> 
                            </FloatingLabel> 
                            <FloatingLabel label='Пароль' htmlFor='password' className='mb-
4'> 
                                <Form.Control name='password' id='password' type='password' 
onChange={handleInputChange} 
                                              placeholder='Введіть пароль'/> 
                                <Form.Text className='text-danger' 
id='errorPassword'></Form.Text> 
                            </FloatingLabel> 
 
 90 
                            <Form.Check onClick={handleShowPassword} type='checkbox' 
id='showPassword' 
                                        label='Показати пароль' className='mb-4'/> 
                            <Row className='d-flex justify-content-center align-items-center 
mb-2'> 
                                <Col md={1}> 
                                    <Link to='/registration'>Реєстрація</Link> 
                                </Col> 
                            </Row> 
                            <Row className='d-flex justify-content-center mb-2'> 
                                <Col md={1}> 
                                    <Button type='submit' variant='primary' className='btn-
lg'>Вхід</Button> 
                                </Col> 
                            </Row> 
                        </Form> 
                    </Col> 
                </Row> 
            </Container> 
    ); 
}; 
 
export default UserLogin; 
 
Компонент UserRegistration: 
 
import React, {useEffect, useState} from "react"; 
import img from '../../Assets/img/registration_forest.jpg'; 
import {Button, Card, Col, Container, FloatingLabel, Form, Row} from "react-bootstrap"; 
import {Link, useNavigate} from "react-router-dom"; 
import $ from 'jquery'; 
import {registerUser} from "../../API/APIService"; 
import {getUserNameFromToken} from "../../Assets/js/token"; 
 
const UserRegistration = () => { 
    const navigate = useNavigate(); 
    const [loading, setLoading] = useState(true); 
    const [formData, setFormData] = useState({ 
        last_name: '', 
        first_name: '', 
        email: '', 
        password: '', 
    }); 
 
    useEffect(() => { 
        setLoading(true); 
 
        const email = getUserNameFromToken(); 
        if (email !== null) { 
            setLoading(false); 
            navigate(-1); 
        } 
 
        setLoading(false); 
    }, []); 
 
    const handleInputChange = (e) => { 
        const {name, value} = e.target; 
        setFormData({...formData, [name]: value}); 
    }; 
 
 91 
 
    const showPassword = () => { 
        let passwordInput = $('#password'); 
 
        if (passwordInput.attr('type') === 'password') { 
            passwordInput.attr('type', 'text'); 
        } else { 
            passwordInput.attr('type', 'password'); 
        } 
    }; 
 
    const handleSubmit = async (e) => { 
        e.preventDefault(); 
 
        try { 
            await registerUser(formData) 
 
            navigate('/login'); 
        } catch (error) { 
            console.log('Registration error: ', error.response.data.message); 
            if (error.response.data.message === 'User already exists') { 
                $("#errorEmail").text('Користувач з даним email вже існує'); 
            } 
        } 
    }; 
 
    if (loading) { 
        return <div>Loading...</div>; 
    } 
 
    return ( 
        <> 
            <Container className='py-5'> 
                <Row className='d-flex align-items-center justify-content-center'> 
                    <Col lg={8}> 
                        <Card className='rounded-3' style={{maxWidth: '600px'}}> 
                            <Card.Img src={img} className='w-100 rounded-top' 
alt='Registration img'/> 
                            <Card.Body className='px-5'> 
                                <h3 className="mb-4 pb-2 pb-md-0 mb-md-5 px-md-2 text-
center">Дані для реєстрації</h3> 
                                <Form onSubmit={handleSubmit}> 
                                    <Row className='mb-4'> 
                                        <Col md={6}> 
                                            <FloatingLabel label='Прізвище' 
htmlFor='last_name'> 
                                                <Form.Control name='last_name' id='last_name' 
value={formData.last_name} onChange={handleInputChange} type='text' placeholder='Введіть 
прізвище'/> 
                                            </FloatingLabel> 
                                        </Col> 
                                        <Col md={6}> 
                                            <FloatingLabel label="Ім'я" htmlFor='first_name'> 
                                                <Form.Control name='first_name' 
id='first_name' value={formData.first_name} onChange={handleInputChange} type='text' 
placeholder='Введіть прізвище'/> 
                                            </FloatingLabel> 
                                        </Col> 
                                    </Row> 
                                    <Row className='mb-4'> 
                                        <Col> 
 
 92 
                                            <FloatingLabel label='Email' htmlFor='email'> 
                                                <Form.Control name='email' id='email' 
value={formData.email} onChange={handleInputChange} type='email' placeholder='Введіть 
email'/> 
                                                <Form.Text className='text-danger' 
id='errorEmail'></Form.Text> 
                                            </FloatingLabel> 
                                        </Col> 
                                    </Row> 
                                    <Row className='mb-4'> 
                                        <Col> 
                                            <FloatingLabel label='Пароль' htmlFor='password'> 
                                                <Form.Control name='password' id='password' 
value={formData.password} onChange={handleInputChange} type='password' placeholder='Введіть 
пароль'/> 
                                                <Form.Text className='text-danger' 
id='errorPassword'></Form.Text> 
                                            </FloatingLabel> 
                                        </Col> 
                                    </Row> 
                                    <Row className='mb-4'> 
                                        <Col> 
                                            <Form.Check type='checkbox' id='showPassword' 
label='Показати пароль' className='mb-4' onClick={showPassword}/> 
                                        </Col> 
                                    </Row> 
                                    <Row className='mb-2'> 
                                        <Col className='text-center'> 
                                            <span>Вже є обліковий запис? Тоді просто <Link 
to='/login'>увійдіть</Link></span> 
                                        </Col> 
                                    </Row> 
                                    <Row className='d-flex justify-content-center'> 
                                        <Button type='submit' variant='primary' 
className='btn-lg'>Зареєструватись</Button> 
                                    </Row> 
                                </Form> 
                            </Card.Body> 
                        </Card> 
                    </Col> 
                </Row> 
            </Container> 
        </> 
    ); 
}; 
 
export default UserRegistration; 
 
  
 
 93 
ДОДАТОК В 
 
 
 
 
 
ВЕБ-ОРІЄНТОВАНИЙ СЕРВІС ДЛЯ ПОШУКУ МІСЦЬ ВІДПОЧИНКУ 
 
ІНСТРУКЦІЯ КОРИСТУВАЧА 
482. ЧДТУ. 42291-01 34 01 
 
Листів 4 
 
 
 
 
 
Розробник    _____________                   Кавун Д.Р. 
 
 
 
 
 
 
 
 
 
 
Черкаси – 2024  
 
 94 
Веб-орієнтований сервіс для пошуку місць відпочинку розроблений таким 
чином, що включає в себе дві ролі сервісу: 
– користувач (звичайний користувач); 
– адміністратор (користувач з додатковими правами, адміністратор сервісу). 
Реєстрація користувача відбувається на сторінці реєстрації. Для створення 
облікового запису користувачу необхідно ввести: своє прізвище, ім’я, email та 
вигадати пароль. На рис. В.1 представлено процес «Реєстрація». 
 
Рисунок В.1 – Процес «Реєстрація» 
Після створення облікового запису можна перейти до авторизації.  
На рис. В.2 представлено процес «Авторизація». 
 
 95 
 
Рисунок В.2 – Процес «Авторизація» 
Користувач може переглядати каталог готелів, кінотеатрів та театрів на 
відповідних сторінках у вибраному місті (рис. В.3). 
 
Рисунок В.3 – Каталог готелів у місті Львів 
Натиснувши на вкладку «Готель», відкриється сторінка з інформацією про 
нього (рис. В.4). 
 
 96 
 
Рисунок В.4 – Сторінка з інформацією про готель 
Авторизований користувач може зберігати готелі, кінотеатри та театри до 
списків обраного, які відображаються на сторінці профілю (рис. В.5). У 
неавторизованого користувача такої можливості немає. 
 
Рисунок В.5 – Списки обраного 
Також в сервісі реалізовано редагування свого профілю (рис. В.6). Тут можна 
змінити своє прізвище, ім’я, email та пароль. 
 
 97 
 
Рисунок В.6 – Сторінка для редагування профілю 
 
  
 
 98 
ДОДАТОК Г 
 
 
 
 
 
ВЕБ-ОРІЄНТОВАНИЙ СЕРВІС ДЛЯ ПОШУКУ МІСЦЬ ВІДПОЧИНКУ 
 
Структура бази даних 
482. ЧДТУ. 42291-01 90 01 
 
Листів 3 
 
 
 
 
 
Розробник    _____________                   Кавун Д.Р. 
 
 
 
 
 
 
 
 
 
 
Черкаси – 2024  
 
 99 
 
Рисунок Г.1 – Структура бази даних 
 
Рисунок Г.2 – Таблиця користувачів у базі даних 
 
Рисунок Г.3 – Таблиця готелів у базі даних 
 
 100 
 
Рисунок Г.4 – Таблиця кінотеатрів у базі даних 
 
Рисунок Г.5 – Таблиця театрів у базі даних 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1 01 
ДОДАТОК Д 
 
 
 
 
 
 
ВЕБ-ОРІЄНТОВАНИЙ СЕРВІС ДЛЯ ПОШУКУ МІСЦЬ ВІДПОЧИНКУ 
 
 
 
Публікація по темі кваліфікаційної роботи бакалавра 
Тези доповіді студентської науково-практичної конференції ЧДТУ, 
23-24 квітня 2024 р. 
482.ЧДТУ. 42291-01 90 02 
 
Листів 2 
 
 
 
 
 
Розробник    _____________                   Кавун Д.Р. 
 
 
 
 
 
Черкаси – 2024 
 
1 02