Будь ласка, використовуйте цей ідентифікатор, щоб цитувати або посилатися на цей матеріал: https://er.chdtu.edu.ua/handle/ChSTU/8927
Назва: Серверна частина мобільного застосунку "Студент ЧДТУ»
Автори: Заспа, Григорій Олександрович
Чоповенко, Василь Миколайович
Ключові слова: МОБІЛЬНИЙ ДОДАТОК;СТУДЕНТ;УНІВЕРСИТЕТ;СЕРВЕРНА ЧАСТИНА;НАВЧАЛЬНИЙ ПРОЦЕС;MOBILE APPLICATION;STUDENT;UNIVERSITY;SERVER-SIDE;COMPONENT;EDUCATIONAL PROCESS
Дата публікації: 9-чер-2023
Короткий огляд (реферат): АНОТАЦІЯ Чоповенко Василь Миколайович Серверна частина мобільного додатку “Студент ЧДТУ” 121 - Інженерія програмного забезпечення Черкаський державний технологічний університет Черкаси, 2023 Кваліфікаційна робота присвячена розробці серверної частини мобільного додатку для студентів. Метою є проектування та розробка зручного, функціонального мобільного додатку (серверної частини), що допоможе студентам в організації своїх навчальних завдань та повсякденних справ. У роботі проведено дослідження аналогів, збір та аналіз вимог до розроблюваного ПЗ, проектування та тестування серверної частини мобільного додатку, який містить такі функції, як запис на вибіркові дисципліни, розклад, голосування, перегляд інформації про студента та логін. Для розробки серверного ПЗ використані такі технології, як Java, Spring Framework, PostgreSQL, Hibernate ORM, Git, GitHub, Gradle. Результатом є розроблена та протестована серверна частина мобільного додатку, розгорнута в хмарному сервісі, з якою взаємодіє мобільний застосунок. Наразі активно використовується студентами університету під час навчального процесу для виконання задач, передбачених функціоналом додатку.
ANNOTATION Chopovenko Vasyl Mykolayovych The server part of the mobile application "Student CSTU" 121 - Software engineering Cherkasy State Technical University Cherkasy, 2023 The qualification work is dedicated to the development of the server-side component of a mobile application for students. The goal is to design and develop a convenient and functional mobile application (server-side) that will assist students in organizing their academic tasks and everyday activities. The work includes researching analogues, collecting and analyzing requirements for the software being developed, designing and testing the server-side component of the mobile application, which includes features such as elective course registration, schedule, voting, student information viewing, and login. The following technologies were used for the development of the server-side software: Java, Spring Framework, PostgreSQL, Hibernate ORM, Git, GitHub, and Gradle. The result is a developed and tested server-side component of the mobile application, deployed on a cloud service, which interacts with the mobile application. It is currently actively used by university students during the educational process to perform tasks provided by the application's functionality.
URI (Уніфікований ідентифікатор ресурсу): https://er.chdtu.edu.ua/handle/ChSTU/8927
Розташовується у зібраннях:121 Інженерія програмного забезпечення (Інженерія програмного забезпечення)

Файли цього матеріалу:
Файл Опис РозмірФормат 
кваліфікаційна робота бакалавра Чоповенко Василь Миколайович.pdf
  Restricted Access
16.49 MBAdobe PDFПереглянути/Відкрити    Запит копії


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

Extracted text
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ЧЕРКАСЬКИЙ ДЕРЖАВНИЙ ТЕХНОЛОГІЧНИЙ УНІВЕРСИТЕТ
Факультет інформаційних технологій і систем
Кафедра програмного забезпечення автоматизованих систем
ПОЯСНЮВАЛЬНА ЗАПИСКА
до кваліфікаційної роботи
«бакалавра»
освітній рівень
на тему: Серверна частина мобільного застосунку «Студент ЧДТУ»
Виконав: студент 4 курсу, групи ПЗ-1904
Спеціальності
121 «Інженерія програмного забезпечення»
(шифр і назва напряму підготовки)
Студент Чоповенко В.М.
(прізвище та ініціали)
Керівник Заспа Г.О.
(прізвище та ініціали)
Рецензент Крайовий В. М.
(прізвище та ініціали)
Черкаси 2023
Черкаський державний технологічний університет
повне найменування вищого навчального закладу
Факультет інформаційних технологій і систем
Кафедра програмного забезпечення автоматизованих систем
Освітній рівень бакалавр
Спеціальність 121 «Інженерія програмного забезпечення»
Освітня програма Інженерія програмного забезпечення
ЗАТВЕРДЖУЮ
Зав. кафедри ПЗАС, професор
___________ Голуб С. В.
«___» _______________ 2023 року
ЗАВДАННЯ
НА КВАЛІФІКАЦІЙНУ РОБОТУ СТУДЕНТУ
Чоповенко Василь Миколайович
(прізвище, ім’я, по батькові)
1. Тему проекту (роботи) Серверна частина мобільного застосунку «Студент ЧДТУ»
Керівник проекту (роботи) Заспа Григорій Олександрович к. т. н., доцент
(прізвище, ім’я , по батькові, науковий ступінь, вчене звання)
Затверджені наказом Черкаського державного технологічного університету від « 24 » лютого
2023 року №43/04
2. Строк подання студентом проекту (роботи) 10 червня 2023 р.
3. Вхідні дані до проекту (роботи) стандарти програмного забезпечення; процеси управління;
вимоги до проекту; календарне планування проекту; управління ресурсами
4. Зміст розрахунково-пояснювальної записки (перелік питань, які потрібно розробити)
Вступ;
Існуючі методи та засоби розвʼязання поставлених завдань;
Проектування програмного забезпечення системи;
Розробка та тестування програмного забезпечення;
Реалізація та впровадження результатів;
Висновок;
Список використаних джерел;
Додаток А. Специфікація
Додаток Б. Лістинг програми
Додаток В. Інструкція користувача
Додаток Г. Графічні матеріали
5. Перелік графічного матеріалу (з точним зазначенням обов’язкових робіт проекту);
Діаграма класів;
Діаграма пакетів;
Діаграма компонентів;
Діаграма розгортання;
Діаграма діяльності;
Діаграма послідовності;
Діаграма комунікації;
Функціональна схема системи;
6. Консультанти розділів проекту (роботи)
Прізвище, ініціали та посади Підпис, дата
Розділ
консультанта Завдання видав Завдання прийняв
1
2
3
7. Дата видачі завдання 24 січня 2023 р.
КАЛЕНДАРНИЙ ПЛАН
Строк
виконання
№
Назва етапів випускної роботи етапів Примітки
п/п
випускної
роботи
1 Постановка задачі 05.12.2022 виконано
2 Підготовка завдання 13.12.2022 виконано
3 Погодження завдання 16.12.2022 виконано
4 Затвердження завдання 17.01.2023 виконано
Основна стадія
1 Підбір матеріалів 02.02.2023 виконано
2 Аналіз шляхів вирішення поставленої задачі 27.02.2023 виконано
3 Розрахунок основних параметрів роботи 09.03.2023 виконано
4 Вибір кінцевого варіанту проектного рішення 17.03.2023 виконано
5 Оформлення первісної редакції роботи 28.03.2023 виконано
Заключна стадія
1 Узгодження прийнятих проектних рішень з 10.05.2023 виконано
керівником
2 Оформлення пояснювальної записки роботи в 19.05.2023 виконано
кінцевій редакції
3 Попередній захист роботи 22.05.2023 виконано
4 Затвердження роботи 29.05.2023 виконано
5 Рецензування роботи 01.06.2023 виконано
6 Захист роботи 08.06.2023
Студент _____________________ Чоповенко В.М.
(підпис) (прізвище та ініціали)
Керівник проекту (роботи) _____________________ Заспа Г.О.
(підпис) (прізвище та ініціали)
АНОТАЦІЯ
Чоповенко Василь Миколайович
Серверна частина мобільного додатку “Студент ЧДТУ”
121 - Інженерія програмного забезпечення
Черкаський державний технологічний університет
Черкаси, 2023
Кваліфікаційна робота присвячена розробці серверної частини мобільного
додатку для студентів. Метою є проектування та розробка зручного,
функціонального мобільного додатку (серверної частини), що допоможе
студентам в організації своїх навчальних завдань та повсякденних справ.
У роботі проведено дослідження аналогів, збір та аналіз вимог до
розроблюваного ПЗ, проектування та тестування серверної частини мобільного
додатку, який містить такі функції, як запис на вибіркові дисципліни, розклад,
голосування, перегляд інформації про студента та логін.
Для розробки серверного ПЗ використані такі технології, як Java, Spring
Framework, PostgreSQL, Hibernate ORM, Git, GitHub, Gradle.
Результатом є розроблена та протестована серверна частина мобільного
додатку, розгорнута в хмарному сервісі, з якою взаємодіє мобільний застосунок.
Наразі активно використовується студентами університету під час навчального
процесу для виконання задач, передбачених функціоналом додатку.
Ключові слова: МОБІЛЬНИЙ ДОДАТОК, СТУДЕНТ, УНІВЕРСИТЕТ,
СЕРВЕРНА ЧАСТИНА, НАВЧАЛЬНИЙ ПРОЦЕС.
ANNOTATION
Chopovenko Vasyl Mykolayovych
The server part of the mobile application "Student CSTU"
121 - Software engineering
Cherkasy State Technical University
Cherkasy, 2023
The qualification work is dedicated to the development of the server-side
component of a mobile application for students. The goal is to design and develop a
convenient and functional mobile application (server-side) that will assist students in
organizing their academic tasks and everyday activities.
The work includes researching analogues, collecting and analyzing
requirements for the software being developed, designing and testing the server-side
component of the mobile application, which includes features such as elective course
registration, schedule, voting, student information viewing, and login.
The following technologies were used for the development of the server-side
software: Java, Spring Framework, PostgreSQL, Hibernate ORM, Git, GitHub, and
Gradle.
The result is a developed and tested server-side component of the mobile
application, deployed on a cloud service, which interacts with the mobile application.
It is currently actively used by university students during the educational process to
perform tasks provided by the application's functionality.
Keywords: MOBILE APPLICATION, STUDENT, UNIVERSITY,
SERVER-SIDE COMPONENT, EDUCATIONAL PROCESS.
ЗМІСТ
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ................................................................................. 5
ВСТУП...................................................................................................................................... 6
РОЗДІЛ 1...................................................................................................................................9
ІСНУЮЧІ МЕТОДИ ТА ЗАСОБИ РОЗВ’ЯЗАННЯ ПОСТАВЛЕНИХ ЗАВДАНЬ....9
1.1 Актуальні проблеми, що виникають в процесі виконання завдань.......................... 9
1.2 Методи та засоби, які вже використовуються для усунення проблем та виконання
завдань................................................................................................................................ 11
1.3 Пошук та опис аналогів.............................................................................................. 19
1.4 Конкретизація завдань роботи....................................................................................20
РОЗДІЛ 2.................................................................................................................................22
ПРОЕКТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ СИСТЕМИ....................... 22
2.1 Моделювання предметної області..............................................................................22
2.1.1 Предметна область моделювання. Модель предметної області. Словник
предметної області....................................................................................................... 22
2.1.2 Елементи моделювання предметної області.....................................................23
2.1.3 Робоча область моделювання............................................................................. 24
2.2 Формування та аналіз вимог.......................................................................................27
2.2.1 Формування вимог до програмного забезпечення........................................... 27
2.2.2 Формування вимог за допомогою діаграми прецедентів................................ 30
2.3 Проектування логічної структури програмного комплексу.................................... 32
2.3.1 Діаграми класів....................................................................................................32
2.3.2 Діаграми пакетів..................................................................................................36
2.4 Архітектурне проектування........................................................................................37
2.4.1 Діаграма компонентів......................................................................................... 37
2.4.2 Розгортання програмної системи на апаратних засобах. Діаграма
розгортання................................................................................................................... 37
2.5 Моделювання поведінки системи.............................................................................. 38
2.5.1 Діаграма діяльності.............................................................................................38
2.5.2 Діаграма послідовності.......................................................................................41
2.5.3 Діаграма комунікації........................................................................................... 45
ЧДТУ 231924.010 ПЗ
Зм Лист № документа Підпис Дата
Розроб. Чоповенко. В. М. Літ. Лист Листів.
Керівник Заспа Г. О. Серверна частина [н] 3 136
мобільного застосунку
Н. контр. Півень О. Б. “Студент ЧДТУ” ФІТІС,
Затверд. Голуб С. В. Кафедра ПЗАС, ПЗ-1904
2.5.4 Діаграма скінченного автомату........................................................................... 45
РОЗДІЛ 3..................................................................................................................................46
РОЗРОБКА ТА ТЕСТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ........................46
3.1 Розробка програмного комплексу................................................................................46
3.1.1 Обґрунтування вибору засобів реалізації...........................................................46
3.1.2 Опис структурної (функціональної) схеми........................................................ 50
3.1.4 Розробка бази даних............................................................................................. 53
3.1.5 Розробка інтерфейсу користувача....................................................................... 60
3.1.6 Опис розробки програмних компонентів........................................................... 60
3.2 Тестування системи...................................................................................................... 69
3.2.1 Модульне тестування........................................................................................... 69
3.2.2 Інтеграційне тестування.......................................................................................72
3.2.3 Системне тестування............................................................................................72
3.2.4 Приймальне тестування....................................................................................... 83
3.2.5 Реалізація та впровадження результатів............................................................. 83
ВИСНОВОК............................................................................................................................86
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ........................................................................... 88
ДОДАТОК А............................................................................................................................ 92
ДОДАТОК Б............................................................................................................................ 94
ДОДАТОК В.......................................................................................................................... 119
ДОДАТОК Г.......................................................................................................................... 128
ЧДТУ 231924.010 ПЗ
ЧДТУ 231924.010 ПЗ
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ
БМ - База даних мобільного додатку
БСД - База даних системи деканату
БД - База даних
ПЗ - Програмне забезпечення
API - Application Programming Interface
HTTP - HyperText Transfer Protocol
MVC - Model-View-Controller pattern
HTML - HyperText Markup Language
ООП - Обʼєкто-орієнтований підхід
СУБД - Система управління базою даних
ORM - Object-relational mapping
ІС - Інформаційна система (система деканату)
URL - Uniform Resource Locator
ЧДТУ - Черкаський державний технологічний університет
UML - Unified Modeling Language
JAR - Java archive
MVP - Minimum Valuable Product
JWT - JSON Web Token
JSON - JavaScript Object Notation
SQL - Structured Query Language
JVM - Java Virtual Machine
5
ЧДТУ 231924.010 ПЗ
ВСТУП
Актуальність теми зумовлена тим, що студенти та університет часто
стикаються з низкою проблем в сфері інформаційної взаємодії:
– запису на вибіркові дисципліни;
– заяв студентів;
– розкладу;
– власних оцінок студентів;
– запитів на довідки;
– опитування студентів, наприклад, щодо оцінювання викладачів;
– інформації про викладачів та предмети;
– отримання індивідуального навчального плану.
Виконання більшості з цих завдань вимагає прямої взаємодії студентів з
різними відділами університету, витрачає певний час та, іноді, є причиною
непорозумінь, які в подальшому приводять до необхідності проходження того
самого шляху по колу (яскравим прикладом є заяви, при написанні яких часто
виникають помилки, а для виправлення необхідно переписувати їх по новому).
У випадку опитувань, вони вимагають студента бути присутнім в
університеті, що не завжди є можливим, або збігається з розкладом чи
бажаннями студента.
На даний момент не існує універсального інструменту, який покривав би
всі ці випадки. Для прикладу, в університеті вже є сервіс розкладу. Але для
перегляду розкладу за вибірковими дисциплінами необхідно виконати
додатковий запит, так як вони відносяться до іншої групи. Крім того, тут не
враховується факт того, що не всі вибіркові дисципліни, які привʼязані до
конкретної групи є тими, на які записаний студент.
Всі вище описані факти вимагають створення надійного рішення усіх
проблем студентського життя в одному місці з максимальною доступністю для
кожного.
Мета роботи: надати студентам зручний доступ до необхідної інформації,
робити навчальний процес більш цікавим та зручним, а також допомогти їм з
6
ЧДТУ 231924.010 ПЗ
плануванням свого часу.
Завдання: проектування та розробка частини мобільного застосунку для
студентів, а саме серверне ПЗ для нього.
Об’єкт розробки: серверна частина мобільного застосунку “Студент
ЧДТУ”.
Методи проектування та конструювання:
– декомпозиція за рахунок розбивання складної задачі на менші складові;
– системний підхід, який дає можливість оцінити задачу, її роль та місце
в існуючій системі;
– Agile Scrum [1] – інкрементальна модель конструювання ПЗ, при якій
робота поділяється на спринти (1-2 тижні), протягом якого відбувається
планування задач, розробка нового функціоналу, виправлення існуючих
помилок та тестування;
– конструювання з можливістю перевірки – передбачає написання
програми з можливістю подальшого тестування;
– мінімізація складності – несе в собі набір технік, необхідних для
написання простого та зрозмулого коду, який буде легко
підтримуватись.
Інструментарій
Мовою програмування було обрано Java [2], так як вона широко поширена
для розробки серверних програм, має велику кількість бібліотек та
фреймворків, надійність яких підтверджена мільйонами користувачів.
Фреймворком для розробки було обрано Spring Framework [3]. Він є
одним з найпопулярніших Java фреймворків для серверної розробки і
складається з декількох модулів, кожен з яких надає функціональність для
вирішення певного роду задач (Spring Security, Spring MVC, Spring Testing
тощо).
Базою даних було обрано PostgreSQL [4], яка за роки активного розвитку
заслужила міцну репутацію. Працює на всіх операційних системах з
дотриманням стандарту SQL та є продуктом з відкритим вихідним кодом.
7
ЧДТУ 231924.010 ПЗ
Інтеграція з системою деканату. В університеті уже існує система
деканату, яка активно використовується деканатами та навчально-методичним
відділом уже кілька років. Застосунок, який планується розробити в рамках
даної роботи, повинен інтегруватись з існуючою системою деканату, так як вона
має всі необхідні дані про студентів. Крім того, застосунок буде доповнювати
існуючу систему, додаючи нові дані (наприклад, дані про записи на вибіркові
дисципліни).
Опис отриманих результатів: результатом роботи є спроектований та
розроблений робочий серверний модуль з усією функціональністю, описаною в
пункті 1.4, з яким взаємодіє мобільний застосунок “Студент ЧДТУ”. Даний
додаток зараз широко використовується студентами, так як містить необхідний
для них функціонал і продовжує доповнюватись новим.
Практичне значення отриманих результатів: мобільний застосунок,
для якого була спроектована та розроблено дане серверне ПЗ, уже
використовується студентами, полегшуючи їхню взаємодію з інформаційним
простором університету. Студенти активно записуються на вибіркові
дисципліни через наш додаток, а працівники навчально-методологічного відділу
слідкують за цим процесом, маючи на руках усю необхідну інформацію щодо
процесу запису.
Розклад зменшує кількість повторюваних дій, які студентам необхідно
пройти щоб переглянути розклад використовуючи попередній сервіс, а
генерація заяв спростила процес їхнього написання і зменшила ймовірність
помилок.
Модуль голосувань дає можливість студентам взяти участь в них без
необхідності відвідування університету.
Особистий внесок автора: в повному обсязі розроблено серверну
частину для мобільного застосунка «Студент ЧДТУ».
8
ЧДТУ 231924.010 ПЗ
РОЗДІЛ 1
ІСНУЮЧІ МЕТОДИ ТА ЗАСОБИ РОЗВ’ЯЗАННЯ ПОСТАВЛЕНИХ
ЗАВДАНЬ
1.1 Актуальні проблеми, що виникають в процесі виконання завдань
Технічний борг і надмірна розробка
Технічна заборгованість [5] — це термін, при якому розробники
порушують правила SOLID [6] і DRY [6], наприклад пропускаючи тестування
або перегляд коду та рефакторинг [7]. Іноді це відбувається тому, що проект
відстає від графіка, або він перевищив бюджет. У цій ситуації розробники йдуть
на прорахований ризик і просувають MVP на ринок, перш ніж він буде готовий.
На жаль, іноді розробники пропускають ці кроки просто тому, що забули або
вважають їх марною тратою часу.
В інших випадках розробники відволікаються або надто зосереджуються
й забувають про принцип KISS [6]. Отже, вони надто ускладнюють несуттєві
речі за допомогою складних прийомів. По суті, замість того, щоб зосередитися
на функціях, які впливають на загальну продуктивність, або проблемних місцях,
вони надмірно оптимізують функції, які не є такими ключовими.
В обох ситуаціях результатом є заплутаний код, до якого розробники не
торкаються, боячись зламати його. Про рефакторинг, оновлення або
масштабування проекту на даному етапі не може бути й мови.
Недостатнє тестування
Тестування [5] є важливою частиною процесу розробки. Це дозволяє
розробникам знаходити баги та помилки та своєчасно їх виправляти. Хоча
неможливо протестувати все, важливо, щоб розробники писали та запускали
тести на кожному етапі для якомога більшої кількості сценаріїв. Неналежне
тестування або повний пропуск тестів створює непередбачувану і нестабільну
поведінку. Окрім цього, рефакторинг є неможливий, оскільки розробники
ніколи не дізнаються, що не так і чому.
Відсутність перевірки коду та статичного аналізу коду
Перевірки коду [5] є широко поширеною практикою при розробці. Коли
9
ЧДТУ 231924.010 ПЗ
розробник готовий додати новий функціонал до основної версії продукту, код
передається іншому розробнику на перевірку. Ця особа вручну перевіряє кожен
рядок, і якщо все гаразд, код надсилається до основної гілки.
Статичний аналіз коду, також відомий як аналіз вихідного коду, є більш
автоматизованим процесом, який також перевіряє код перед його розгортанням.
Розробники використовують інструменти для статичного аналізу, які
перевіряють його на відповідність інструкціям щодо розробки, дотримання
стандартів і звітують про це.
Хаос технологій та інструментів
Існує незліченна кількість [5] мов програмування, фреймворків, бібліотек
та інструментів, які розробники використовують у своїх щоденних завданнях.
Як наслідок, кожен розробник має своїх фаворитів і часто не погоджується один
з одним щодо того, яка технологія найкраща для кожного сценарію.
Відсутність автоматичного резервування
Говорячи про автоматичне резервне копіювання [5], мається на увазі
регулярне автоматичне збереження копії продакшн даних. Під продакшн
даними мається на увазі як кодова база, так і вся інформацію в базах даних.
Однак, хоча код можна відтворити або переписати, дані користувача є
незамінними. Стає зрозуміло, чому частково або повністю видалена БД через
баг чи просто людську помилку є величезною проблемою. І тут на допомогу
приходить автоматичне резервне копіювання. Якщо якась із баз даних буде
пошкоджена, все, що потрібно зробити, це відновити попередню версію. Так,
деякі дані можуть бути втрачені, але більшість із них буде в безпеці.
Ускладнені моделі даних
Моделі даних [5] є першою частиною проектування бази даних.
Моделювання даних визначає, які дані зберігає БД, як вони збираються та яка
кореляція між кожним елементом даних.
Погане моделювання в цьому випадку впливає на загальну
продуктивність, оскільки запити займають набагато більше часу. Крім того,
оновлення та підтримка інфраструктури буде дорогою і дуже складною у
10
ЧДТУ 231924.010 ПЗ
довгостроковій перспективі.
SQL-інʼєкції
SQL інʼєкції [8] — це вразливість веб-безпеки, яка дозволяє зловмиснику
втручатися в запити, які програма робить до своєї бази даних. Зазвичай це
дозволяє зловмиснику переглядати дані, які вони зазвичай не можуть отримати.
Це може включати дані, що належать іншим користувачам, або будь-які інші
дані, до яких має доступ сама програма.
Відсутність логів
Логування [5] допомагають розробникам, відповідальним за
обслуговування, економити величезну кількість часу. На жаль, воно не таке
популярне серед розробників програмного забезпечення, як хотілося б.
Порівняно з трасуванням стека (популярна стратегія розробників), ведення
логів дозволяє не лише визначити, що та де пішло не так, але й те, як це
сталося.
1.2 Методи та засоби, які вже використовуються для усунення
проблем та виконання завдань
Фреймворки
На даний момент існує безліч фреймворків, які використовуються для
серверної розробки. Вони мають свої особливості [10], використовують різні
мови для розробки і направлені на виконання певних задач.
Express.js
Минулого року Express.js [9] використовували понад 23%
бекенд-розробників.
Створений на основі NodeJS, Express утримує своє місце серед
найпопулярніших фреймворків веб-додатків протягом багатьох років завдяки
своїй чудовій продуктивності, мінімалістичному дизайну та надійному набору
функцій.
Велика частина популярності Express.js, ймовірно, зводиться до опори на
Node.JS і мову JavaScript. Використання мови веб-розробки за замовчуванням
робить фреймворк таким, який легко підібрати для розробників, які шукають
11
ЧДТУ 231924.010 ПЗ
інструмент, який може забезпечити повний пакет технологій для їхніх програм.
Проте Express здатний на більше, ніж могли очікувати розробники, які не
знайомі з його інструментами.
Гнучкість, надійність і продуктивність — ось ключові слова, пов’язані з
розробкою Express.js, і ключові причини того, чому фреймворк займає перше
місце як найпопулярніший серверний фреймворк у всьому світі.
ASP.NET Core
Минулого року ASP.NET [9] Core використовували 20% серверних
веб-розробників.
Фреймворк Microsoft з відкритим вихідним кодом для розробки
веб-додатків стає все сильнішим після того, як компанія почала серйозний
перегляд свого технологічного пакету. З моменту випуску ASP.NET Core у 2016
році ця технологія стала флагманською платформою бренду Microsoft.
Відходячи від попередніх підходів .NET Framework, ASP.NET Core — це
кросплатформна технологія, яка підтримує розробку та розгортання в Windows,
macOS і Linux в додачу до розширеної підтримки хмарних додатків. Крім того,
ці інструменти значно ефективніші за інші пов’язані веб-технології, як
показують тести.
Spring
У 2021 році Spring [9] використовували понад 16% веб-розробників.
Порівняно з найпопулярнішими фреймворкам, Spring має більш
впевнений дизайн і пропонує багатий набір важких функцій. Хоча дизайн Spring
може бути негативним для невеликих проектів, розробники отримують один із
найпродуктивніших серверних веб-фреймворків, доступних наразі, як
компроміс.
Спираючись на Java для розробки додатків, Spring зазвичай
використовується для широкого спектру програм, починаючи від мікросервісів і
закінчуючи великими хмарними програмами. У порівнянні бенчмарків Spring
виявився найефективнішою серверною веб-платформою, протестованою з
найближчими конкурентами.
12
ЧДТУ 231924.010 ПЗ
Будучи зрілим і високорозвиненим рішенням Java та Spring є чудовим
вибором для команд, які шукають продуктивний, комплексний і високо
масштабований підхід до розробки веб-додатків.
Django
У 2021 році Django [9] використовували 13% бекенд-розробників.
Django — це веб-платформа на основі Python, яка цінує чисту архітектуру
та дизайн як головний пріоритет для своїх програм. Зріла платформа з
відкритим вихідним кодом, яка багато запропонувала розробникам за останні 16
років. Фреймворк може похвалитися тим, що він є безпечним, масштабованим і
універсальним рішенням для розробників.
Хоча Django менш продуктивний, ніж Spring або Express, він дуже
помітний тим, що ефективно витрачає час і ресурси розробників на створення
повнофункціональних веб-програм. Django постачається в комплекті з
великими пакетами та інструментами для вирішення типових завдань, таких як
аутентифікація, RSS-канали та інші.
Laravel
У 2021 році Laravel [9] використовували трохи менше 11% розробників.
Найпопулярніший фреймворк PHP серед веб-розробників на сьогодні,
Laravel – це ефективний серверний фреймворк, який так само цінує архітектуру
та дизайн серед своїх найвищих пріоритетів. Найбільш помітними функціями
Laravel і, можливо, причиною, чому він залишався таким популярним протягом
останнього десятиліття, є його модульна система пакетів і вбудований менеджер
залежностей.
Використовуючи потужний менеджер пакетів, Laravel дозволяє
розробникам легко додавати функції до своїх програм, що робить його
інструментом, який економить час розробки, є безпечним і високоефективним.
Завдяки чудовим інструментам тестування, підтримці архітектури MVC і
вбудованим шаблонам, одна з ключових причин, чому Laravel залишається
таким популярним, полягає в тому, що він дозволяє розробникам створювати
потужні та надійні програми за неймовірно короткі терміни.
13
ЧДТУ 231924.010 ПЗ
Хоча даний фреймворк не може похвалитись високими показниками
продуктивності, Laravel компенсує недоліки в часі розробки, безпеці та
виняткових програмах, які він підтримує.
Ruby on Rails
У 2021 році Ruby on Rails [9] використовували трохи менше 8% серверних
веб-розробників.
Найдосконаліший фреймворк у цьому списку, незмінна популярність
Ruby протягом майже двох десятиліть, відколи він став доступний, багато
говорить про можливості та корисність фреймворку. Вважається, що близько 5%
Інтернету наразі підтримується Ruby on Rails.
Один із найбільш фреймворків, доступних на даний момент, Ruby
постійно входить до 10 найулюбленіших веб-фреймворків. Він віддає пріоритет
ефективності, гарному дизайну та продуктивності серед найважливіших
атрибутів.
Як зріле рішення серед більш сучасних конкурентів, Rails не є
найефективнішим підходом до бекенд-розробки, але він отримав високу оцінку
серед своїх прихильників для створення високоякісного програмного
забезпечення.
СУБД
СУБД поділяють на реляційні та нереляційні.
Реляційна база даних — це тип сховища даних, який організовує дані в
таблиці, пов’язані одна з одною. SQL (Structured Query Language) є ядром цих
систем, оскільки вона використовується для зв’язку з цими базами даних і
керування ними.
Нереляційна бази даних — це нетаблична БД, яка використовує різні
моделі даних для зберігання, керування та доступу до даних.
В даній роботі планується використовувати реляційну базу даних, так як
між моделями предметної області існують складні звʼязки, які можна виразити
засобами реляційних баз.
MySQL
14
ЧДТУ 231924.010 ПЗ
Це одна з найпопулярніших систем реляційних баз даних. Спочатку
MySQL [11] був відкритим вихідним кодом, а тепер належить корпорації Oracle.
Плюси MySQL
Безкоштовне встановлення. MySQL Community Edition можна
завантажити безкоштовно. Звичайно, є й інші опції з передоплатою, такі як
Enterprise або Cluster із більшою функціональністю.
Простий синтаксис і помірна складність. Структура та стиль MySQL
дуже прості. Наприклад, більшість завдань можна виконувати прямо в
командному рядку, скорочуючи кроки розробки.
Хмарна сумісність. За своєю природою бізнес-орієнтований і спочатку
розроблений для Інтернету, MySQL підтримується найпопулярнішими
хмарними провайдерами. Він доступний на таких провідних платформах, як
Amazon, Microsoft та інших.
Мінуси MySQL
Проблеми масштабованості. MySQL не створювався з урахуванням
масштабованості, яка закладена в його коді. Теоретично можливо масштабувати
MySQL, але для цього знадобиться більше інженерних зусиль порівняно з
будь-якою базою даних NoSQL.
Часткова підтримка відкритого коду. Хоча MySQL має частину з
відкритим вихідним кодом, вона здебільшого знаходиться під ліцензією Oracle.
Це обмежує спільноту MySQL щодо вдосконалення СУБД.
Обмежена відповідність стандартам SQL. Структурована мова запитів
має певні стандарти. MySQL не повністю їх дотримується, тобто MySQL не
підтримує деякі стандартні функції SQL. З іншого боку, MySQL має деякі
розширення та відмінні функції, які не відповідають стандартам Structured
Query Language.
Oracle
Oracle [11] — це система управління реляційними базами даних, створена
та керована корпорацією Oracle. У своїх останніх випусках вона
перелаштувалась на хмарні обчислення. Ліцензування ядра бази даних Oracle є
15
ЧДТУ 231924.010 ПЗ
повністю запатентованим, доступні як безкоштовні, так і платні варіанти.
Плюси Oracle
Інновації для щоденного робочого процесу. Починаючи з випуску Oracle
12c, регулярно з’являлися нові технології хмарних обчислень. З кожним новим
випуском Oracle намагається не відставати від темпів інновацій,
зосереджуючись на інформаційній безпеці, включаючи активний захист даних,
розділення, покращене резервне копіювання та відновлення.
Сильна технічна підтримка та документація. Oracle забезпечує гідну
підтримку клієнтів і надає вичерпну технічну документацію на багатьох
ресурсах.
Велика місткість. Багатомодульне рішення Oracle дозволяє приймати й
обробляти величезну кількість даних. Завдяки нещодавно випущеній функції
багатокористувацької підтримки, архітектура бази даних тепер спрощує
упаковку багатьох баз даних і безперебійне керування ними.
Мінуси Oracle
Висока вартість. Хоча база даних Oracle має безкоштовні версії, вони
дуже обмежені з точки зору функціональності. Стандартна версія, яка не
включає всі доступні функції, коштує 17 500 доларів США за одиницю.
Enterprise Edition коштує понад 47 000 доларів США за одиницю.
Ресурсоємна технологія. Базі даних Oracle потрібна потужна
інфраструктура. Для інсталяції потрібно не лише багато місця на диску, але й
доведеться враховувати постійні оновлення апаратного забезпечення, якщо вона
розгортаєте локально.
Складне навчання. База даних Oracle не є системою, якою можна почати
користуватися відразу. Для її запуску краще мати сертифікованих інженерів
Oracle DB. Документація Oracle, хоч і охоплює багато питань, іноді може бути
заплутаною. Отже, для встановлення та запустку базу даних Oracle, доведеться
розглянути можливість найняти спеціалізованих експертів.
PostgreSQL
PostgreSQL [11] має схожості з MySQL. Вона спрямована на посилення
16
ЧДТУ 231924.010 ПЗ
стандартів відповідності та розширюваності. Отже, ця СУБД може обробляти
будь-яке робоче навантаження, як для одномашинних продуктів, так і для
складних програм.
Плюси PostgreSQL
Чудова масштабованість. Вертикальна масштабованість є відмінною
рисою PostgreSQL, на відміну від СУБД MySQL.
Підтримка спеціальних типів даних. PostgreSQL за замовчуванням
підтримує велику кількість типів даних, таких як JSON, XML та інші.
PostgreSQL використовує його переваги, будучи однією з небагатьох реляційних
баз даних із сильною підтримкою функцій NoSQL.
Легко інтегровані інструменти сторонніх розробників. Система
керування базами даних PostgreSQL має потужну підтримку додаткових
інструментів, як безкоштовних, так і комерційних.
Підтримка з відкритим кодом і спільнотою. PostgreSQL є повністю
відкритим вихідним кодом і підтримується спільнотою, що зміцнює її як цілісну
екосистему.
Мінуси Postgre
Невідповідна документація. Незважаючи на те, що PostgreSQL має
велику спільноту та надає потужну підтримку своїм учасникам, документації
все ще бракує послідовності та повноти.
Відсутність інструментів звітності та аудиту. Істотним недоліком
PostgreSQL є відсутність інструментів ревізії, які б показували поточний стан
бази даних. Необхідно постійно перевіряти, чи не йде щось не так. Завжди існує
ризик, що інженери БД помітять збій занадто пізно.
MSSQL
Як повністю комерційний інструмент, Microsoft SQL Server [11] є однією з
найпопулярніших реляційних СУБД, на додаток до MySQL, PostgreSQL і Oracle.
Він добре справляється з ефективним зберіганням, зміною та керуванням
реляційними даними. Для взаємодії з базами даних SQL Server інженери БД
зазвичай використовують мову Transact-SQL (T-SQL), яка є розширенням
17
ЧДТУ 231924.010 ПЗ
стандарту SQL.
Плюси MSSQL
Різноманітність версій. Microsoft SQL Server надає широкий вибір
різних параметрів із різноманітними функціями. Наприклад, версія Express із
безкоштовною базою даних пропонує інструменти початкового рівня.
Developers опція дозволяє створювати та тестувати програми, включаючи деякі
корпоративні функції, але без ліцензії на робочий сервер. Для більших проектів
також існують версії Web, Standard і Enterprise із різним ступенем можливостей
керування і рівнів обслуговування.
Комплексні рішення для бізнес-даних. З фокусом на переважно
комерційних рішеннях, MSSQL надає багато додаткових функцій для бізнесу.
Крім того, він надає інструменти для загального адміністрування даних,
онлайн-аналітичної обробки та інтелектуального аналізу даних, а також опції
для створення звітів і візуалізації.
Багата документація та допомога громади. Оскільки Microsoft SQL
Server призначений для комплексного обслуговування бази даних, повна
онлайн-документація також відображає цю концепцію. Крім того, Microsoft
Premier надає доступ до спеціальної підтримки спільноти Microsoft, що є
перевагою, коли інженеру БД потрібна допомога.
Підтримка хмарних баз даних. Будучи частиною узгодженої екосистеми
Microsoft, MSSQL можна інтегрувати з хмарою Microsoft, базою даних SQL
Azure або SQL Server на віртуальних машинах Azure.
Мінуси MSSQL
Висока вартість. MSSQL Server, який використовується в основному в
корпоративному масштабі, залишається одним із найдорожчих рішень.
Говорячи про цифри, наразі версія Enterprise коштує понад 14 000 доларів США
за ядро, яке продається у вигляді пакетів із 2 ядрами.
Нечіткі умови ліцензії. Інша проблема — процес ліцензування, що
постійно змінюється. Саму стратегію ціноутворення важко зрозуміти, а
елементи, включені в конкретне видання, є плаваючими, мають тенденцію
18
ЧДТУ 231924.010 ПЗ
переходити від одного до іншого.
Складний процес налаштування. Для початківців, яким доводиться
працювати з великими наборами даних, робота з оптимізацією запитів і
налаштуванням продуктивності може бути проблематичною.
1.3 Пошук та опис аналогів
KNU Online
Київський національний університет ім. Т. Шевченка має застосунок [12]
для студентів з наступними можливостями [13]:
– електронний кабінет студента, в якому він може: оцінити викладачів,
звʼязатись з ними, деканом та адміністрацією гуртожитку через онлайн
чат, отримати або здати завдання, замовити довідки або скористатись
довідковою інформацією;
– електронний кабінет викладача, в якому він може розмістити навчальну
інформацію (лекції, завдання, тести, лабораторні роботи, практичні
роботи, літературу в електронному форматі), відповідати на питання
студентів в онлайн чаті;
– спеціальний розділ для іноземних студентів;
– перегляд новин університету;
– електронний деканат;
– цифрова бібліотека.
Мій НУВГП
Національний університет водного господарства та природокористування
має власний мобільний застосунок для викладачів та студентів [14]. На даний
момент в додатку є такі можливості:
– перегляд вступної кампанії університету, освітніх програм та інша
інформація для абітурієнтів, яка надходить з сайту університету;
– пошук та перегляд розклад, який наповнюється через існуючу систему
“Деканат”
– добірка новин та оголошень, яка також підтягується з основного сайту
університету;
19
ЧДТУ 231924.010 ПЗ
– для студентів перегляд, а для викладачів - заповнення журналу
успішності студентів, яке здійснюється через корпоративну пошту та
систему авторизації Google;
– перегляд інформації про кафедри, викладачів, а також - функціонал
пошуку аудиторій.
Рис. 1.1 - Інтерфейс мобільного додатку “Мій НУВГП” [15]
1.4 Конкретизація завдань роботи
Серверна частина повинна надавати REST API з наступним
функціоналом:
Запис на вибіркові дисципліни
– студент може обрати вибіркові дисципліни в першому етапі запису;
– під час запису студент може бачити правила запису на дисципліни;
– студент може переглянути обрані дисципліни після завершення
першого етапу;
– у випадку дискваліфікації якогось з предметів, обраних студентом, він
може дозаписатись на необхідну кількість дисциплін на другому етапі;
– після завершення другого етапу студент може переглянути фінальний
список дисциплін, на які він записався.
Розклад
– студент може переглянути розклад на поточний семестр;
– вибіркові дисципліни, на які студент не записаний, не повинні
20
ЧДТУ 231924.010 ПЗ
відображатись;
– студент може знайти розклад вказавши необхідну групу або викладача.
Інформація про студента
– студент може переглянути загальну інформацію про себе (курс,
спеціальність, групу, освітню програму тощо).
Голосування
– студент може переглянути список поточних голосувань;
– студент може взяти участь в активних голосуваннях;
– студент може переглянути інформацію про голосування.
Генерування заяв
– студент може згенерувати найбільш поширені заяви, ввівши необхідні
дані; результатом даної операції буде відображення готової заяви з
підставленими даними студента.
Логін
– студент може авторизуватись в додатку ввівши власний логін та пароль.
21
ЧДТУ 231924.010 ПЗ
РОЗДІЛ 2
ПРОЕКТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ СИСТЕМИ
2.1 Моделювання предметної області
2.1.1 Предметна область моделювання. Модель предметної області.
Словник предметної області
Рис. 2.1 - Модель предметної області
Факультет - підрозділ університету, що займається певною галуззю
знань.
Спеціальність - напрямок підготовки фахівців.
Освітня програма - це документ, який визначає навчальні цілі, зміст та
організацію навчання для певного рівня освіти або навчального закладу.
Кафедра - це структурний підрозділ вищого навчального закладу, який
займається певною галуззю науки, дисципліною або спеціалізацією.
Група - студенти, які навчаються разом на одній спеціальності.
22
ЧДТУ 231924.010 ПЗ
Вибіркова дисципліна - це навчальний предмет, який студент може
вибрати для вивчення з числа запропонованих в навчальному плані свого
факультету або спеціальності.
Параметри вибору вибіркових дисциплін - це інформація про період
запису на вибіркові дисципліни, яка містить дати початку і закінчення турів
вибору дисциплін, мінімальну та максимальну кількість студентів, які можуть
записатись на одну дисципліну.
Освітній ступінь - це рівень кваліфікації, який підтверджується
відповідним документом про закінчення навчального закладу певного рівня.
Розклад - графік проведення занять для конкретної групи.
Заява - це письмове звернення, у якому студент висловлює свої
побажання, прохання, або подає документи до відповідних органів
університету.
2.1.2 Елементи моделювання предметної області
Для моделювання предметної області використовується мова UML. На
етапі проектування будуть наведені діаграми, зображені на рисунку нижче.
Рис. 2.2 – Основні діаграми UML [39]
23
ЧДТУ 231924.010 ПЗ
Дані графічні схеми описують предметну область проекту, дають
уявлення про роботу системи, як в загальному вигляді, так і на рівні
компонентів та їх взаємодії. Слідуючи цим діаграмам можна відносно швидко
зрозуміти структуру нашого додатку, його інтеграцію з іншими системами
університету.
2.1.3 Робоча область моделювання
Вибіркові дисципліни
Процес вибору вибіркових дисциплін ділиться на два тури: якщо
вибіркові дисципліни, які студент обрав у першому турі, не набрали необхідної
кількості студентів (були дискваліфіковані), то йому дається можливість
дообрати серед тих дисциплін, які не були дискваліфіковані. Кожен тур має 4
дати:
– початок першого туру;
– завершення першого туру;
– початок другого туру;
– завершення другого туру.
Між першим і другим туром відбувається дискваліфікація предметів, які
не набрали необхідної кількості студентів. Ці кількості задає працівник
навчально-методичного відділу. Крім того, він може записати студента на
дисципліну власноруч або зробити заміщення певних предметів (відписати і
одразу ж записати студента на вибіркові дисципліни за умови, що семестри цих
дисциплін збігаються).
Студенти скороченої форми навчання мають формальний та реальний
курси (наприклад, студент, який прийшов на 2 курс з коледжу буде мати
реальний курс - 2, але формальний - 1), які при реєстрації необхідно
враховувати. Крім того, вони реєструються на вибіркові дисципліни два рази:
при вступі і під час загального вибору.
В рамках роботи над вибірковими дисциплінами було введено кілька
статусів, які відправляються з сервера для координації дій на стороні
24
ЧДТУ 231924.010 ПЗ
мобільного додатку. Ці статуси сигналізують мобільному додатку про дії, які
необхідно виконати в даний момент вибору дисциплін.
BEFORE_FIRST_ROUND - період перед першим туром.
FIRST_ROUND - перший тур.
BETWEEN_FIRST_AND_SECOND_ROUND - період між першим та
другим туром.
SECOND_ROUND - другий тур.
AFTER_SECOND_ROUND - період після другого туру.
Більш детально ознайомитись з схемою роботи на основі вище наведених
статусів можна на малюнку нижче.
Рис. 2.3 - Набір дій мобільного додатку на основі статусів, які повертаються з
сервера в певний момент вибору дисциплін.
Розклад
Студенти можуть переглядати розклад з урахуванням вибіркових
дисциплін.
25
ЧДТУ 231924.010 ПЗ
На другому курсі вибіркові дисципліни обʼєднуються під однією групою,
тому є шанс, що не всі з дисциплін в розкладі є тими, на які записаний студент.
Тому необхідно фільтрувати такі дисципліни, щоб залишити лише ті, на які
записаний студент.
Проблемою є той факт, що при введенні інформації в систему розкладу,
яка знаходиться за межами університету, існує шанс допущення помилки в назві
дисципліни. Тому варто передбачити порівняння назв дисциплін з певним
порогом помилок (в нашому випадку порогом є 4 допустимі помилки в назві).
Функціонал фільтрації не гарантує 100% точності, тому студент може
ввімкнути або вимкнути його. Для цього передбачено перемикач на екрані
розкладу та відповідний параметр (прапорець), який приймає сервер.
Генерація заяв
Для більшості заяв були сформовані шаблони, на основі яких система
повинна генерувати готову заяву, підставляючи інформацію студента, яка вже є
в системі. Частина інформації отримується від студента, тому передбачено поля
для введення даних відповідно до типу заяви.
Опитування
У опитувань є варіанти голосувань/кандидати. Цим варіантам можуть
бути присвоєні ідентифікатори факультетів. Лише студенти цих факультетів
можуть голосувати за дані варіанти. Якщо такий ідентифікатор відсутній, то
варіант доступний для вибору усім студентам, незалежно від їхнього
факультету.
Крім того, голосування мають максимальне число варіантів, яке необхідно
обрати під час опитування/голосування. Це число також може відрізнятись
залежно від факультету. Голос студента, який не обрав необхідну кількість
варіантів, не буде збережено в системі. Процес збереження голосу є анонімним
(в системі не зберігається інформація про те, за який варіант проголосував
студент). У варіанту голосування є атрибут, який показує кількість відданих за
нього голосів.
Інформація про студента
26
ЧДТУ 231924.010 ПЗ
Студент може навчатись на декількох спеціальностях. Якщо студент має
хоча б одну активну спеціальність, то в мобільному він може перемикатись
лише між активними спеціальностями.
У випадку, якщо всі спеціальності студента є неактивним, варто знайти ті
спеціальності, які знаходяться в академічній відпустці і дозволити перемикатись
між ними. Але в такому випадку функціонал буде обмежений (присвоєно
відповідну роль користувачеві).
Для кожної спеціальності необхідно обраховувати формальний та
реальний курс, який треба показувати в інформації про спеціальність студента.
2.2 Формування та аналіз вимог
2.2.1 Формування вимог до програмного забезпечення
В проекті мобільного додатку для студентів в ролі замовника, а отже, і
укладача вимог виступає університет та структури, які діють в його стінах
(навчально-методичний відділ, деканат тощо). На основі цього, було зібрано
необхідну інформацію для складання первинних та детальних вимог для
розробки даного додатку.
Первинні і детальні вимоги
ПЕРВИННІ ВИМОГИ
1 Студент може залогінитись в додатку.
2 Студент може взяти участь в записі на вибіркові дисципліни.
3 Студент може переглядати розклад в додатку.
4 Студент може згенерувати необхідну йому заяву ввівши власні дані.
5 Студент може взяти участь в голосуванні.
6 Студент може переглянути інформацію про себе.
ДЕТАЛЬНІ ВИМОГИ
1.1 При введенні вірного логіна та пароля студент може залогінитись в
додатку.
1.2 Лише аутентифікований користувач має доступ до функціоналу
додатку.
27
ЧДТУ 231924.010 ПЗ
1.3 Студент, який має декілька спеціальностей може перемикатись між
ними.
1.4 Обрана спеціальність впливає на:
– те, для якої групи буде автоматично завантажуватись розклад;
– запис на вибіркові дисципліни;
– інформацію в заявах;
– інформацію в профілі студента.
1.5 У випадку відсутності активних спеціальностей і наявній
спеціальності в академічній відпустці, студенту доступний лише обмежений
функціонал мобільного додатку: розклад, генерація заяв, перегляд власної
інформації, участь в опитуваннях.
1.6 Студенту в академічній відпустці не дозволено приймати участь у
записі на вибіркові дисципліни;
2.1 Враховувати, що деякі студенти не можуть обирати вибіркові
дисципліни:
– 4 курс бакалаврату;
– 2 курс магістратури.
2.2 Студент повинен бачити вибрані в минулому році дисципліни, доки
не зʼявляться параметри вибору вибіркових дисциплін в основній системі
університету (вноситься працівниками навчально-методичного відділу).
2.3 Студент повинен бачити кількість часу до початку першого туру,
якщо наявні параметри вибору.
2.4 Студент повинен бачити інформацію про поточний тур, таку як:
номер туру, час до його початку або закінчення, навчальний рік на який
ведеться запис.
2.5 Студент повинен бачити правила вибору вибіркових дисциплін.
2.6 Студент повинен отримувати лише ті вибіркові дисципліни, які його
стосуються (тут враховується його галузь знань, ступінь, семестр).
2.7 Між першим і другим туром показувати дисципліни, на які студент
записався в першому турі, а також час до початку другого туру.
28
ЧДТУ 231924.010 ПЗ
2.8 В другому турі необхідно показувати список вибіркових дисциплін,
серед яких студент повинен вибрати собі недостаючі, але тільки у випадку якщо
серед його дисциплін, обраних в першому турі, є дискваліфіковані.
2.9 Для студентів скороченої форми передбачити можливість
записатись двічі в одному навчальному році при вступі та під час загального
вибору.
3.1 Відправляти розклад студента враховуючи його вибіркові
дисципліни.
3.2 У випадку, коли вибіркові дисципліни обʼєднуються однією групою
(на 2 курсі), необхідно відкидати ті дисципліни, на які студент не записаний.
3.3 Студент може переглядати розклад для груп, вказавши необхідну.
3.4 Студент може переглядати розклад для викладачів.
3.5 Студент може вказати часовий проміжок, на який він планує
отримати
4.1 Студент може бачити список заяв, які він може згенерувати.
4.2 Автоматично підтягувати в шаблон заяви дані про студента, які є в
системі університету.
4.3 Передбачити можливість отримувати дані від студента, якщо такі
необхідні в заяві.
5.1 Студент може бачити лише активні голосування.
5.2 Студент може брати участь лише в активних голосуваннях.
5.3 Для кожного голосування може бути встановлено необхідну
кількість кандидатів, за яких студент повинен проголосувати. Ця кількість
варіюється в залежності від факультету.
5.4 У кандидата голосування може бути вказано факультет, лише
студенти якого можуть проголосувати за нього.
5.5 За відсутності вказаного факультету, кандидат вважається
доступним для голосування усім студентам.
6.1 Студент може бачити інформацію про себе.
29
ЧДТУ 231924.010 ПЗ
6.2 В залежності від обраної спеціальності показувати інформацію, яка
повʼязана з даною спеціальністю.
Вимоги замовника і розробника. Функціональні та нефункціональні
вимоги
Розрізняють дві категорії представлення вимог: вимоги замовника
(первинні вимоги) і вимоги розробника (детальні вимоги). Відрізняються вони
одна від одної мірою опрацювання описів. Первинні, детальні та функціональні
вимоги описані в попередньому пункті.
Нефункціональні вимоги:
– використовувати існуючу систему університету для доступу до даних;
– убезпечити дані від несанкціонованого доступу;
– використовувати JWT [16] для аутентифікації мобільного додатку, між
сервером мобільного додатку та системою деканату;
– дозволити доступ до всіх ресурсів лише активним студентам; студенти
в академічній відпустці повинні мати обмежений доступ.
2.2.2 Формування вимог за допомогою діаграми прецедентів
Рис. 2.4 - Діаграма прецедентів функціоналу логіну
Рис. 2.5 - Діаграма прецедентів функціоналу голосування
30
ЧДТУ 231924.010 ПЗ
Рис. 2.6 - Діаграма прецедентів функціоналу розкладу
Рис. 2.7 - Діаграма прецедентів функціоналу вибіркових дисциплін
31
ЧДТУ 231924.010 ПЗ
Рис. 2.8 - Діаграма прецедентів функціоналу заяв
Рис. 2.9 - Діаграма прецедентів функціоналу перегляду інформації про студента
2.3 Проектування логічної структури програмного комплексу
2.3.1 Діаграми класів
Рис. 2.10 - Діаграма класів модуля логіну
32
ЧДТУ 231924.010 ПЗ
Рис. 2.11 - Діаграма класів модуля студента
Рис. 2.12 - Діаграма класів модуля вибіркових дисциплін
33
ЧДТУ 231924.010 ПЗ
Рис. 2.13 - Діаграма класів модуля опитувань/голосувань
34
ЧДТУ 231924.010 ПЗ
Рис. 2.14 - Діаграма класів модуля розкладу
35
ЧДТУ 231924.010 ПЗ
Рис. 2.15 - Діаграма класів модуля заяв
2.3.2 Діаграми пакетів
Рис. 2.16 - Діаграма пакетів
36
ЧДТУ 231924.010 ПЗ
2.4 Архітектурне проектування
2.4.1 Діаграма компонентів
Рис. 2.17 - Діаграма компонентів
2.4.2 Розгортання програмної системи на апаратних засобах. Діаграма
розгортання
Рис. 2.18 - Діаграма розгортання
37
ЧДТУ 231924.010 ПЗ
2.5 Моделювання поведінки системи
2.5.1 Діаграма діяльності
Рис. 2.19 - Діаграма діяльності для функціоналу отримання списку вибіркових
дисциплін
Рис. 2.20 - Діаграма діяльності для функціоналу розкладу
38
ЧДТУ 231924.010 ПЗ
Рис. 2.21 - Діаграма діяльності для функціоналу генерації заяв
Рис. 2.22 - Діаграма діяльності для функціоналу голосувань
39
ЧДТУ 231924.010 ПЗ
Рис. 2.23 - Діаграма діяльності для функціоналу отримання інформації про
студента
Рис. 2.24 - Діаграма діяльності для функціоналу аутентифікації
40
ЧДТУ 231924.010 ПЗ
2.5.2 Діаграма послідовності
Рис. 2.25 - Діаграма послідовності функціоналу запису на вибіркові дисципліни
Рис. 2.26 - Діаграма послідовності функціоналу отримання вибіркових
дисциплін перед першим туром
Рис. 2.27 - Діаграма послідовності функціоналу отримання вибіркових
дисциплін після другого туру або між першим та другим туром
41
ЧДТУ 231924.010 ПЗ
Рис. 2.28 - Діаграма послідовності для функціоналу отримання вибіркових
дисциплін в першому турі
Рис. 2.29 - Діаграма послідовності для функціоналу отримання вибіркових
дисциплін в другому турі
42
ЧДТУ 231924.010 ПЗ
Рис. 2.30 - Діаграма послідовності для функціоналу отримання списку заяв
Рис. 2.31 - Діаграма послідовності для функціоналу логіну
43
ЧДТУ 231924.010 ПЗ
Рис. 2.32 - Діаграма послідовності для функціоналу опитувань
Рис. 2.33 - Діаграма послідовності для функціоналу розкладу
Рис. 2.34 - Діаграма послідовності для функціоналу інформації про студента
44
ЧДТУ 231924.010 ПЗ
2.5.3 Діаграма комунікації
Рис. 2.35 - Діаграма комунікації системи
2.5.4 Діаграма скінченного автомату
Рис. 2.36 - Діаграма скінченного автомату функціоналу вибіркових дисциплін
45
ЧДТУ 231924.010 ПЗ
РОЗДІЛ 3
РОЗРОБКА ТА ТЕСТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ
3.1 Розробка програмного комплексу
Крім роботи над серверною частиною для мобільного, велась робота над
серверною частиною системи деканату, а саме - модулем запису на вибіркові
дисципліни. Тому в розділах нижче (розробка бази даних) будуть згадуватись
елементи з системи деканату.
3.1.1 Обґрунтування вибору засобів реалізації
Мова програмування
Мовою програмування для виконання поставленої задачі було обрано
Java. Вона є дуже популярною в сфері розробки веб-серверів (і не тільки), має
велике ком’юніті, а отже високий шанс знайти рішення багатьох проблем. До
речі, широка спільнота прихильників також є причиною появи величезної
кількості фреймворків (одним з таких є Spring Framework, за допомогою якого
розроблявся даний проект), бібліотек та технологій для розробки в різних
напрямках.
Крім того, Java – крос-платформна мова, що означає її незалежність
відносно операційної системи, на якій вона запускається (весь код виконується
віртуальною машиною). Це дає можливість виконувати зібрану програму на
різних пристроях.
Дана мова є відносно легкою для освоєння новачками, але підходить і для
розробки складних програмних комплексів. Підтримка ООП також є однією з
причин використання цієї мови.
Фреймворк
Spring Framework – це один з найбільш популярних фреймворків для
серверної розробки на мові Java. Він складається з кількох модулів, кожен з
яких надає обширний набір інструментів, які покривають усі аспекти розробки,
поставлені перед даним проектом.
Spring Data Access – містить функціонал для роботи з базою даних,
займається автоматичним управлінням транзакцій.
46
ЧДТУ 231924.010 ПЗ
Spring Security – модуль, який надає функціонал аутентифікації,
авторизації та захист від поширених атак. З його допомогою було досить просто
реалізувати логін в наш додаток з використанням технології JWT.
Spring MVC [17] дозволяє розробляти веб-програми використовуючи
MVC [19] шаблон, а також керує логікою, пов’язаною з веб – прийом HTTP [20]
запитів, знаходження необхідного контролера тощо.
Spring Test [17] дає можливість швидко писати, як юніт, так й інтеграційні
тести, запускати їх, переглядати статистику щодо покриття коду тестами;
містить бібліотеки для створення моків [21], assert команд [22]; дозволяє
частково або повністю запускати проект для тестування, в залежності від того,
що ви тестуєте.
У даного фреймворка детальна документація, велика кількість різних
навчальний відео, форумів, де можна знайти відповіді на більшість питань,
освоїти необхідний матеріал, що спрощує його вивчення.
СУБД
Під час розробки було використано PostgreSQL – це СУБД з відкритим
вихідним кодом, яка має всі необхідні механізми для забезпечення надійного
сховища даних:
– підтримує SQL стандарти та є сумісною з багатьма системами;
– має великий набір типів даних;
– підтримує транзакції, що дозволяє впевнитись в коректності
збережуваних даних;
– відкрита система спричинила популярність, а отже і розвиток системи
співтовариством розробників;
– зручна документація містить усе необхідне для швидкого старту у
використанні.
ORM
Hibernate [18] – це фреймворк для об’єктно-реляційного відображення,
який дозволяє взаємодіяти з базою даних дуже просто, використовуючи Java
об’єкти, як сутності бази даних (entity).
47
ЧДТУ 231924.010 ПЗ
Він зводить до мінімуму кількість SQL-коду, який треба написати, так як
більшість стандартних операцій уже реалізовані. Всі маніпуляції з базою даних
відбуваються за допомогою об’єктно-орієнтованого підходу.
Фреймворк забезпечує захист від SQL-інʼєкцій, а його дизайн дозволяє
переносити код взаємодії з базою даних між різними СУБД без зміни логіки.
Система контролю версій
Git [23] - це популярна система контролю версій, яка має безліч переваг:
– дозволяє зберігати копії проекту на кількох робочих машинах;
– Git достатньо швидкий, навіть при роботі з великими проектами та
файлами;
– Git дозволяє створювати різні гілки, щоб працювати над різними
частинами проекту паралельно;
– Git зберігає історію змін для кожного файлу, що дозволяє переглядати,
хто, коли та які зміни вносив;
– Git підтримує різні операційні системи та інтегрується з іншими
інструментами для розробки програмного забезпечення;
– Git дозволяє синхронізувати локальні зміни з віддаленим репозиторієм,
що робить можливим спільну розробку.
Платформа для розміщення коду
Github [24] - це сервіс для хостингу репозиторіїв Git та керування ними,
який має безліч переваг:
– дозволяє вести спільну розробку та зливати код з різних гілок в головну
за допомогою такого поняття, як pull request - запит на злиття гілки;
– стандартний функціонал дозволяє створювати дошки з завданнями,
призначати їм статуси, додавати описи, призначати спринти і все це
безкоштовно;
– інтегрується з середовищем розробки Intellij IDEA [25], що дає
можливість конфігурувати та керувати репозиторієм в редакторі;
48
ЧДТУ 231924.010 ПЗ
– має дуже зручний інтерфейс для перевірки змін в коді при проведенні
pull request, підсвічуючи змінені, видалені, додані ділянки коду, файли;
дозволяє залишати коментарі, зауваження щодо змін;
– Github дозволяє відстежувати внесок кожного розробника у проект, що
дозволяє керувати правами доступу до проекту та розподіляти
відповідальність між розробниками.
Середовище розробки
Для розробки проекту було використано інтегроване середовище
розробки Intellij IDEA. Воно являє собою потужний редактор коду з великим
вмістом засобів для розробки на мові Java. Швидкий процес розробки
забезпечується автодоповненням, механізмами рефакторингу, інспекцією та
аналізом коду, автоматичною генерацією деяких кодових структур (if, for або
try-catch блоки) та багато іншого.
Середовище підтримує розробку веб-додатків за допомогою різних
фреймворків, в тому числі Spring. Розширення інтерфейсу надають повний
контроль над додатком, огляд структури проекту, швидкий перехід між
компонентами систем, автоматичний запуск та збирання проекту, запуск тестів
тощо.
Плагіни баз даних (в моєму випадку PostgreSQL) дають можливість
виконувати запити до неї, керувати структурою таблиць, модифікувати дані,
додавати нові колонки, не покидаючи редактор.
Intellij IDEA підтримує інтеграцію з системами контролю версій, що
робить процес використання Git набагато зручнішим та швидшим, а можливість
підʼєднатись до власного GitHub репозиторію дозволяє зберігати зміни,
відслідковувати історію комітів, перемикатись між гілками, переглядати чужі
зміни, тобто виконувати всі необхідні операції для забезпечення спільної
розробки.
Система збирання
Збирання проекту відбувається за допомогою інструменту під назвою
Gradle [26]. Він запускається на JVM, що робить його зручним для тих, хто
49
ЧДТУ 231924.010 ПЗ
розробляє на Java, адже логіка збирання може використовувати стандартні Java
APIs. JVM дозволяє запускати Gradle на різних платформах. Крім того, дана
система збирання дозволяє додавати власну логіку збирання, задачі та плагіни
зручним та зрозумілим синтаксисом.
Ще одним плюсом є те, що IntelliJ IDEA підтримує плагін для Gradle,
дозволяючи запускати різні етапи збирання через зручний графічний інтерфейс,
відслідковувати статус збирання.
Аргументом в сторону Gradle також є швидкість, з якою збирається
проект. Він використовує кеші для повторного використання результату
попереднього збирання, а також уникає виконання непотрібних задач.
3.1.2 Опис структурної (функціональної) схеми
Рис. 3.1 - Функціональна схема системи
50
ЧДТУ 231924.010 ПЗ
Рис. 3.2 - Структурна схема системи
Кожна підсистема описує свій набір REST [27] контролерів, які засобами
Spring Framework викликаються, коли сервер отримує запит на відповідний
URL. Контролеру передається інформація про запит, його заголовки, параметри
URL, тіло запиту тощо. Контролер повертає відповідь з необхідним кодом та
результатом запиту на мобільний, або ж помилку, якщо така сталася під час
виконання.
Підсистема генерації заяв займається побудовою шаблону заяви на
основі даних, отриманих з мобільного, які ввів студент, а також інформації про
цього студента в системі деканату.
Підсистема розкладу по заданих параметрах знаходить розклад на
сервері розкладу ЧДТУ (у вигляді HTML), розбирає отриманий HTML на
необхідні частини та відправляє на мобільний. Дані про вибіркові дисципліни,
групу студента дана підсистема отримує з системи деканату.
Підсистема інформації про студента на основі ідентифікатора студента
знаходить необхідні дані про нього в системі деканату та відправляє на
мобільний. Крім того, підсистема містить допоміжний функціонал для інших
модулів.
Підсистема вибіркових дисциплін знаходить інформацію про процес
запису на дисципліни, списки цих дисциплін, та відправляє їх на мобільний.
Також дана підсистема займається збереженням, обраних студентом, вибіркових
дисциплін в системі деканату.
Підсистема голосувань (опитувань) надає інформацію про усі активні
голосування, валідує отримані голоси студентів, вносить ці голоси в базу даних.
51
ЧДТУ 231924.010 ПЗ
3.1.3 Опис логічної схеми системи
Логічно система побудована на основі архітектурного шаблона MVC
(Model-View-Controller). В його основу покладено ідею розділення
бізнес-логіки, даних та їх відображення. Схему зображено на рисунку 3.3.
Model відповідає за структуру даних, їх оновлення та доступ до них.
View визначає вигляд даних, їх відображення.
Controller керує процесом оновлення даних у відповідь на дії
користувача.
Кодова база проекту будується за схожим принципом. В ролі контролерів
виступають класи, позначені анотацією @Controller. Вони отримують дані від
користувача на відповдіний URL та передають їх в класи моделей.
Роль моделей виконують кілька класів:
– класи з анотаціями @Entity - сутності, які відображають таблиці бази
даних;
– класи, позначені анотацією @Repository - безпосередньо взаємодіють з
базою даних, виконують такі операції як INSERT, UPDATE, SELECT,
DELETE, тобто модифікують дані.
У випадку з серверною частиною, яка надає REST API, відображенням
виступають дані у вигляді JSON, отримані з моделей.
Рис. 3.3 - Логічна схема системи на основі MVC
Між контролером та моделлю існують звʼязуючі класи, позначені
анотацією @Service [3]. Вони отримують дані з контролера, оновлюють моделі,
52
ЧДТУ 231924.010 ПЗ
або ж отримують з них необхідну інформацію, та повертають у вигляді DTO
(Data Transfer Object) [28] користувачеві. DTO за своєю суттю - це звичайні Java
обʼєкти, які не містять бізнес-логіки і слугують лише для передачі даних між
користувачем (мобільний додаток) та сервером. Сервер серіалізує дані, отримані
в форматі JSON в DTO. Контролер передає DTO в сервіс, де він буде
перетворений в Entity та переданий в репозиторій. Останній зберігає дані в базу
даних.
Якщо ж виконується операція читання, то контролер викликає метод
сервіса, сервіс звертається до репозиторія, який витягує дані з таблиці та
повертає їх у вигляді Entity; сервіс перетворює Entity в DTO та повертає
користувачеві (сервер десеріалізує DTO в JSON).
Рис. 3.4 - Потік даних в системі (MVC шаблон)
3.1.4 Розробка бази даних
Концептуальні моделі даних
Рис. 3.5 - Концептуальна модель бази даних системи деканату для модуля
вибіркових дисциплін
53
ЧДТУ 231924.010 ПЗ
Рис. 3.6 - Концептуальна модель мобільної бази даних
Логічні моделі даних
Таблиця SELECTIVE_COURSE (Вибіркова дисципліна):
– id заповнюється автоматично; тип даних – SERIAL;
– поле teacher_id зв’язане зовнішнім ключем з полем id в таблиці teacher
(Викладач) і посилається на викладача, який веде вибіркову
дисципліну; тип даних – INTEGER;
– поле department_id зв’язане зовнішнім ключем з полем id в таблиці
department (Кафедра) і посилається на кафедру, до якої відноситься
вибіркова дисципліна; тип даних – INTEGER; обмеження - NOT NULL;
– поле degree_id зв’язане зовнішнім ключем з полем id в таблиці degree
(Ступінь) і посилається на ступінь студентів, для яких передбачена
вибіркова дисципліна; тип даних – INTEGER; обмеження - NOT NULL;
– поле field_of_knowledge_id зв’язане зовнішнім ключем з полем id в
таблиці field_of_knowledge (Галузь знань) і посилається на галузь
знань, до якої відноситься дана вибіркова дисципліна; тип даних –
INTEGER;
– поле course_id зв’язане зовнішнім ключем з полем id в таблиці course
(Дисципліна) і посилається на дисципліну, яка є вибірковою; тип даних
– INTEGER; обмеження - NOT NULL;
54
ЧДТУ 231924.010 ПЗ
– поле study_year визначає навчальний рік, в якому викладається
вибіркова дисципліна; тип даних – INTEGER; обмеження - NOT NULL;
– поле training_cycle описує цикл підготовки і обмежене до 15 символів;
тип даних – CHARACTER VARYING; обмеження - NOT NULL;
– поле other_fields_of_knowledge описує додаткові галузі знань, до яких
може відноситись вибіркова дисципліна і обмежене до 25 символів; тип
даних – CHARACTER VARYING;
– поле description містить опис вибіркової дисципліни і обмежене до 1024
символів; тип даних – CHARACTER VARYING; обмеження - NOT
NULL;
– поле available являє собою прапорець, який описує статус вибіркової
дисципліни – активна чи ні; тип даних – BOOLEAN; обмеження - NOT
NULL;
– поле group_name використовується для додавання назви групи
вибіркової дисципліни і обмежене до 20 символів; тип даних –
CHARACTER VARYING;
– обмеження таблиці - UNIQUE (course_id, study_year, degree_id,
field_of_knowledge_id )
Таблиця SELECTIVE_COURSES_STUDENT_DEGREES (Запис
студента на вибіркову дисципліну):
– id заповнюється автоматично; тип даних – SERIAL;
– поле selective_course_id зв’язане зовнішнім ключем з полем id в таблиці
selective_course (Вибіркова дисципліна) і посилається на вибіркову
дисципліну, на яку записана спеціальність студента; тип даних –
INTEGER; обмеження - NOT NULL;
– поле student_degree_id зв’язане зовнішнім ключем з полем id в таблиці
student_degree (Спеціальність студента) і посилається на спеціальність
студента, яка записана на дану вибіркову дисципліну; тип даних –
INTEGER; обмеження - NOT NULL;
55
ЧДТУ 231924.010 ПЗ
– поле active являє собою прапорець, який описує статус запису на
вибіркову дисципліну – активний чи ні; тип даних – BOOLEAN;
обмеження - NOT NULL;
– поле created_at містить дату створення запису студента на вибіркову
дисципліну; тип даних – DATETIME; обмеження - NOT NULL;
– обмеження таблиці - UNIQUE (student_degree_id, selective_course_id)
Таблиця SELECTIVE_COURSES_YEAR_PARAMETERS (Параметри
запису на вибіркові дисципліни):
– id заповнюється автоматично; тип даних – SERIAL;
– поле first_round_start_date являє собою дату початку першого туру; тип
даних - DATETIME; обмеження - NOT NULL, UNIQUE;
– поле first_round_end_date являє собою дату завершення першого туру;
тип даних - DATETIME; обмеження - NOT NULL, UNIQUE;
– поле second_round_start_date являє собою дату початку другого туру;
тип даних - DATETIME; обмеження - NOT NULL, UNIQUE;
– поле second_round_end_date являє собою дату завершення другого туру;
тип даних - DATETIME; обмеження - NOT NULL, UNIQUE;
– поле study_year визначає навчальний рік, в якому застосовуються
параметри вибору дисциплін; тип даних – INTEGER; обмеження - NOT
NULL;
– поле bachelor_general_min_students_count визначає мінімальну кількість
бакалаврів, які повинні записатись на вибіркову дисципліну загального
циклу; тип даних – INTEGER; обмеження - NOT NULL;
– поле bachelor_professional_min_students_count визначає мінімальну
кількість бакалаврів, які повинні записатись на вибіркову дисципліну
професійного циклу; тип даних – INTEGER; обмеження - NOT NULL;
– поле master_general_min_students_count визначає мінімальну кількість
магістрів, які повинні записатись на вибіркову дисципліну загального
циклу; тип даних – INTEGER; обмеження - NOT NULL;
56
ЧДТУ 231924.010 ПЗ
– поле master_professional_min_students_count визначає мінімальну
кількість магістрів, які повинні записатись на вибіркову дисципліну
професійного циклу; тип даних – INTEGER; обмеження - NOT NULL;
– поле phd_general_min_students_count визначає мінімальну кількість
докторів філософії, які повинні записатись на вибіркову дисципліну
загального циклу; тип даних – INTEGER; обмеження - NOT NULL;
– поле phd_professional_min_students_count визначає мінімальну кількість
докторів філософії, які повинні записатись на вибіркову дисципліну
професійного циклу; тип даних – INTEGER; обмеження - NOT NULL;
– поле max_students_count визначає максимальну кількість студентів, які
можуть записатись на одну дисципліну; тип даних – INTEGER;
обмеження - NOT NULL;
– поле period_case визначає визначає тип запису (звичайний чи пізній);
тип даних – CHARACTER VARYING; обмеження - NOT NULL;
Таблиця APPLICATION_USER (Користувач додатку):
– id посилається на student_id з бази даних системи деканату; тип даних –
INTEGER; обмеження - NOT NULL, UNIQUE;
– поле username зберігає логін користувача; тип даних – CHARACTER
VARYING; обмеження - NOT NULL, UNIQUE;
– поле password зберігає пароль користувача; тип даних – CHARACTER
VARYING; обмеження - NOT NULL;
Таблиця CURRENT_YEAR (Навчальний рік):
– id заповнюється автоматично; тип даних – SERIAL;
– поле curr_year містить поточний навчальний рік; тип даних – INTEGER,
обмеження - NOT NULL;
Таблиця POLL (Голосування):
– id заповнюється автоматично; тип даних – SERIAL;
– поле title описує назву голосування і обмежене до 150 символів; тип
даних - CHARACTER VARYING; обмеження - NOT NULL;
57
ЧДТУ 231924.010 ПЗ
– поле start_date являє собою дату початку голосування; тип даних -
DATE; обмеження - NOT NULL;
– поле end_date являє собою дату завершення голосування; тип даних -
DATE; обмеження - NOT NULL;
– поле max_choices_number_by_faculty розрахований на json рядок
(максимальна довжина - 150 символів) формату {id: value, id_1:
value_1,.. }, де id - ідентифікатор факультету з бази даних деканату,
value - необхідна кількість обраних варіантів голосування від одного
студента даного факультету; тип даних - CHARACTER VARYING;
– поле active являє собою прапорець, який описує статус голосування –
активне чи ні; тип даних – BOOLEAN; обмеження - NOT NULL;
– обмеження таблиці - UNIQUE (title, start_date, end_date)
Таблиця POLL_OPTION (Варіант голосування):
– id заповнюється автоматично; тип даних – SERIAL;
– поле title містить назву варіанту голосування і обмежене до 150
символів; тип даних - CHARACTER VARYING; обмеження - NOT
NULL;
– поле votes_count містить кількість голосів, відданих за даний варіант;
тип даних - INTEGER; обмеження - NOT NULL;
– поле poll_id зв’язане зовнішнім ключем з полем id в таблиці poll
(Голосування) і посилається на голосування, до якого цей варіант
відноситься; тип даних – INTEGER; обмеження - NOT NULL;
– поле faculty_id являє собою ідентифікатор факультету з системи
деканату, для студентів якого доступний даний варіант голосування;
може набувати значення NULL, якщо варіант доступний для всіх
студентів незалежно від факультету; тип даних - INTEGER;
– обмеження таблиці - UNIQUE (title, poll_id)
Таблиця STUDENT_DEGREE_VOTE (Голос студента):
– id заповнюється автоматично; тип даних – SERIAL;
58
ЧДТУ 231924.010 ПЗ
– поле student_degree_id містить ідентифікатор спеціальності студента з
системи деканату; тип даних - INTEGER; обмеження - NOT NULL;
– поле poll_id зв’язане зовнішнім ключем з полем id в таблиці poll
(Голосування) і посилається на голосування, до якого цей голос
студента відноситься; тип даних – INTEGER; обмеження - NOT NULL;
– обмеження таблиці - UNIQUE (student_degree_id, poll_id)
Фізичні моделі даних
Рис. 3.7 - Фізична модель частини бази даних системи деканату
59
ЧДТУ 231924.010 ПЗ
Рис. 3.8 - Фізична модель бази даних мобільного застосунку
3.1.5 Розробка інтерфейсу користувача
Розробка серверної частини не передбачає графічного інтерфейсу.
Результатом роботи є REST API, яким може користуватись будь-який клієнт,
здатний відправляти HTTP запити (в нашому випадку - мобільний додаток).
Опис розробленого API, параметрів та їх призначень описано в додатку В.
3.1.6 Опис розробки програмних компонентів
Вхідною точкою в модуль вибіркових дисциплін є клас
SelectiveCourseController (Рис. 3.9), який отримує HTTP запити на відповідний
URL за допомогою анотацій @GetMapping або @PostMapping.
Рис. 3.9 - Клас SelectiveCourseController
60
ЧДТУ 231924.010 ПЗ
Далі цей клас делегує роботу класу SelectiveCourseService, який виконує
бізнес-логіку, повʼязану з вибірковими дисциплінами. Основним тут є метод
getSelectiveCourses (Рис. 3.9), який в залежності від періоду запису відправляє
необхідні дані у відповідь. Тут іде взаємодія з класом StudentService (описаний
нижче), де отримується необхідна інформація про спеціальність студента.
Метод getSelectiveCourseForEnrollment звертається до системи деканату
для отримання вибіркових дисциплін. Метод
getSelectiveCoursesSelectionTimeParams звертається до системи деканату для
отримання параметрів вибору дисциплін. Метод getStudentSelectiveCourses
звертається до системи деканату для отримання вибіркових дисциплін, на які
записався студент на наступний навчальний рік. Метод
getSelectiveCoursesSelectionRules звертається до системи деканату для
отримання правил вибору дисциплін.
Рис. 3.10 - Метод getSelectiveCourses класу SelectiveCourseService
61
ЧДТУ 231924.010 ПЗ
Рис. 3.11 - Метод recordOnSelectiveCourses класу SelectiveCourseService
Метод recordOnSelectiveCourses (Рис. 3.11) відправляє дисципліни для
запису в систему деканату, де вони зберігаються в базу даних. Конструкція catch
[2] перехоплює помилки, які виникають під час запиту (некоректні
ідентифікатори, невідповідність правилам вибору тощо).
Модуль інформації про студента описує клас StudentController (Рис.
3.12), що повертає дані про студента, який увійшов в систему. Цю роботу він
делегує класу StudentService. За отримання даних відповідає метод getStudent
(Рис. 3.13). Він перевіряє, чи має студент активні спеціальності і, якщо це так,
то відправляє інформацію лише про них. Якщо ж активні спеціальності
відсутні, то йде пошук цих спеціальностей в таблиці академічних відпусток, і,
якщо такі знайдені, відправляється інформація про них.
Рис. 3.12 - Клас StudentController
62
ЧДТУ 231924.010 ПЗ
Рис. 3.13 - Метод getStudent класу StudentService
StudentService містить набір методів (Рис. 3.14), яким користуються різні
компоненти системи. Метод getStudentSemester повертає обʼєкт з поточним і
наступним семестром студента. Метод getCurrentStudentSemester повертає
поточний семестр студента. Метод getStudentDegreeYear обраховує курс
студента. Прапорець realYear сигналізує, який сам курс необхідно обрахувати -
реальний чи фактичний. Метод getStudentDegreesInAcademicVacation
звертається до системи деканату, де знаходить усі спеціальності студента, які
перебувають в академічній відпустці. Метод getStudentDegree знаходить
інформацію про спеціальність студента в системі деканату по заданому
ідентифікатору.
Рис. 3.14 - Набір методів класу StudentService
63
ЧДТУ 231924.010 ПЗ
Клас PollController (Рис. 3.15) представляє вхідну точку модуля
опитувань. Тут описано API для отримання активних опитувань, опитування
по ідентифікатору, метод для збереження голосу в базу даних.
Рис. 3.15 - Клас PollController
Основна логіка зосереджена в класі PollService. Для взаємодії з базою
даних він використовує класи (Рис. 3.16): PollRepository - клас взаємодії з
таблицею опитувань, PollOptionRepository - клас взаємодії з таблицею варіантів
опитувань, StudentDegreeVoteRepository - клас взаємодії з таблицею голосів.
Крім того, функціонал опитувань вимагає інформацію про студента, тому даний
сервіс використовує клас StudentService. DateTimeService - це сервіс, який
слугує лише для того, щоб повертати поточний час системи. Такий підхід
необхідний для можливості покриття PollService та інших класів, які
використовують поточний час, модульними тестами.
64
ЧДТУ 231924.010 ПЗ
Рис. 3.16 - Набір методів класу PollController
Метод createStudentDegreeVotes (Рис. 3.17) займається валідацією та
збереження голосу студента в базу даних. Клас PollOptionsValidator допомагає
перевірити коректність отриманих даних і генерує помилку
OperationCanntoBePerformerException, якщо дані не є валідними. Метод
checkExistingStudentVotes перевіряє чи не прийняв студент участь в цьому
голосуванні раніше. Якщо так, то генерується помилка. Після успішного
збереження голосу, збільшується на 1 значення поля votesCount варіанту
голосування (обраного студентом), яке показує кількість голосів відданих за цей
варіант. Зміна зберігається в базу даних викликом метода
pollOptionsRepositoy.save, в який передається сутність варіанту голосування з
оновленим значенням.
65
ЧДТУ 231924.010 ПЗ
Рис. 3.17 - Метод createStudenDegreeVotes класу PollService
API розкладу описано в класі ScheduleController (Рис. 3.18). Даний клас
взаємодіє з StudentService класом для отримання назви групи студента, по якій
відбувається пошук, а також курс студента для того, щоб визначити, чи треба
виконувати фільтрацію (дана функція необхідна лише для студентів 2 курсу).
Метод getScheduleByUserGroups слугує для отримання розкладу за групою
студента, який увійшов у систему. Метод getScheduleByGroups дозволяє
отримувати розклад за вказаними групами. Сервер розкладу не підтримує таку
функцію, але було розроблено логіку, яка зʼєднує кілька розкладів в одни для
зручного відображення. Такий самий функціонал реалізований в методі
getScheduleByTeachers, але параметрами виступають ПІБ викладачів.
66
ЧДТУ 231924.010 ПЗ
Рис. 3.18 - Клас ScheduleController
Логіка пошуку виділена в окремий клас - ScheduleProvider (Рис. 3.19).
Параметром конструктора є ScheduleSearch enum (Рис. 3.20), який визначає
параметр, по якому ведеться пошук: група чи викладач. В класі
ScheduleProvider є дві залежності: клас ScheduleHtmlProvider - звертається до
серверу розкладу для отримання HTML, який потім передається в наступну
залежність - клас ScheduleHtmlParser, який займається обробкою HTML,
розбиванням його на елементи, виділенням інформації про розклад за
допомогою регулярних виразів [29]. Клас ScheduleHtmlParser використовує клас
LessonDetailsParser для отримання деталей про предмет. В цьому класі є масив
регулярних виразів (Рис. 3.21), які намагаються виділити деталі предмета і
повертають їх у вигляді класу Lesson (Рис. 3.22).
67
ЧДТУ 231924.010 ПЗ
Рис. 3.19 - Клас ScheduleProvider
Рис. 3.20 - Елементи ScheduleSearch перечислення
Рис. 3.21 - Масив класів, які займаються виділенням деталей про предмет
Рис. 3.22 - Виділення деталей про предмет у класі LessonDeteailsParser
68
ЧДТУ 231924.010 ПЗ
3.2 Тестування системи
3.2.1 Модульне тестування
Для написання модульних тестів було використано засоби, які надає
Spring Testing Framework, такі як JUnit [30], Mockito, JUnit Assertions тощо.
JUnit являє собою платформу для написання та запуску тестів на JVM.
JUnit Assertions - це набір методів, які дозволяють задати умови
проходження тестів. Іншими словами, це набір критеріїв, заданих розробником,
які визначають успішність пройденого тесту. Нижче буде наведено приклади їх
використання.
Mockito дозволяє створювати моки, тобто імітувати роботу якогось
компонента системи без його реальної участі в тестах. Зазвичай такі
компоненти вимагають додаткової підтримки та ресурсів, наприклад БД, тому в
модульних тестах їх прийнято замінювати на мок-обʼєкти. Їх можна
конфігурувати, задавати поведінку та реакцію на взаємодію з ними тощо. Нижче
буде наведено приклади з їхнім використанням.
Модульні тести розроблялись за методологією AAА, яка умовно поділяє
тест на три структурні частини: Arrange - підготовка тестових даних; Act -
виконання бізнес-логіки системою, яка тестується; Assert - перевірка умов.
Рис. 3.23 - Уривок коду тестів з модуля опитувань
69
ЧДТУ 231924.010 ПЗ
Тести для модуля опитувань обʼєднані в класі PollServiceTests. Вкладений
(позначений анотацією @Nested) GetActivePolls клас являє собою контейнер
для тестів, які охоплюють логіку отримання списку активних опитувань.
Анотація @Test дає JUnit зрозуміти, що цей метод є тестом. Для зручності та
усунення дублювання коду, створення тестових даних винесено в окремі методи
(на рисунку вище - buildStudentDegreeWithFacultyId(2)). Метод when приймає на
вхід виклик методу (наприклад, на рисунку вище -
mockPollRepository.findAllByActiveTrue(), який звертається до бази даних), для
якого треба імітувати поведінку, а метод thenReturn вказує, який результат
повинен повернути переданий метод.
Після виконання бізнес-логіки (метод pollService.getActivePolls)
відбувається перевірка умов тесту за допомогою assertThat(...) метода. Обʼєкт,
який повертається містить такі методи як equals, hasSize, notNull та багато
інших, що дозволяє створювати читабельний та інтуїтивний код.
Створення мок обʼєктів відбувається в статичному методі, позначеному як
@BeforeAll. Методи mock, when, thenReturn є частиною бібліотеки Mockito, про
яку згадується на початку цього підрозділу.
Рис. 3.24 - Код ініціалізації моків в модулі опитувань
70
ЧДТУ 231924.010 ПЗ
Анотація @DisplayNameGeneration задає формат імен для тестів. На
рисунку нижче параметр DisplayNameGenerator.ReplaceUnderscores.class дає
вказівку замінити всі нижні підкреслення на пробіли.
Крім стандартних методів стверджень (assertThat, notNull, equals та ін.)
Spring Framework дозволяє створювати власні (Рис. 3.26). Для цього необхідно
унаслідуватись від AbstractAssert класу, додати власні методи перевірки, які
повертають this. Використання зображено на рисунку нижче.
Рис. 3.25 - Уривок коду з тестів модуля вибіркових дисциплін
Рис. 3.26 - Код реалізації власного assert методу
71
ЧДТУ 231924.010 ПЗ
3.2.2 Інтеграційне тестування
На даний момент в системі відсутні автоматичні інтеграційні тести.
Цілісність програми та правильність її роботи перевіряється ручним
тестуванням всієї системи (буде описано в наступному пункті).
Інтеграційне тестування передбачає перевірку роботи компонентів -
серверна програма та БД в нашому випадку. База даних - це позапроцесна
залежність [31], тобто усі тести мають доступ до її спільного екземпляра.
Потенційно, це призводить до того, що один тест може змінити дані, які
використовує інший тест, таким чином спричиняючи неочікувану поведінку
[31]. В модульних тестах цю проблему обходять використанням моків. Але в
інтеграційних тестах прийнято використовувати реальний екземпляр бази
даних. Для запобігання вище описаних проблем планується використати
технологію, яка дозволяє створювати окремий екземпляр бази даних для
кожного тестового класу. Таким чином буде досягнуто ізоляцію тестів один від
одного і унеможливить втручання одного тесту у виконання іншого.
Для запуску кількох екземплярів бази даних планується використати
технологію Docker [32]. Він надає можливість пакувати та запускати програму в
ізольованому середовищі, яке називається контейнером. Ізоляція та безпека
дозволяють запускати багато контейнерів одночасно на певному хості.
Контейнери легкі та містять усе необхідне для запуску програми, тому не
потрібно покладатися на те, що зараз встановлено на хості.
Бібліотека Testcontainers [33] дозволяє швидко та зручно запускати Docker
контейнери з базою даних для різних тестів, а після їхнього завершення -
зупинити контейнери та звільнити ресурси.
3.2.3 Системне тестування
Для проведення тестування системи вручну необхідно запустити сервер
мобільного додатку та серверну частину системи деканату, як описано в додатку
В. Для виконання HTTP запитів використовується програма Postman [34].
Тестування модуля логіну
1 Логін активного студента
72
ЧДТУ 231924.010 ПЗ
Передумови:
– створений користувач в таблиці application_user (БМ);
– в таблиці student_degree (БСД) повинен бути запис де поле active - true,
student_id - id в записі таблиці таблиці application_user (БМ);
Очікуваний результат: відповідь з JWT токеном доступу, призначена
роль - ROLE_STUDENT.
Виконання:
Рис. 3.27 - Відправка запиту в програмі Postman
Рис. 3.28 - ROLE_STUDENT в отриманому токені
2 Хибний логін або пароль
Передумови: ті самі, що й в попередньому тесті.
Очікуваний результат: HTTP статус код - 403 Forbidden
Виконання:
73
ЧДТУ 231924.010 ПЗ
Рис. 3.29 - Відправка запиту в програмі Postman
3 Логін студента в академічній відпустці
Передумови:
– створений користувач в таблиці application_user (БМ);
– в таблиці student_degree (БСД) для всіх записів, де student_id - id з
запису в таблиці application_user (БМ), поле active - false.
– в таблиці student_academic_vacation (БСД) створений запис, де поле
active - true, student_degree_id - значення id одного з записів, описаних в
попередній передумові цього тесту.
Очікуваний результат: відповідь з JWT токеном доступу, роль -
ROLE_STUDENT_IN_ACADEMIC_VACATION.
Виконання:
Рис. 3.30 - Відправка запиту в програмі Postman
74
ЧДТУ 231924.010 ПЗ
Рис. 3.31 - ROLE_STUDENT_IN_ACADEMIC_VACATION в отриманому токені
Тестування модуля студента
4 Інформація про студента
Передумови:
– студент увійшов в систему (Authorization заголовок містить Bearer
<token>, отриманий в попередніх тестах);
Очікуваний результат: відповідь з інформацією про студента.
Виконання:
Рис. 3.32 - Відправка запиту в програмі Postman
75
ЧДТУ 231924.010 ПЗ
Тестування модуля вибіркових дисциплін
5 Період перед першим туром запису
Передумови:
– студент увійшов в систему;
– активний запис в таблиці student_degree (БСД) посилається на запис в
таблиці student_group (БСД), де creation_year - 2021, active - true,
real_begin_year - 1, specialization_id - посилаєтсья на запис в таблиці
specialization (БСД), де degree_id - 1.
– в таблиці current_year поле curr_year - 2021 (для обох баз даних);
– в таблиці selective_courses (БСД) є записи, де study_year - 2022,
degree_id - 1, training_cycle - GENERAL, available - true, course_id -
посилається на записи в таблиці course (БСД), де semester - 3 або 4.
– в таблиці selective_courses_year_parameters (БСД) є запис, де study_year
- 2021; first_round_start_date - пізніше ніж поточна дата; поля
_min_students_count - 5, max_students_count - 10, period_case - EARLY;
Очікуваний результат: відповідь з порожніми списками дисциплін (поле
firstSemester та secondSemester), courseSelectionPeriod -
BEFORE_FIRST_ROUND, selectionRules - null.
Виконання:
Рис. 3.33 - Відправка запиту в програмі Postman
76
ЧДТУ 231924.010 ПЗ
6 Перший тур запису
Передумови: ті самі, що й в попередньому тесті, але в таблиці
selective_courses_year_parameters (БСД) необхідно змінити дати, щоб перший
тур припадав на поточний час.
Очікуваний результат: відповідь з списками дисциплін,
courseSelectionPeriod - FIRST_ROUND, selectioRules - містять правила вибору
для поточного студента (кількість доступних для вибору дисциплін в 1 та 2
семестрах з відповідним циклом підготовки).
Виконання:
Рис. 3.34 - Відправка запиту в програмі Postman
77
ЧДТУ 231924.010 ПЗ
7 Запис на дисципліни в першому турі
Передумови: ті самі, що й в попередньому тесті.
Очікуваний результат: створені записи в таблиці
selective_courses_student_degree (БСД).
Виконання:
Рис. 3.35 - Відправка запиту в програмі Postman
Рис. 3.36 - Створені записи в таблиці selective_courses_student_degree (БСД)
після першого туру
78
ЧДТУ 231924.010 ПЗ
8 Період між першим та другим туром
Передумови: ті самі, що й в попередньому тесті, але в таблиці
selective_courses_year_parameters (БСД) необхідно змінити дати, щоб період між
першим та другим туром припадав на поточний час.
Очікуваний результат: відповідь з дисциплін, на які записався студент
(поля firstSemester та secondSemester), courseSelectionPeriod -
BETEWEN_FIRST_AND_SECOND_ROUND, selectionRules - null
Виконання:
Рис. 3.37 - Відправка запиту в програмі Postman
9 Другий тур запису
Передумови: ті самі, що й в попередньому тесті, але в таблиці
selective_courses_year_parameters (БСД) необхідно змінити дати, щоб другий тур
79
ЧДТУ 231924.010 ПЗ
припадав на поточний час і в таблиці selective_courses_student_degree (БСД)
зробити для одного запису поле active - false (дискваліфікувати предмет).
Очікуваний результат: відповідь зі списками дисциплін (поля
firstSemester та secondSemester, де selectedInFirstRound позначає чи записався
студент на дисципліну в першому турі), courseSelectionPeriod -
SECOND_ROUND, selectioRules - містять правила вибору для поточного
студента, з урахуванням дисциплін, на які студент вже записався (тепер
дозаписатись можна лише на одну дисципліну загального циклу).
Виконання:
Рис. 3.38 - Відправка запиту в програмі Postman
80
ЧДТУ 231924.010 ПЗ
10 Дозапис на дисципліни в другому турі
Передумови: ті самі, що й в попередньому тесті.
Очікуваний результат: створені записи в таблиці
selective_courses_student_degree (БСД).
Виконання:
Рис. 3.39 - Відправка запиту в програмі Postman
Рис. 3.40 - Створені записи в таблиці selective_courses_student_degree (БСД)
після другого туру
81
ЧДТУ 231924.010 ПЗ
11 Другий тур запису
Передумови: ті самі, що й в попередньому тесті.
Очікуваний результат: відповідь з списками дисциплін, на які студент
записався в результаті двох турів (firstSemester та secondSemester поля),
courseSelectionPeriod - AFTER_SECOND_ROUND, selectioRules - null.
Виконання:
Рис. 3.41 - Відправка запиту в програмі Postman
Тестування модуля заяв (наведено один приклад, так як інші заяви
формуються ідентично)
12 Заява на зміну імені
Передумови: студент увійшов в систему.
82
ЧДТУ 231924.010 ПЗ
Очікуваний результат: відповідь з шаблоном заяви.
Виконання:
Рис. 3.42 - Відправка запиту в програмі Postman
3.2.4 Приймальне тестування
Під час розробки проводились збори з працівниками
навчально-методичного відділу, де обговорювалась логіка роботи додатку,
вимоги до існуючого та нового функціоналу, а також відбувалась демонстрація
та перевірка роботи системи.
Приймальне тестування проводиться безпосередньо знавцев предметної
області (керівником проекту) перед розгортанням нової версії серверного ПЗ.
Перевіряються всі модулі, щоб уникнути помилок, які могли зʼявитись в
результаті змін в кодовій базі. Процес схожий на перевірку, описану в пункті
про системне тестування, але в якості доступу до REST API використовується
не Postman, а мобільний додаток, який має доступ до даного API. Під час цієї
перевірки відтворюється реальний процес взаємодії студента через мобільний
додаток з серверною частиною використовуючи тестові дані.
Після фінальних перевірок відбувається процес розгортання програми на
сервері, який буде описано в наступному підрозділі.
3.2.5 Реалізація та впровадження результатів
Серверна частина мобільного додатку працює на сервері Linux у вигляді
сервіса [35]. Він працює у фоні без графічного інтерфейсу і слухає порт,
83
ЧДТУ 231924.010 ПЗ
встановлений в application.yaml (Рис. 3.44) файлі проекту. Linux сервер
надається хмарним сервісом для хостингу, який використовується
університетом.
Для створення сервіса на сервер поміщається файл (з розширенням
.service) з конфігурацією (Рис 3.43), де:
– Description - опис сервіса;
– After - вказує порядок запуску сервіса (в даному випадку, після сервіса
postgres);
– StartLimitBurst - встановлює максимальну кількість спроб запуску,
дозволену в межах зазначеного інтервалу;
– StartLimitInterval - визначає часовий інтервал, протягом якого сервіс
може спробувати запуститися певну кількість разів, перш ніж systemd
вважатиме її невдалою;
– Type - визначає тип процесу для сервіса («simple» вказує на те, що
сервіс є окремим автономним процесом, який запускається
безпосередньо systemd);
– Restart - визначає умови, за яких systemd має спробувати перезапустити
сервіс. «on-failure» вказує на те, що сервіс слід перезапустити лише в
разі його збою (вихід із ненульовим кодом статусу);
– User - визначає користувача, від імені якого має працювати сервіс;
– ExecStart - визначає команду або виконуваний файл (повний шлях),
який systemd має виконати для запуску сервіса;
– StandardOutput - визначає, куди слід реєструвати стандартний вивід;
– StandardError - вказує, куди слід реєструвати стандартний вивід
помилок;
– WantedBy - визначає ціль або рівень запуску, для якого має бути
ввімкнено сервіс (multi-user.target вказує на те, що сервіс слід
запускати, коли система досягне рівня запуску для кількох
користувачів).
84
ЧДТУ 231924.010 ПЗ
Рис. 3.43 - Файл конфігурації Linux сервіса
Команда java -jar запускає зібраний Spring проект, в якому вбудований
Tomcat сервлет контейнер [36], відповідальний за отримання запитів та їх
передачу нашій програмі в потрібне місце. Для збирання проекту
використовується Gradle задача під назвою bootJar [37] (кроки для
налаштування та запуску Gradle задач описані в додатку В). Цей процес
супроводжується пакуванням класів з кодом проекту і класами залежностей в
спеціальний архів. Після виконання bootJar, в папці build проекту буде створено
файл з розширенням .jar [38]. Цей файл необхідно помістити в папку на сервері
та вказати шлях до нього в полі ExecStart, зображеному на рисунку 3.43.
Для запуску сервісу в терміналі виконується команда systemctl start
<service_name> або systemctl enable <service_name>. Для того, щоб зупини
сервіс, необхідно виконати команду systemctl stop <service_name> або systemctl
disable <service_name>.
В команді ExecStart є рядок –spring.config.location, який вказує шлях до
файлу з конфігурацією (Рис. 3.44) для програми. В ньому містяться необхідні
дані конфігурацій, такі як URL, логін та пароль від бази даних, ssl ключі, порт,
на якому буде працювати програма, URL серверної частини системи деканату,
URL серверу розкладу, токен доступу до серверної частини системи деканату
тощо.
85
ЧДТУ 231924.010 ПЗ
Рис. 3.44 - Приклад application.yaml файлу
ВИСНОВОК
У ході виконання роботи над серверною частиною мобільного додатку
для студентів було проведено проектування системи та розроблено відповідне
ПЗ.
На першому етапі розробки було досліджено існуючі аналоги та набір
функціоналу, який вони надають. Після цього, було зібрано первинні вимоги,
проведено їхній аналіз і, на їхній основі, сформовано детальні вимоги для
проекту. В результаті цього етапу було поставлено завдання розробити модуль
вибіркових дисциплін, розкладу, інформації про студента, опитувань та логіну.
Другим етапом стало проектування архітектури системи. Тут було
описано спосіб взаємодії компонентів системи, алгоритми роботи модулів та
план розгортання ПЗ. Графічне зображення всіх необхідних схем було
побудоване завдяки мові UML.
Для розробки програми було обрано наступні інструменти: Java, Spring
Framework, Hibernate ORM, PostgreSQL СУБД, Gradle, Git та GitHub. Під час
цього етапу було реалізовано всі поставлені завдання та розроблено необхідні
модулі.
86
ЧДТУ 231924.010 ПЗ
На етапі тестування було перевірено роботу функціоналу та стабільність
серверної частини додатку. Виявлені помилки було усунено та проведено
повторне тестування. Завершенням цього етапу було підтвердження коректності
роботи системи знавцем предметної області (керівником проекту).
Підсумовуючи все вище описане можна стверджувати, що мета
кваліфікаційної роботи була досягнута. Результатом є готовий продукт, який був
розгорнутий на серверах університету (мобільна частина викладена в Play
Market) і зараз активно використовується студентами університету.
Актуальність та потрібність цього додатку засвідчує той факт, що процес запису
на вибіркові дисципліни відбувається виключно за допомогою нашого додатку,
що робить його ключовим елементом навчального процесу.
В майбутньому планується додати модульні тести для всієї кодової бази, а
також написати інтеграційні тести. В планах розширювати функціонал
додатку: отримання довідок, перегляд власних оцінок, перегляд
заборгованостей тощо.
87
ЧДТУ 231924.010 ПЗ
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ
1 Agile Scrum - [Електронний ресурс] - Режим доступу:
https://www.atlassian.com/agile/scrum
2 Herbert Schildt. Java. The complete reference; 11th edition (2019)
Language: English 1882 pages ISBN: 978-1-26-044024-9
3 Spring in Action. Craig S. Walls. Manning Publications; 5th edition
(2019) Language: English 521 pages ISBN: 978-1-61729-494-5
4 PostgreSQL - [Електронний ресурс] - Режим доступу:
https://www.postgresql.org/about/
5 Top 10 Mistakes Backend Developers Make - [Електронний ресурс] -
Режим доступу:
https://wiredelta.com/10-common-mistakes-backend-developers-make/
6 KISS, DRY, S.O.L.I.D, YAGNI - [Електронний ресурс] - Режим
доступу:
https://senior.ua/articles/kiss-dry-solid-yagni--navscho-dotrimuvatis-principv-progra
muvannya
7 Robert C. Martin. Clean Code. (2009) Language: English 462 pages
ISBN: 978-0-13-235088-4
8 SQL injection - [Електронний ресурс] - Режим доступу:
https://portswigger.net/web-security/sql-injection
9 The Most Popular Backend Frameworks - [Електронний ресурс] -
Режим доступу:
https://www.pangea.ai/web-development-resources/most-popular-backend-framewor
ks-for-teams/
10 Stack Overflow Developers Survey 2021 - [Електронний ресурс] -
Режим доступу: https://insights.stackoverflow.com/survey/2021
11 Comparing Database Management Systems: MySQL, PostgreSQL,
MSSQL Server, MongoDB, Elasticsearch, and others - [Електронний ресурс] -
Режим доступу:
88
ЧДТУ 231924.010 ПЗ
https://www.altexsoft.com/blog/business/comparing-database-management-systems-
mysql-postgresql-mssql-server-mongodb-elasticsearch-and-others/
12 У КНУ розробили мобільний додаток - [Електронний ресурс] -
Режим доступу:
https://mon.gov.ua/ua/news/u-knu-rozrobili-mobilnij-dodatok-tam-ye-elektronni-kabi
neti-studentiv-i-vikladachiv-biblioteka-ta-bagato-inshogo
13 Університет у смартфоні: презентували додаток "KNU online" -
[Електронний ресурс] - Режим доступу:
https://www.ukrinform.ua/rubric-technology/3060294-universitet-u-smartfoni-prezent
uvali-dodatok-knu-online.html
14 Мій НУВГП - [Електронний ресурс] - Режим доступу:
https://wiki.nuwm.edu.ua/index.php/Освітній_органайзер_Мій_НУВГП_Мобільні
й_додаток_Android
15 Мій НУВГП в Play Market - [Електронний ресурс] - Режим доступу:
https://play.google.com/store/apps/details?id=com.m_myr.nuwm.nuwmschedule&hl=
uk&gl=US
16 JWT - [Електронний ресурс] - Режим доступу:
https://jwt.io/introduction
17 Spring Framework Features - [Електронний ресурс] - Режим доступу:
https://www.bmc.com/blogs/spring-framework/
18 Hibernate - [Електронний ресурс] - Режим доступу:
https://hibernate.org/orm/
19 MVC - [Електронний ресурс] - Режим доступу:
https://developer.mozilla.org/en-US/docs/Glossary/MVC
20 HTTP Protocol - [Електронний ресурс] - Режим доступу:
https://www.freecodecamp.org/news/what-is-http/
21 Mockito - [Електронний ресурс] - Режим доступу:
https://site.mockito.org/
22 JUnit Assertiosn - [Електронний ресурс] - Режим доступу:
https://www.baeldung.com/junit-assertions
89
ЧДТУ 231924.010 ПЗ
23 Introduction to Git features - [Електронний ресурс] - Режим доступу:
https://blog.knoldus.com/introduction-to-git-features-and-commands/
24 GitHub Features - [Електронний ресурс] - Режим доступу:
https://github.com/features
25 IntelliJ IDEA Features - [Електронний ресурс] - Режим доступу:
https://www.jetbrains.com/idea/features/#features
26 Gradle - [Електронний ресурс] - Режим доступу:
https://www.postman.com/product/tools/
27 What is REST API? - [Електронний ресурс] - Режим доступу:
https://restfulapi.net/
28 DTO - [Електронний ресурс] - Режим доступу:
https://snyk.io/blog/how-to-use-java-dtos/
29 Regular Expressions (Class Pattern) - [Електронний ресурс] - Режим
доступу: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
30 JUnit 5 User Guide - [Електронний ресурс] - Режим доступу:
https://junit.org/junit5/docs/current/user-guide
31 Vladimir Khorikov. Unit-testing. (2020) Language: English 320 pages
ISBN: 9781617296277.
32 Docker Overview - [Електронний ресурс] - Режим доступу:
https://docs.docker.com/get-started/overview/
33 Testcontainers for Java - [Електронний ресурс] - Режим доступу:
https://www.testcontainers.org/
34 Postman - [Електронний ресурс] - Режим доступу:
https://www.postman.com/product/tools/
35 Service in Linux - [Електронний ресурс] - Режим доступу:
https://www.imaginelinux.com/service-in-linux/
36 Tomcat Servlet Container - [Електронний ресурс] - Режим доступу:
https://www.infoworld.com/article/3510460/what-is-apache-tomcat-the-original-java-
servlet-container.html
90
ЧДТУ 231924.010 ПЗ
37 Gradle. Java Plugin - [Електронний ресурс] - Режим доступу:
https://docs.gradle.org/current/userguide/java_plugin.html
38 JAR file - [Електронний ресурс] - Режим доступу:
https://en.wikipedia.org/wiki/JAR_(file_format)
39 Методичні рекомендації до підготовки кваліфікаційної роботи
бакалавра для здобувачів вищої освіти зі спеціальності 121 «Інженерія
програмного забезпечення» усіх форм навчання [Текст] /Укл.: Голуб С.В., Заспа
Г.О., Півень О.Б., Катаєва Є.Ю., Салапатов В.І., Метелап В.В., Олексюк В.В.;
М-во освіти і науки України, Черкас, держ. технол. ун-т. - Черкаси : ЧДТУ, 2023.
- 97 с.
40 Student App on Play Market - [Електронний ресурс] - Режим доступу:
https://play.google.com/store/apps/details?id=ua.edu.chdtu.deanoffice.student_mobile
_cross&hl=en&gl=US
91
ДОДАТОК А
ЗАТВЕРДЖЕНО:
Зав. кафедри ПЗАС
проф. Голуб С. В.
___________________________
СЕРВЕРНА ЧАСТИНА МОБІЛЬНОГО ЗАСТОСУНКУ «СТУДЕНТ ЧДТУ»
Специфікація
ЧДТУ.231924-010 ПЗ
Листів 2
Розробник ________________ Чоповенко В. М.
Керівник ________________ Заспа Г.О.
Н.Контроль ________________ Півень О.Б.
Черкаси 2023
92
Позначення Найменування Примітка
Документація
482.ЧДТУ.231924-010 12-01 Лістинг програми
482.ЧДТУ.231924-010 34-01 Інструкція користувача
482.ЧДТУ.231924-010 90-01 Графічні матеріали
93
ДОДАТОК Б
СЕРВЕРНА ЧАСТИНА МОБІЛЬНОГО ЗАСТОСУНКУ «СТУДЕНТ ЧДТУ»
Лістинг програми
482.ЧДТУ.231924-010 12-01
Листів 25
Розробник ________________ Чоповенко В. М.
Черкаси 2023
482.ЧДТУ.231924-010 12-01
Файл SelectiveCourseController
@RestController
@RequestMapping("/selective-courses")
public class SelectiveCourseController {
private SelectiveCourseService selectiveCourseService;
@Autowired
public SelectiveCourseController(SelectiveCourseService selectiveCourseService) {
this.selectiveCourseService = selectiveCourseService;
}
@GetMapping
public ResponseEntity<SelectiveCourses> getSelectiveCourses(@RequestParam int
studentDegreeId) throws NotFoundException {
return
ResponseEntity.ok(selectiveCourseService.getSelectiveCourses(studentDegreeId));
}
@PostMapping("/registration")
public ResponseEntity<StudentDegreeSelectiveCoursesIds>
getConfirmedSelectiveCourses(@RequestBody SelectiveCoursesStudentDegreeWrite
selectiveCoursesStudentDegreeWrite) {
return
selectiveCourseService.recordOnSelectiveCourses(selectiveCoursesStudentDegreeWrite);
}
}
Файл SelectiveCourseService
@Service
public class SelectiveCourseService {
private final RestTemplate restTemplate;
private final StudentService studentService;
private final CurrentYearService currentYearService;
private final DateTimeService dateTimeService;
public SelectiveCourseService(RestTemplateBuilder restTemplateBuilder,
StudentService studentService,
CurrentYearService currentYearService,
DateTimeService dateTimeService) {
this.restTemplate = restTemplateBuilder.build();
this.studentService = studentService;
this.currentYearService = currentYearService;
this.dateTimeService = dateTimeService;
}
public SelectiveCourses getSelectiveCourses(int studentDegreeId) throws
NotFoundException {
SelectiveCourses selectiveCourses = new SelectiveCourses();
StudentDegree studentDegree =
studentService.getStudentDegree(studentDegreeId);
SelectiveCoursesSelectionTimeParams selectionTimeParams =
getSelectiveCoursesSelectionTimeParams(studentDegree);
selectiveCourses.setSelectionTimeParams(selectionTimeParams);
CourseSelectionPeriod currentPeriod =
selectionTimeParams.getCourseSelectionPeriod();
if (currentPeriod.isBeforeFirstRoundOrNoSelectiveCourses())
return selectiveCourses;
95
482.ЧДТУ.231924-010 12-01
SelectiveCoursesBySemesters studentCoursesBySemesters =
getStudentSelectiveCourses(studentDegreeId, selectionTimeParams);
if (!currentPeriod.isBetweenOrAfterSecondRound()) {
SelectiveCoursesSelectionRules[] selectionRules =
getSelectiveCoursesSelectionRules(studentDegreeId);
if (currentPeriod == CourseSelectionPeriod.FIRST_ROUND &&
studentCoursesBySemesters.getCount() == 0) {
studentCoursesBySemesters =
getSelectiveCoursesForEnrollment(studentDegree);
selectiveCourses.setSelectionRules(selectionRules);
} else if (currentPeriod == CourseSelectionPeriod.SECOND_ROUND &&
!studentCoursesBySemesters.countEqualsTo(selectionRules)) {
selectiveCourses.setSelectionRules(studentCoursesBySemesters.calculateRules(selectionRules)
);
studentCoursesBySemesters.merge(getSelectiveCoursesForEnrollment(studentDegree).getAll());
}
}
selectiveCourses.setFirstSemester(studentCoursesBySemesters.getFirst());
selectiveCourses.setSecondSemester(studentCoursesBySemesters.getSecond());
return selectiveCourses;
}
private SelectiveCoursesSelectionTimeParams
getSelectiveCoursesSelectionTimeParams(StudentDegree studentDegree)
throws NotFoundException {
int studentYear =
studentService.getStudentDegreeYear(studentDegree.getStudentGroup(), true);
int studyYear = currentYearService.getYear();
int degreeId = studentDegree.getSpecialization().getDegree().getId();
SelectiveCoursesYearParameters selectiveCoursesYearParameters =
getSelectiveCoursesYearParameters(studentDegree.getId(), studyYear);
SelectionTimeParametersCreator selectionTimeParametersCreator =
new SelectionTimeParametersCreator(DegreeEnum.getById(degreeId),
selectiveCoursesYearParameters, studentYear);
return selectionTimeParametersCreator.getSelectionTimeParameters(studyYear,
dateTimeService.now());
}
private SelectiveCoursesBySemesters
getSelectiveCoursesForEnrollment(StudentDegree studentDegree) {
Semester semester =
studentService.getStudentSemester(studentDegree.getStudentGroup());
return new SelectiveCoursesBySemesters(
getSelectiveCoursesBySemester(semester.getNextFirst(),
studentDegree),
getSelectiveCoursesBySemester(semester.getNextSecond(),
studentDegree),
false
);
}
96
482.ЧДТУ.231924-010 12-01
private List<SelectiveCourse> getSelectiveCoursesBySemester(int semester,
StudentDegree studentDegree) {
String url = Constants.BASE_URL + "/selective-courses";
String completeUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("studyYear", currentYearService.getYear() + 1)
.queryParam("degreeId",
studentDegree.getSpecialization().getDegree().getId())
.queryParam("semester", semester)
.queryParam("studentDegreeId", studentDegree.getId())
.toUriString();
HttpEntity<SelectiveCourse> request = new
HttpEntity<>(HttpUtil.getHeaders());
ResponseEntity<SelectiveCourse[]> response =
this.restTemplate.exchange(completeUrl, HttpMethod.GET, request, SelectiveCourse[].class);
SelectiveCourse[] selectiveCourses = response.getBody();
return Arrays.asList(selectiveCourses);
}
private SelectiveCoursesYearParameters getSelectiveCoursesYearParameters(int
studentDegreeId, int studyYear) {
String url = Constants.BASE_URL + "/selective-courses-year-parameters";
String completeUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("year", studyYear)
.queryParam("studentDegreeId", studentDegreeId)
.toUriString();
HttpEntity<SelectiveCoursesYearParameters> request = new
HttpEntity<>(HttpUtil.getHeaders());
ResponseEntity<SelectiveCoursesYearParameters> response =
restTemplate.exchange(completeUrl, HttpMethod.GET, request,
SelectiveCoursesYearParameters.class);
return response.getBody();
}
private SelectiveCoursesSelectionRules[] getSelectiveCoursesSelectionRules(int
studentDegreeId) {
String url = Constants.BASE_URL +
"/selective-courses/selection-rules?studentDegreeId=" + studentDegreeId;
HttpEntity<SelectiveCoursesSelectionRules[]> request = new
HttpEntity<>(HttpUtil.getHeaders());
ResponseEntity<SelectiveCoursesSelectionRules[]> response =
restTemplate.exchange(url, HttpMethod.GET, request,
SelectiveCoursesSelectionRules[].class);
return response.getBody();
}
public ResponseEntity<StudentDegreeSelectiveCoursesIds>
recordOnSelectiveCourses(SelectiveCoursesStudentDegreeWrite
selectiveCoursesStudentDegreeWrite) {
try {
String url = Constants.BASE_URL + "/selective-courses/registration";
HttpEntity<SelectiveCoursesStudentDegreeWrite> request = new
HttpEntity<>(selectiveCoursesStudentDegreeWrite, HttpUtil.getHeaders());
ResponseEntity<StudentDegreeSelectiveCoursesIds> response =
restTemplate.postForEntity(url, request, StudentDegreeSelectiveCoursesIds.class);
return ResponseEntity.ok(response.getBody());
97
482.ЧДТУ.231924-010 12-01
} catch (HttpClientErrorException e) {
return new ResponseEntity(e.getLocalizedMessage(), e.getStatusCode());
}
}
public List<SelectiveCourse> getActiveSelectiveCoursesForCurrentYear(int
studentDegreeId) {
String url = Constants.BASE_URL + "/selective-courses/student-courses";
String completeUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("studyYear", currentYearService.getYear())
.queryParam("studentDegreeId", studentDegreeId)
.queryParam("all", false)
.toUriString();
HttpEntity<SelectiveCoursesStudentDegree> request = new
HttpEntity<>(HttpUtil.getHeaders());
ResponseEntity<SelectiveCoursesStudentDegree> response =
restTemplate.exchange(completeUrl, HttpMethod.GET, request,
SelectiveCoursesStudentDegree.class);
return response.getBody().getSelectiveCourses();
}
private SelectiveCoursesBySemesters getStudentSelectiveCourses(int
studentDegreeId, SelectiveCoursesSelectionTimeParams selectionTimeParams) {
String url = Constants.BASE_URL + "/selective-courses/student-courses";
String completeUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("studyYear", selectionTimeParams.getStudyYear())
.queryParam("studentDegreeId", studentDegreeId)
.queryParam("all", true)
.toUriString();
HttpEntity<SelectiveCoursesStudentDegree> request = new
HttpEntity<>(HttpUtil.getHeaders());
ResponseEntity<SelectiveCoursesStudentDegree> response =
restTemplate.exchange(completeUrl, HttpMethod.GET, request,
SelectiveCoursesStudentDegree.class);
return new
SelectiveCoursesBySemesters(response.getBody().getSelectiveCourses(), true);
}
}
Файл ScheduleController
@RestController
@RequestMapping("/schedule")
public class ScheduleController {
private final ScheduleService scheduleService;
private final StudentService studentService;
@Autowired
public ScheduleController(ScheduleService scheduleService, StudentService
studentService) {
this.scheduleService = scheduleService;
this.studentService = studentService;
}
@GetMapping()
public ResponseEntity<List<ScheduleDay>> getScheduleByUserGroups(@RequestParam()
int studentDegreeId,
98
482.ЧДТУ.231924-010 12-01
@RequestParam(required = false) String group,
@RequestParam(required = false) boolean shouldFilter) throws UnsupportedEncodingException,
NotFoundException {
List<ScheduleDay> schedule;
StudentDegree studentDegree =
studentService.getStudentDegree(studentDegreeId);
String studentGroupName = getStudentGroupName(studentDegree, group);
if (shouldFilter && isNotSecondYearStudent(studentDegree))
schedule = scheduleService.getFilteredSchedule(studentGroupName,
studentDegree);
else
schedule = scheduleService.getSchedule(studentGroupName, studentDegree);
return ResponseEntity.ok(schedule);
}
private String getStudentGroupName(StudentDegree studentDegree, String group)
throws NotFoundException {
if (studentDegree.getStudentGroup() == null) {
throw new NotFoundException("Неможливо знайти розклад для студента з
відсутньою групою");
}
return group != null ? group : studentDegree.getStudentGroup().getName();
}
private boolean isNotSecondYearStudent(StudentDegree studentDegree) {
return studentService.getStudentDegreeYear(studentDegree.getStudentGroup(),
true) != 2;
}
@PostMapping("/groups")
public ResponseEntity<List<ScheduleDay>> getScheduleByGroups(@Validated
@RequestBody ScheduleRequest scheduleRequest) throws UnsupportedEncodingException {
DateRange dateRange = new DateRange(scheduleRequest.getFromDate(),
scheduleRequest.getToDate());
List<ScheduleDay> schedule = new
ScheduleProvider(ScheduleSearch.GROUP).getScheduleByMultiParams(scheduleRequest.getParams()
, dateRange);
return ResponseEntity.ok(schedule);
}
@PostMapping("/teachers")
public ResponseEntity<List<ScheduleDay>> getScheduleByTeachers(@Validated
@RequestBody ScheduleRequest scheduleRequest) throws UnsupportedEncodingException {
DateRange dateRange = new DateRange(scheduleRequest.getFromDate(),
scheduleRequest.getToDate());
List<ScheduleDay> schedule = new
ScheduleProvider(ScheduleSearch.TEACHER).getScheduleByMultiParams(scheduleRequest.getParams
(), dateRange);
return ResponseEntity.ok(schedule);
}
// final String lev is just constant number required by the schedule server
@GetMapping("/teachers-suggestions")
public ResponseEntity<List<String>> getTeacherSuggestions(@RequestParam() String
query, @RequestParam(required = false, defaultValue = "0") int faculty)
99
482.ЧДТУ.231924-010 12-01
throws JsonProcessingException {
final String lev = "141";
return ResponseEntity.ok(scheduleService.getSuggestions(query, faculty,
lev));
}
@GetMapping("/groups-suggestions")
public ResponseEntity<List<String>> getGroupSuggestions(@RequestParam() String
query, @RequestParam(required = false, defaultValue = "0") int faculty)
throws JsonProcessingException {
final String lev = "142";
return ResponseEntity.ok(scheduleService.getSuggestions(query, faculty,
lev));
}
}
Файл ScheduleService
@Service
public class ScheduleService {
private final SelectiveCourseService selectiveCourseService;
private final StudentService studentService;
private final RestTemplate restTemplate;
public ScheduleService(RestTemplateBuilder restTemplateBuilder,
SelectiveCourseService selectiveCourseService,
StudentService studentService) {
this.restTemplate = restTemplateBuilder.build();
this.selectiveCourseService = selectiveCourseService;
this.studentService = studentService;
}
public List<ScheduleDay> getSchedule(String studentGroup, StudentDegree
studentDegree) throws UnsupportedEncodingException {
List<SelectiveCourse> selectiveCourses =
selectiveCourseService.getActiveSelectiveCoursesForCurrentYear(studentDegree.getId());
List<String> selectiveCoursesGroups = new ArrayList<>();
if (selectiveCourses != null) {
selectiveCoursesGroups = getSelectiveCoursesGroups(selectiveCourses,
studentDegree);
}
selectiveCoursesGroups.add(studentGroup);
ScheduleProvider scheduleProvider = new
ScheduleProvider(ScheduleSearch.GROUP);
return scheduleProvider.getScheduleByMultiParams(selectiveCoursesGroups, new
DateRange());
}
public List<ScheduleDay> getFilteredSchedule(String studentGroup, StudentDegree
studentDegree) throws UnsupportedEncodingException {
Schedule schedule = new Schedule(new ArrayList<>());
List<SelectiveCourse> selectiveCourses =
selectiveCourseService.getActiveSelectiveCoursesForCurrentYear(studentDegree.getId());
if (selectiveCourses != null) {
schedule = getFilteredScheduleForSelectiveCourses(selectiveCourses,
studentDegree);
100
482.ЧДТУ.231924-010 12-01
}
List<ScheduleDay> mainGroupScheduleDays = new
ScheduleProvider(ScheduleSearch.GROUP).getScheduleDays(studentGroup, new DateRange());
schedule.addScheduleDays(mainGroupScheduleDays);
return schedule.getSortedScheduleDays();
}
private Schedule getFilteredScheduleForSelectiveCourses(List<SelectiveCourse>
selectiveCourses, StudentDegree studentDegree) throws UnsupportedEncodingException {
List<String> selectiveCoursesGroups =
getSelectiveCoursesGroups(selectiveCourses, studentDegree);
List<String> selectiveCoursesNames =
getSelectiveCoursesNames(selectiveCourses);
ScheduleProvider scheduleProvider = new
FilteredScheduleProvider(ScheduleSearch.GROUP, selectiveCoursesNames);
return new
Schedule(scheduleProvider.getScheduleByMultiParams(selectiveCoursesGroups, new
DateRange()));
}
private List<String> getSelectiveCoursesGroups(List<SelectiveCourse>
selectiveCourses, StudentDegree studentDegree) {
int currentStudentSemester =
studentService.getCurrentStudentSemester(studentDegree.getStudentGroup());
List<String> selectiveCoursesGroups = selectiveCourses
.stream()
.filter(selectiveCourse -> selectiveCourse.getCourse().getSemester()
== currentStudentSemester)
.map(SelectiveCourse::getGroupName)
.collect(Collectors.toList());
return
selectiveCoursesGroups.stream().distinct().collect(Collectors.toList());
}
private List<String> getSelectiveCoursesNames(List<SelectiveCourse>
selectiveCourses) {
return selectiveCourses
.stream()
.map(selectiveCourse ->
selectiveCourse.getCourse().getCourseName().getName())
.collect(Collectors.toList());
}
public List<String> getSuggestions(String query, int faculty, String lev) throws
JsonProcessingException {
String url = SCHEDULE_SUGGESTIONS_URL + "&lev=" + lev + "&faculty=" + faculty
+ "&query=" + query;
ResponseEntity<String> response = this.restTemplate.getForEntity(url,
String.class);
Suggestions suggestions = new ObjectMapper().readValue(response.getBody(),
Suggestions.class);
return suggestions.getSuggestions();
}
}
Файл ScheduleSearch
101
482.ЧДТУ.231924-010 12-01
public enum ScheduleSearch {
GROUP("group"),
TEACHER("teacher");
private String paramName;
ScheduleSearch(String paramName) {
this.paramName = paramName;
}
public String getParamName() {
return paramName;
}
}
Файл ScheduleProvider
public class ScheduleProvider {
private final ScheduleHtmlParser scheduleHtmlParser;
private final ScheduleHtmlProvider scheduleHtmlProvider;
public ScheduleProvider(ScheduleSearch scheduleSearch) {
this.scheduleHtmlParser = new ScheduleHtmlParser();
this.scheduleHtmlProvider = new ScheduleHtmlProvider(scheduleSearch);
}
public List<ScheduleDay> getScheduleDays(String param, DateRange dateRange)
throws UnsupportedEncodingException {
String html = scheduleHtmlProvider.getScheduleHtml(param, dateRange);
return scheduleHtmlParser.parse(param, html);
}
public List<ScheduleDay> getScheduleByMultiParams(List<String> params, DateRange
dateRange) throws UnsupportedEncodingException {
Schedule schedule = new Schedule(new ArrayList<>());
for (String param : getDistinctParams(params)) {
schedule.addScheduleDays(getScheduleDays(param, dateRange));
}
return schedule.getSortedScheduleDays();
}
private List<String> getDistinctParams(List<String> params) {
return params.stream().distinct().collect(Collectors.toList());
}
}
Файл ScheduleHtmlProvider
public class ScheduleHtmlProvider {
private final RestTemplate restTemplate = new RestTemplateBuilder().build();
private final String charset = "cp1251";
private final ScheduleSearch requestParam;
public ScheduleHtmlProvider(ScheduleSearch requestParam) {
this.requestParam = requestParam;
}
public String getScheduleHtml(String param, DateRange dateRange) throws
UnsupportedEncodingException {
102
482.ЧДТУ.231924-010 12-01
this.restTemplate.getMessageConverters().add(0, new
StringHttpMessageConverter(Charset.forName(charset)));
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
String requestBody = createRequestBody(param, dateRange.getFromDate(),
dateRange.getToDate());
HttpEntity<String> request = new HttpEntity<>(requestBody, httpHeaders);
ResponseEntity<String> response =
this.restTemplate.postForEntity(SCHEDULE_SERVER_URL, request, String.class);
return response.getBody();
}
private String createRequestBody(String param, LocalDate fromDate, LocalDate
toDate) throws UnsupportedEncodingException {
StringBuilder requestBody = new StringBuilder("&")
.append(requestParam.getParamName())
.append("=")
.append(encodeParam(param));
if (fromDate != null) {
requestBody.append("&sdate=").append(getFormattedDate(fromDate));
}
if (toDate != null) {
requestBody.append("&edate=").append(getFormattedDate(toDate));
}
return requestBody.toString();
}
private String getFormattedDate(LocalDate localDate) {
return localDate.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
}
private String encodeParam(String param) throws UnsupportedEncodingException {
return URLEncoder.encode(param, charset).replaceAll("%20", "+");
}
}
Файл ScheduleHtmlParser
public class ScheduleHtmlParser {
private final LessonDetailsParser lessonDetailsParser;
private Elements days;
public ScheduleHtmlParser() {
lessonDetailsParser = new LessonDetailsParser();
}
public List<ScheduleDay> parse(String param, String html) {
Document scheduleHtml = Jsoup.parse(html);
days = scheduleHtml.select(".container .container").select(".col-md-6");
return parseDays(param);
}
private List<ScheduleDay> parseDays(String param) {
List<ScheduleDay> scheduleDays = new ArrayList<>();
for (Element day : days) {
103
482.ЧДТУ.231924-010 12-01
String dateWithDayName = day.select("h4").html();
String[] dateAndDayName = dateWithDayName.split("<small>", 2);
String date = dateAndDayName[0].trim();
String dayName = dateAndDayName[1].replaceAll("</small>", "");
Elements dailyLessons = day.select("tr");
scheduleDays.add(new ScheduleDay(dayName.trim(), date,
lessonDetailsParser.parse(dailyLessons, param)));
}
return scheduleDays;
}
}
Файл LessonDetailsParser
public class LessonDetailsParser {
private final BaseLessonDetailsExtractor[] extractors = {
new LessonDetailsExtractor(),
new NoLocationLessonDetailsExtractor(),
new NoLocationAndGroupsLessonDetailsExtractor()
};
private List<Lesson> lessonsForOneDay;
private int order;
private String timeRange;
public List<Lesson> parse(Elements lessons, String param) {
lessonsForOneDay = new ArrayList<>();
for (Element lesson : lessons) {
Elements lessonElements = lesson.select("td");
order = Integer.parseInt(lessonElements.get(0).html());
timeRange = lessonElements.get(1).html().replaceAll("<br>", " ");
String[] lessonsWithDetails = lessonElements.get(2).html().split("<div
class=\"link\">");
for (String lessonWithDetails : lessonsWithDetails) {
extractLessonDetails(lessonWithDetails, param);
}
}
return lessonsForOneDay;
}
private void extractLessonDetails(String lessonWithDetails, String param) {
for (BaseLessonDetailsExtractor extractor : extractors) {
if (extractor.canExtract(lessonWithDetails)) {
lessonsForOneDay.add(new Lesson(
param, order, timeRange,
extractor.getType(),
extractor.getNameAndTeacher(),
extractor.getLocation(),
extractor.getAdditionalGroups()));
break;
}
}
}
104
482.ЧДТУ.231924-010 12-01
}
Файл PollController
@RestController
@RequestMapping("/poll")
public class PollController {
private final PollService pollService;
public PollController(PollService pollService) {
this.pollService = pollService;
}
@GetMapping()
public ResponseEntity<List<PollDTO>> getActivePolls(@RequestParam int
studentDegreeId) throws NotFoundException {
return ResponseEntity.ok(pollService.getActivePolls(studentDegreeId));
}
@GetMapping("/{id}")
public ResponseEntity<PollDTO> getPollById(@PathVariable int id, @RequestParam
int studentDegreeId)
throws OperationCannotBePerformedException, NotFoundException {
return ResponseEntity.ok(pollService.getPollById(id, studentDegreeId));
}
@PostMapping("/vote")
public ResponseEntity<StudentDegreeVoteDTO> createStudentDegreeVotes(
@Validated @RequestBody StudentDegreeVotesWriteDTO
studentDegreeVotesWriteDTO)
throws OperationCannotBePerformedException, NotFoundException {
StudentDegreeVote studentDegreeVote =
pollService.createStudentDegreeVotes(studentDegreeVotesWriteDTO);
return ResponseEntity.ok(map(studentDegreeVote, StudentDegreeVoteDTO.class));
}
}
Файл PollService
@Service
public class PollService {
private final PollRepository pollRepository;
private final PollOptionRepository pollOptionRepository;
private final StudentDegreeVoteRepository studentDegreeVoteRepository;
private final StudentService studentService;
private final DateTimeService dateTimeService;
public PollService(PollRepository pollRepository,
PollOptionRepository pollOptionRepository,
StudentDegreeVoteRepository studentDegreeVoteRepository,
StudentService studentService,
DateTimeService dateTimeService) {
this.pollRepository = pollRepository;
this.studentDegreeVoteRepository = studentDegreeVoteRepository;
this.pollOptionRepository = pollOptionRepository;
this.studentService = studentService;
this.dateTimeService = dateTimeService;
}
105
482.ЧДТУ.231924-010 12-01
public List<PollDTO> getActivePolls(int studentDegreeId) throws NotFoundException
{
int facultyId = getStudentFacultyId(studentDegreeId);
List<Poll> allActivePolls = pollRepository.findAllByActiveTrue();
return allActivePolls.stream()
.map(poll -> mapPollEntityToDto(facultyId, poll, studentDegreeId))
.collect(Collectors.toList());
}
public PollDTO getPollById(int id, int studentDegreeId) throws
OperationCannotBePerformedException, NotFoundException {
Poll poll = pollRepository.findById(id);
if (poll == null) {
throw new OperationCannotBePerformedException("Не існує голосування за
таким id");
}
int facultyId = getStudentFacultyId(studentDegreeId);
return mapPollEntityToDto(facultyId, poll, studentDegreeId);
}
private PollDTO mapPollEntityToDto(int facultyId, Poll poll, int studentDegreeId)
{
poll.filterOptionsByFacultyId(facultyId);
PollDTO pollDTO = mapToPollDTO(poll, facultyId);
if (checkIfStudentVoted(studentDegreeId, poll.getId())) {
pollDTO.setVoted(true);
}
return pollDTO;
}
private boolean checkIfStudentVoted(int studentDegreeId, int pollId) {
StudentDegreeVote studentVote =
studentDegreeVoteRepository.findByStudentDegreeIdEqualsAndPollIdEquals(studentDegreeId,
pollId);
return studentVote != null;
}
@Transactional
public StudentDegreeVote createStudentDegreeVotes(StudentDegreeVotesWriteDTO
studentDegreeVotesWriteDTO)
throws OperationCannotBePerformedException, NotFoundException {
List<PollOption> pollOptions =
pollOptionRepository.findAllByIdIn(studentDegreeVotesWriteDTO.getOptionIds());
int studentDegreeId = studentDegreeVotesWriteDTO.getStudentDegreeId();
int studentFacultyId = getStudentFacultyId(studentDegreeId);
int userOptionsCount = studentDegreeVotesWriteDTO.getOptionIds().size();
PollOptionsValidator pollOptionsValidator = new
PollOptionsValidator(pollOptions);
pollOptionsValidator.validateOptionsFaculty(studentFacultyId);
pollOptionsValidator.validateOptionsIntegrity(userOptionsCount);
int pollId = pollOptions.get(0).getPoll().getId();
checkExistingStudentVotes(studentDegreeId, pollId);
106
482.ЧДТУ.231924-010 12-01
Poll poll = pollRepository.findById(pollId);
poll.inRangeOf(dateTimeService.now());
poll.checkMaxChoicesViolation(studentFacultyId, userOptionsCount);
StudentDegreeVote newStudentVote = new StudentDegreeVote(studentDegreeId,
pollId);
StudentDegreeVote studentDegreeVoteAfterSave =
studentDegreeVoteRepository.save(newStudentVote);
pollOptions.forEach(PollOption::incrementVotesCount);
pollOptionRepository.saveAll(pollOptions);
return studentDegreeVoteAfterSave;
}
private void checkExistingStudentVotes(int studentDegreeId, int pollId) throws
OperationCannotBePerformedException {
StudentDegreeVote existingStudentVote =
studentDegreeVoteRepository.findByStudentDegreeIdEqualsAndPollIdEquals(studentDegreeId,
pollId);
if (existingStudentVote != null) {
throw new OperationCannotBePerformedException("Ви вже взяли участь в
даному голосуванні");
}
}
private int getStudentFacultyId(int studentDegreeId) throws NotFoundException {
return
studentService.getStudentDegree(studentDegreeId).getSpecialization().getFacultyId();
}
}
Файл PollOptionsValidator
public class PollOptionsValidator {
private final List<PollOption> pollOptions;
public PollOptionsValidator(List<PollOption> pollOptions) {
this.pollOptions = pollOptions;
}
public void validateOptionsFaculty(int facultyId) throws
OperationCannotBePerformedException {
boolean nonFacultyOptions = pollOptions.stream().allMatch(pollOption ->
pollOption.getFacultyId() == null);
if (nonFacultyOptions) {
return;
}
boolean allOptionsHaveFacultyId = pollOptions.stream().allMatch(pollOption ->
pollOption.getFacultyId() != null);
if (!allOptionsHaveFacultyId) {
throw new OperationCannotBePerformedException("Некоректні ідентифікатори
кандидатів");
}
if (!pollOptions.stream().allMatch(pollOption -> pollOption.getFacultyId() ==
facultyId)) {
107
482.ЧДТУ.231924-010 12-01
throw new OperationCannotBePerformedException("Факульти кандидатів не
відповідають факультету студента");
}
}
public void validateOptionsIntegrity(int userOptionsCount) throws
OperationCannotBePerformedException {
if (pollOptions == null || pollOptions.size() != userOptionsCount) {
throw new OperationCannotBePerformedException("Вказані некоректні
ідентифікатори кандидатів");
}
boolean allOptionsOfTheSamePoll = pollOptions.stream()
.map(pollOption -> pollOption.getPoll().getId())
.distinct()
.limit(2)
.count() <= 1;
if (!allOptionsOfTheSamePoll) {
throw new OperationCannotBePerformedException("Не можна голосувати за
канидатів з різних опитувань одночасно");
}
}
}
Файл StudentController
@RestController
public class StudentController {
private StudentService restService;
@Autowired
public StudentController(StudentService restService) {
this.restService = restService;
}
@GetMapping("/students")
public ResponseEntity<Student> getStudent() {
return ResponseEntity.ok(restService.getStudent(JwtUtil.getUserIdInt()));
}
}
Файл StudentService
@Service
public class StudentService {
private final CurrentYearService currentYearService;
private final RestTemplate restTemplate;
private final DateTimeService dateTimeService;
public StudentService(RestTemplateBuilder restTemplateBuilder,
CurrentYearService currentYearService,
DateTimeService dateTimeService) {
this.restTemplate = restTemplateBuilder.build();
this.currentYearService = currentYearService;
this.dateTimeService = dateTimeService;
}
public Student getStudent(int studentId) {
String url = Constants.BASE_URL + "/students/" + studentId + "/degrees";
HttpEntity<Student> request = new HttpEntity<>(HttpUtil.getHeaders());
108
482.ЧДТУ.231924-010 12-01
ResponseEntity<Student> response = this.restTemplate.exchange(url,
HttpMethod.GET, request, Student.class);
Student student = response.getBody();
boolean isActiveStudentDegree =
student.getDegrees().stream().anyMatch(StudentDegree::isActive);
Set<StudentDegree> studentDegrees = formStudentDegrees(student.getDegrees(),
isActiveStudentDegree);
student.setDegrees(studentDegrees);
return student;
}
private Set<StudentDegree> formStudentDegrees(Set<StudentDegree> studentDegrees,
boolean onlyActiveStudentDegrees) {
Set<StudentDegree> degrees;
if (onlyActiveStudentDegrees)
degrees =
studentDegrees.stream().filter(StudentDegree::isActive).collect(Collectors.toSet());
else
degrees = getStudentDegreesInAcademicVacation(studentDegrees);
for (StudentDegree studentDegree : degrees) {
studentDegree.setRealYear(getStudentDegreeYear(studentDegree.getStudentGroup(), true));
studentDegree.setYear(getStudentDegreeYear(studentDegree.getStudentGroup(), false));
}
return degrees;
}
public Semester getStudentSemester(StudentGroup studentGroup) {
int year = getStudentDegreeYear(studentGroup, true);
return new Semester(year * 2 - 1, year * 2);
}
public int getCurrentStudentSemester(StudentGroup studentGroup) {
Semester semester = getStudentSemester(studentGroup);
return dateTimeService.now().getYear() == currentYearService.getYear() ?
semester.getFirst() : semester.getSecond();
}
public int getStudentDegreeYear(StudentGroup studentGroup, boolean realYear) {
int currentYear = currentYearService.getYear();
int groupCreationYear = studentGroup.getCreationYear();
int groupFirstYear = realYear ? studentGroup.getRealBeginYear() :
studentGroup.getBeginYears();
return currentYear - groupCreationYear + groupFirstYear;
}
private Set<StudentDegree> getStudentDegreesInAcademicVacation(Set<StudentDegree>
studentDegrees) {
List<Integer> studentDegreeIds =
studentDegrees.stream().map(StudentDegree::getId).collect(Collectors.toList());
String url = Constants.BASE_URL +
"/students/degrees/academic-vacations/active";
UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("studentDegreeIds", studentDegreeIds);
109
482.ЧДТУ.231924-010 12-01
HttpEntity<StudentAcademicVacation[]> request = new
HttpEntity<>(HttpUtil.getHeaders());
ResponseEntity<StudentAcademicVacation[]> response =
this.restTemplate.exchange(urlBuilder.toUriString(), HttpMethod.GET, request,
StudentAcademicVacation[].class);
return Arrays.stream(response.getBody())
.map(StudentAcademicVacation::getStudentDegree)
.collect(Collectors.toSet());
}
public StudentStatus getStudentStatus(int studentId) {
String url = Constants.BASE_URL + "/students/status?studentId=" + studentId;
HttpEntity<StudentStatusModel> request = new
HttpEntity<>(HttpUtil.getHeaders());
ResponseEntity<StudentStatusModel> response = this.restTemplate.exchange(url,
HttpMethod.GET, request, StudentStatusModel.class);
return response.getBody().getStudentStatus();
}
public StudentDegree getStudentDegree(int studentDegreeId) throws
NotFoundException {
StudentDegree studentDegree = getStudent(JwtUtil.getUserIdInt())
.getDegrees()
.stream()
.filter(sd -> sd.getId() ==
studentDegreeId).findFirst().orElse(null);
if (studentDegree == null) {
throw new NotFoundException("Не існує student degree з id = " +
studentDegreeId);
}
return studentDegree;
}
}
Файл GenerateApplicationController
@RestController
@RequestMapping("/applications")
public class GenerateApplicationController {
private GenerateApplicationService generateApplicationService;
public GenerateApplicationController(GenerateApplicationService
generateApplicationService) {
this.generateApplicationService = generateApplicationService;
}
@GetMapping("/individual-training-schedule/documents")
public ResponseEntity<String[]>
getDocumentExamplesForIndividualTrainingScheduleApplication() {
return
ResponseEntity.ok(generateApplicationService.getDocumentExamplesForIndividualTrainingSchedu
leApplication());
}
@GetMapping("/individual-training-schedule/reasons")
public ResponseEntity<String[]>
getReasonsForIndividualTrainingScheduleApplication() {
110
482.ЧДТУ.231924-010 12-01
return
ResponseEntity.ok(generateApplicationService.getReasonsForIndividualTrainingScheduleApplica
tion());
}
@GetMapping("/granting-academic-vacation/documents")
public ResponseEntity<String[]>
getDocumentExamplesForGrantingAcademicVacationApplication() {
return
ResponseEntity.ok(generateApplicationService.getDocumentExamplesForGrantingAcademicVacation
Application());
}
@GetMapping("/granting-academic-vacation/reasons")
public ResponseEntity<String[]>
getReasonExamplesForGrantingAcademicVacationApplication() {
return
ResponseEntity.ok(generateApplicationService.getReasonExamplesForGrantingAcademicVacationAp
plication());
}
@GetMapping("/retake-exam")
public ResponseEntity<Application>
generateRetakingExamApplication(@RequestParam() int studentDegreeId,
@RequestParam() String knowledgeControl,
@RequestParam() String course
) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateRetakingExamApplication(studentDegreeI
d, knowledgeControl, course));
}
@GetMapping("/renew-after-academic-vacation")
public ResponseEntity<Application>
generateRenewingAfterAcademicVacationApplication(@RequestParam() int studentDegreeId,
@RequestParam() String date) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateRenewingAfterAcademicVacationApplicati
on(studentDegreeId, date));
}
@GetMapping("/expel")
public ResponseEntity<Application> generateExpellingApplication(@RequestParam()
int studentDegreeId, @RequestParam() String date) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateExpellingApplication(date,
studentDegreeId));
}
@GetMapping("/studying-on-budget")
public ResponseEntity<Application>
generateStudyingOnStateBudgetApplication(@RequestParam() int studentDegreeId) throws
NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateStudyingOnStateBudgetApplication(stude
ntDegreeId));
}
@GetMapping("/grant-academic-vacation")
111
482.ЧДТУ.231924-010 12-01
public ResponseEntity<Application>
generateStudyingOnStateBudgetApplication(@RequestParam() int studentDegreeId,
@RequestParam() String fromDate,
@RequestParam() String toDate,
@RequestParam() String reason,
@RequestParam() String document) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateGrantingAcademicVacationApplication(st
udentDegreeId, fromDate, toDate, reason, document));
}
@GetMapping("/change-name")
public ResponseEntity<Application>
generateChangingNameApplication(@RequestParam() int studentDegreeId,
@RequestParam() String name,
@RequestParam() String formerName,
@RequestParam() String newName) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateChangingNameApplication(studentDegreeI
d, name, formerName, newName));
}
@GetMapping("/renew-after-expelling")
public ResponseEntity<Application>
generateRenewingAfterExpellingApplication(@RequestParam() int studentDegreeId,
@RequestParam() int year,
@RequestParam() String faculty,
@RequestParam() String speciality,
@RequestParam() String tuitionForm,
@RequestParam() String payment,
@RequestParam() String date) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateRenewingAfterExpellingApplication(stud
entDegreeId, year, faculty, speciality, tuitionForm, payment, date));
}
@GetMapping("/refuse-scholarship")
public ResponseEntity<Application>
generateScholarshipRefusingApplication(@RequestParam() int studentDegreeId,
@RequestParam() String firstScholarship,
@RequestParam() String secondScholarship) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateScholarshipRefusingApplication(student
DegreeId, firstScholarship, secondScholarship));
}
112
482.ЧДТУ.231924-010 12-01
@GetMapping("/individual-training-schedule")
public ResponseEntity<Application>
generateIndividualTrainingScheduleApplication(@RequestParam() int studentDegreeId,
@RequestParam() String date,
@RequestParam() String reason,
@RequestParam() String document) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateIndividualTrainingScheduleApplication(
studentDegreeId, date, reason, document));
}
@GetMapping("/change-tuition-form")
public ResponseEntity<Application>
generateChangingTuitionFormApplication(@RequestParam() int studentDegreeId, @RequestParam()
String date) throws NotFoundException {
return
ResponseEntity.ok(generateApplicationService.generateChangingTuitionFormApplication(student
DegreeId, date));
}
@GetMapping("/change-speciality")
public ResponseEntity<Application>
generateChangingSpecialityApplication(@RequestParam() int studentDegreeId,
@RequestParam() String specialization,
@RequestParam() String speciality,
@RequestParam() String tuitionForm,
@RequestParam() int year,
@RequestParam() String payment,
@RequestParam() String date) throws NotFoundException {
return ResponseEntity
.ok(generateApplicationService.generateChangingSpecialityApplication(studentDegreeId,
specialization, speciality, tuitionForm, year, payment, date));
}
@GetMapping("/change-university")
public ResponseEntity<Application> generateChangingUniversityApplication(int
studentDegreeId,
@RequestParam() String university,
@RequestParam() String specialization,
@RequestParam() String speciality,
@RequestParam() int year,
@RequestParam() String tuitionForm,
@RequestParam() String payment) throws NotFoundException {
return ResponseEntity
113
482.ЧДТУ.231924-010 12-01
.ok(generateApplicationService.generateChangingUniversityApplication(studentDegreeId,
university, specialization, speciality, year, tuitionForm, payment));
}
}
Файл GenerateApplicationService
@Service
public class GenerateApplicationService {
private StudentService studentService;
private CurrentYearService currentYearService;
private RestTemplate restTemplate;
@Autowired
public GenerateApplicationService(StudentService studentService,
CurrentYearService currentYearService,
RestTemplateBuilder restTemplateBuilder) {
this.studentService = studentService;
this.restTemplate = restTemplateBuilder.build();
this.currentYearService = currentYearService;
}
public String[] getDocumentExamplesForIndividualTrainingScheduleApplication() {
final String[] documentExamples = {"довідку з місця роботи", "витяг з
трудової книжки", "копію трудового договору",
"медичну довідку про вагітність", "свідоцтво про народження дитини"};
return documentExamples;
}
public String[] getReasonsForIndividualTrainingScheduleApplication() {
final String[] reasons = {"працевлаштуванням за фахом", "вагітністю",
"народженням дитини"};
return reasons;
}
public String[] getDocumentExamplesForGrantingAcademicVacationApplication() {
final String[] documentExamples = {"довідка лікувально-консультативної
комісії", "довідка про вагітність лікувально-профілактичної установи",
"копія свідоцтва про народження дитини", "повістка військового
комісаріату", "довідка про стан здоров’я дитини"};
return documentExamples;
}
public String[] getReasonExamplesForGrantingAcademicVacationApplication() {
final String[] documentExamples = {"за станом здоров'я", "у зв'язку з участю
в програмах академічної мобільності", "у зв'язку з військовою службою",
"за сімейними та іншими особистими обставинами", "по вагітності та
пологах", "по догляду за дитиною до досягнення нею 3-річного віку"};
return documentExamples;
}
public Application generateRetakingExamApplication(int studentDegreeId, String
knowledgeControl, String course) throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder =
new DeanApplicationHeaderBuilder(student, studentDegree,
studentDegreeYear);
114
482.ЧДТУ.231924-010 12-01
ApplicationBodyBuilder applicationBodyBuilder = new
RetakingExamApplicationBodyBuilder(studentDegree, knowledgeControl, course);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateRenewingAfterAcademicVacationApplication(int
studentDegreeId, String date) throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder =
new RectorApplicationHeaderBuilder(student, studentDegree,
studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
RenewingAfterAcademicVacationApplicationBodyBuilder(date);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateExpellingApplication(String date, int studentDegreeId)
throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder =
new RectorApplicationHeaderBuilder(student, studentDegree,
studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
ExpellingApplicationBodyBuilder(studentDegree, studentDegreeYear, date);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateStudyingOnStateBudgetApplication(int studentDegreeId)
throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder =
new RectorApplicationHeaderBuilder(student, studentDegree,
studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
StudyingOnBudgetApplicationBodyBuilder();
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateGrantingAcademicVacationApplication(int
studentDegreeId, String fromDate, String toDate, String reason, String document) throws
NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
115
482.ЧДТУ.231924-010 12-01
ApplicationHeaderBuilder applicationHeaderBuilder =
new RectorApplicationHeaderBuilder(student, studentDegree,
studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
GrantingAcademicVacationBodyBuilder(fromDate, toDate, reason, document);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateChangingNameApplication(int studentDegreeId, String
name, String formerName, String newName) throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder =
new RectorApplicationHeaderBuilder(student, studentDegree,
studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
ChangingNameApplicationBodyBuilder(name, formerName, newName);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateRenewingAfterExpellingApplication(int studentDegreeId,
int year,
String faculty,
String speciality,
String tuitionForm,
String payment,
String date) throws
NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
StudentExpel studentExpel = getStudentExpel(studentDegreeId);
ApplicationHeaderBuilder applicationHeaderBuilder = new
FormerStudentRectorApplicationHeaderBuilder(student, studentDegree, studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder =
new RenewingAfterExpellingApplicationBodyBuilder(year, faculty,
speciality, tuitionForm, payment, date, studentExpel, student.getSex());
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateScholarshipRefusingApplication(int studentDegreeId,
String firstScholarship, String secondScholarship) throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder = new
ExpandedRectorApplicationHeaderBuilder(student, studentDegree, studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
ScholarshipRefusingApplicationBodyBuilder(student, firstScholarship, secondScholarship);
116
482.ЧДТУ.231924-010 12-01
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateIndividualTrainingScheduleApplication(int
studentDegreeId,
String date,
String reason,
String document)
throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
int currentStudentSemester =
studentService.getCurrentStudentSemester(studentDegree.getStudentGroup());
int studentYearSemester = currentStudentSemester % 2 == 0 ? 2 : 1;
int currentStudyYear = currentYearService.getYear();
CoursesForGroup[] coursesForGroup =
getCourses(studentDegree.getStudentGroup().getId(), currentStudentSemester);
List<ApplicationTableRow> applicationTableRows = new ArrayList<>();
for (CoursesForGroup courseForGroup : coursesForGroup) {
String teacherWithInitials =
PersonUtil.makeInitialsSurnameLast(courseForGroup.getTeacher());
applicationTableRows.add(new
ApplicationTableRow(courseForGroup.getCourse().getCourseName().getName(),
teacherWithInitials));
}
ApplicationHeaderBuilder applicationHeaderBuilder = new
DeanApplicationHeaderBuilder(student, studentDegree, studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
IndividualTrainingScheduleApplicationBodyBuilder(studentYearSemester, currentStudyYear,
date, reason, document);
return new ApplicationWithTable(applicationHeaderBuilder,
applicationBodyBuilder, applicationTableRows);
}
public Application generateChangingTuitionFormApplication(int studentDegreeId,
String date) throws NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder = new
RectorApplicationHeaderBuilder(student, studentDegree, studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder = new
ChangingTuitionFormApplicationBodyBuilder(studentDegreeYear, date, studentDegree);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateChangingSpecialityApplication(int studentDegreeId,
String specialization,
String speciality,
String tuitionForm,
117
482.ЧДТУ.231924-010 12-01
int year,
String payment,
String date) throws
NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder = new
RectorApplicationHeaderBuilder(student, studentDegree, studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder =
new ChangingSpecialityApplicationBodyBuilder(specialization,
speciality, tuitionForm, year, studentDegree.getSpecialization().getDegree(), payment,
date);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
public Application generateChangingUniversityApplication(int studentDegreeId,
String university,
String specialization,
String speciality,
int year,
String tuitionForm,
String payment) throws
NotFoundException {
Student student = studentService.getStudent(JwtUtil.getUserIdInt());
StudentDegree studentDegree = StudentUtil.getStudentDegree(studentDegreeId,
student);
int studentDegreeYear = getStudentDegreeYear(studentDegree);
ApplicationHeaderBuilder applicationHeaderBuilder = new
RectorApplicationHeaderBuilder(student, studentDegree, studentDegreeYear);
ApplicationBodyBuilder applicationBodyBuilder =
new ChangingUniversityApplicationBodyBuilder(university,
specialization, speciality, year, studentDegree.getSpecialization().getDegree(),
tuitionForm, payment);
return new Application(applicationHeaderBuilder, applicationBodyBuilder);
}
private int getStudentDegreeYear(StudentDegree studentDegree) {
return studentService.getStudentDegreeYear(studentDegree.getStudentGroup(),
false);
}
private StudentExpel getStudentExpel(int studentDegreeId) {
String url = Constants.BASE_URL +
"/students/degrees/expels/last?studentDegreeId=" + studentDegreeId;
HttpEntity request = new HttpEntity(HttpUtil.getHeaders());
ResponseEntity<StudentExpel> response = this.restTemplate.exchange(url,
HttpMethod.GET, request, StudentExpel.class);
return response.getBody();
}
private CoursesForGroup[] getCourses(int groupId, int semester) {
String url = Constants.BASE_URL + "/groups/" + groupId + "/courses?semester="
+ semester;
HttpEntity request = new HttpEntity(HttpUtil.getHeaders());
ResponseEntity<CoursesForGroup[]> response = this.restTemplate.exchange(url,
HttpMethod.GET, request, CoursesForGroup[].class);
return response.getBody();
}
}
118
ДОДАТОК В
СЕРВЕРНА ЧАСТИНА МОБІЛЬНОГО ЗАСТОСУНКУ «СТУДЕНТ ЧДТУ»
Інструкція користувача
482.ЧДТУ.231924-010 34-01
Листів 9
Розробник ________________ Чоповенко В. М.
Черкаси 2023
482.ЧДТУ.231924-010 34-01
Так як розробка велась над серверною частиною, то в ролі інтерфейсу
користувача виступає REST API. Далі буде описано необхідні кроки для того, щоб
запустити серверну частину.
Першим кроком буде завантажити з GitHub репозиторія наступні проекти:
– https://github.com/chdtu-fitis/deanoffice-mobile-backend
– https://github.com/chdtu-fitis/deanoffice-backend
Далі необхідно завантажити СУБД PostgreSQL 9.6 або більше і встановити її
разом з PgAdmin клієнтом. Порт залишити стандартний - 5432. Далі відкриваємо
PgAdmin і створюємо дві бази даних deanoffice та deanoffice-student-mobile. Ці БД
будуть заповнені після запуску проектів автоматично.
В наступному кроці необхідно завантажити редактор IntelliJ IDEA
Community Edition. Встановлюємо його та відкриваємо завантажені проекти.
Автоматично запуститься індексація та завантаження необхідних бібліотек. Якщо
ж ні, необхідно відкрити вкладу Gradle в лівій частині редактора і натиснути
кнопку Refresh. Далі в файлі application.yaml в полях username та password
змінюємо значення на ті, які були вказані при встановленні PostgreSQL.
Після цього в проекті deanoffice на вкладці Gradle запускаємо Task під
назвою bootRun. Запуститься проект після чого в терміналі необхідно виконати
команду:
Рис. В.1 - cURL команда для отримання токена
120
482.ЧДТУ.231924-010 34-01
Отриманий токен необхідно вставити замість значення в полі token, файл -
application.yaml.
Далі таким же способом, як і попередній проект, запускаємо
deanoffice-student-mobile через Task з назвою bootRun.
Для кожного запиту необхідно додавати X-App-Version заголовок,
значенням якого є поточна версія додатку (можна перевірити в application.yaml
файлі), інакше буде повернуто помилку і відповідне повідомлення. Крім цього
заголовка, необхідно додавати до кожного запиту заголовок Authorization,
значенням якого є Bearer <token>, де token - результат запиту на API логіну
(описаний в 12 пункті).
1 GET /selective-courses
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента.
Призначення: в першому турі вибору повертає вибіркові дисципліни, на які
студент може записатись; між першим і другим туром - повертає дисципліни, на
які студент записався в першому турі; в другому турі повертає дисципліни, обрані
в першому турі (містять поле selectedInFirstRound = true) і ті, на які можна
записатись (якщо серед обраних в першому турі є дискваліфіковані); після другого
туру повертає дисципліни, на які студент записався в результаті двох турів.
2 POST /selective-courses/registration
Тіло запиту:
{
"studentDegree": {
"id": <int> // ідентифікатор спеціальності студента
},
"selectiveCourses": [ "id": <int>, // ідентифікатор вибіркової дисципліни, на
яку записується студент]
}
Призначення: використовується для запису студента на вибіркові
дисципліни; відправляє обрані дисципліни в основну систему деканату.
121
482.ЧДТУ.231924-010 34-01
3 GET /schedule
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String group (необовʼязковий) - група, за якою ведеться пошук розкладу;
якщо не вказана - використовується група студента, яка зберігається в
системі;
– boolean shouldFilter (необовʼязковий) - якщо true, то повертає розклад для
основної групи та для лише тих вибіркових дисципліни, на які записаний
студент (застосовується лише для 2 курсу).
Призначення: повертає розклад студента на місяць з урахуванням
вибіркових дисциплін.
4 POST /schedule/groups
Тіло запиту:
{
"params": [<string>, <string>...], // список параметрів (груп)
"fromDate": "2023.04.08", // початкова дата
"toDate": "2023.05.08" // кінцева дата
}
Призначення: повертає розклад за вказаною групою (групами) на вказаний
період.
5 GET /schedule/groups-suggestions
URL параметри:
– String query - назва групи або її частина.
Призначення: повертає пропозиції назв груп за вказаним параметром.
6 POST /schedule/teachers
Тіло запиту:
{
"params": [<string>, <string>...], // список параметрів (викладачів)
"fromDate": "2023.04.08", // початкова дата
"toDate": "2023.05.08" // кінцева дата
122
482.ЧДТУ.231924-010 34-01
}
Призначення: повертає розклад за вказаним викладачем (викладачами) на
вказаний період.
7 GET /schedule/teachers-suggestions
URL Параметри:
– String query - частина або повне ПІБ викладача.
Призначення: повертає пропозиції ПІБ викладачів за вказаним параметром.
8 GET /poll
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента.
Призначення: повертає список активних опитувань з урахуванням
факультету студента (варіанти опитувань можуть бути призначені лише для
конкретного факультету; необхідна кількість обраних варіантів може також
залежати від факультету).
9 GET /poll/{id}
Параметри шляху:
– int id - ідентифікатор опитування.
Призначення: працює, як і попередній API, але повертає лише одне
опитування за вказаним ідентифікатором.
10 POST /poll/vote
Тіло запиту:
{
"studentDegreeId": [<string>, <string>...], // ідентифікатор спеціальності
студента
"optionIds": [<int>, <int>] // список варіантів, які обрав студент
}
Призначення: зберігає обрані студентом варіанти в базу даних (для
збереження анонімності в базі даних не зберігається інформація про те, який
студент проголосував та який варіант обрав; зберігається лише кількість голосів,
відданих за кожен варіант голосування).
123
482.ЧДТУ.231924-010 34-01
11 GET /students
Призначення: повертає інформацію про студента та його спеціальності;
якщо у студента є хоча б одна активна спеціальність, то повертаються лише
активні спеціальності; якщо немає жодної активної спеціальності, то
повертаються лише спеціальності в академічній відпустці; ідентифікатор студента
береться з токена доступу.
12 POST /api/authenticate
Тіло запиту:
{
"username": <string>, // логін
"password": <string> // пароль
}
Призначення: порівнює логін та пароль з тими, що знаходяться в базі
даних, та, у випадку співпадіння, повертає JWT токен.
13 GET /application-types
Призначення: повертає список доступних для генерації заяв.
14 GET /applications/change-name
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String name - тип інформації, що змінюється (імʼя/прізвище);
– String formerName - попереднє імʼя/прізвище;
– String newName - нове імʼя/прізвище.
Призначення: повертає шаблон заяви на зміну імені/прізвища.
15 GET /applications/change-specialty
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String specialization - нова освітня програма;
– String specialty - нова спеціальність;
– String tuitionForm - нова форма навчання;
– int year - курс, на який переводиться студент;
124
482.ЧДТУ.231924-010 34-01
– String payment - тип оплати навчання (державний бюджет/власні кошти);
– String date - дата переведення на нову спеціальність.
Призначення: повертає шаблон заяви на зміну спеціальності.
16 GET /applications/change-tuition-form
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String date - дата переведення на нову форму навчання.
Призначення: повертає шаблон заяви на зміну форми навчання.
17 GET /applications/change-university
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String university - назва нового університету;
– String specialization - нова освітня програма;
– String specialty - нова спеціальність;
– int year - курс, на який переводиться студент;
– String tuitionForm - нова форма навчання;
– String payment - новий тип оплати навчання (державний бюджет/власні
кошти).
Призначення: повертає шаблон заяви на зміну університету.
18 GET /applications/expel
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String date - дата відрахування.
Призначення: повертає шаблон заяви на відрахування.
19 GET /applications/grant-academic-vacation
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String fromDate - дата початку академічної відпустки;
– String toDate - дата закінчення академічної відпустки;
– String reason - причина надання академічної відпустки;
125
482.ЧДТУ.231924-010 34-01
– String document - документ про підтвердження причини.
Призначення: повертає шаблон заяви про надання академічної відпустки.
20 GET /applications/grant-academic-vacation/documents
Призначення: повертає список можливих документів про підтвердження
причини запиту на надання академічної відпустки.
21 GET /applications/grant-academic-vacation/reasons
Призначення: повертає список можливих причин запиту на надання
академічної відпустки.
22 GET /applications/individual-training-schedule
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String date - дата, з якої надається індивідуальний графік навчання;
– String reason - причина надання індивідуального графіку навчання;
– String document - документ про підтвердження причини.
Призначення: повертає шаблон заяви про надання індивідуального графіку
навчання.
23 GET /applications/individual-training-schedule/documents
Призначення: повертає список можливих документів про підтвердження
причини запиту на надання індивідуального графіку навчання.
24 GET /applications/individual-training-schedule/reasons
Призначення: повертає список можливих причин запиту на надання
індивідуального графіку навчання.
25 GET /applications/refuse-scholarship
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String firstScholarship - стипендія, від якої студент відмовляється;
– String secondScholarship - стипендія, на користь якої студент
відмовляється від вказаної вище.
Призначення: повертає шаблон заяви про відмову від стипендії.
26 GET /applications/renew-after-academic-vacation
126
482.ЧДТУ.231924-010 34-01
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String date - дата відновлення після академічної відпустки.
Призначення: повертає шаблон заяви на поновлення після академічної
відпустки.
27 GET /applications/renew-after-expelling
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– int year - курс, на який студент планує поновитись;
– String faculty - факультет, на який студент планує поновитись;
– String specialty - спеціальність, на яку студент планує поновитись;
– String tuitionForm - форма навчання, на яку студент планує поновитись;
– String payment - тип оплати навчання (державний бюджет/власні кошти),
на який студент планує поновитись;
– String date - дата, з якої студент планує поновитись.
Призначення: повертає шаблон заяви про відновлення після відрахування.
28 GET /applications/retake-exam
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента;
– String knowledgeControl - тип контролю знань (наприклад: іспит, залік);
– String course - дисципліна, яку студент планує перескладати.
Призначення: повертає шаблон заяви про перескладання дисципліни.
29 GET /applications/studying-on-budget
URL Параметри:
– int studentDegreeId - ідентифікатор спеціальності студента.
Призначення: повертає шаблон заяви на участь в конкурсі для переведення
на вакантне місце навчання за рахунок коштів державного бюджету.
127
ДОДАТОК Г
СЕРВЕРНА ЧАСТИНА МОБІЛЬНОГО ЗАСТОСУНКУ «СТУДЕНТ ЧДТУ»
Графічні матеріали
482.ЧДТУ.231924-010 90-01
Листів 9
Розробник ________________ Чоповенко В. М.
Черкаси 2023
482.ЧДТУ.231924-010 90-01
Рис. Г.1 - Слайд вступу
Рис. Г.2 - Слайд опису актуальності теми
129
482.ЧДТУ.231924-010 90-01
Рис. Г.3 - Слайд опису аналогів (Мій НУВГП)
Рис. Г.4 - Слайд опису аналогів (KNU Online)
130
482.ЧДТУ.231924-010 90-01
Рис. Г.5 - Слайд “Завдання”
Рис. Г.6 - Слайд “Команда проекту”
131
482.ЧДТУ.231924-010 90-01
Рис. Г.7 - Слайд “Технології”
Рис. Г.8 - Слайд “Use Case діаграми”
132
482.ЧДТУ.231924-010 90-01
Рис. Г.9 - Слайд “Use Case діаграми (продовження)”
Рис. Г.10 - Слайд “Діаграми класів (модуль вибіркових дисциплін)”
133
482.ЧДТУ.231924-010 90-01
Рис. Г.11 - Слайд з Use Case діаграмами
Рис. Г.12 - Слайд з Use Case діаграмами
134
482.ЧДТУ.231924-010 90-01
Рис. Г.13 - Слайд “Реалізований функціонал”
Рис. Г.14 - Слайд “План розвитку проекту”
135
482.ЧДТУ.231924-010 90-01
Рис. Г.15 - Слайд “Висновки”
Рис. Г.16 - Слайд “Дякую за увагу”
136