JavaRush /Курси /Java Server /Каркас ReadLater Starter

Каркас ReadLater Starter

Java Server
Рівень 2 , Лекція 2
Відкрита

1. Каркас проєкту

Проєкт — це не просто клас Main, який запускається. Спершу легко подумати: «я створив файл, натиснув Run — отже, проєкт уже є». Але щойно з’являється другий файл, повторний запуск через тиждень або спроба стартувати на іншій машині, з’ясовується: у «папки з кодом» немає пам’яті. Вона не пояснює, як її зібрати й запустити.

Каркас Gradle-проєкту — це, по суті, явна домовленість між вами й майбутнім собою, а ще — з одногрупниками, рев’юером, роботодавцем і вашим котом, який випадково натиснув Delete. У цій домовленості прописано, де лежить код, де лежать ресурси, які файли вважаються «офіційними», як називається проєкт, який у нього стартовий клас і чому запуск виконується з кореня проєкту однією командою, а не за схемою «я тут в IDEA галочку поставив».

Можна провести грубу, але корисну аналогію: Java-файл — це інгредієнт, а каркас проєкту — рецепт із температурою, часом і кроками. Інгредієнти без рецепта іноді теж можна з’їсти, але на виході часто виходить «салат із усього, що було в холодильнику».

2. Підсумковий вигляд ReadLater Starter

Зараз ми зберемо мінімальну структуру, у якій з першого погляду зрозуміло: це Gradle-проєкт, він запускається через Wrapper, у нього є build-файли, код і ресурси. Це не «ідеальна» структура на всі часи, але це стійка база, на яку ми спокійно нарощуватимемо наступні теми курсу.

І ще одна важлива домовленість: Wrapper-файли в цьому дереві не пишуть руками. Вони вже входять до стартового каркаса проєкту й далі комітяться в репозиторій як частина єдиної точки входу. Нижче — той самий мінімальний каркас, який потім будемо перевіряти через build і run.

Ось еталонне дерево — найменший мінімум:

readlater-starter/
├─ gradlew
├─ gradlew.bat
├─ gradle/
│  └─ wrapper/
│     ├─ gradle-wrapper.jar
│     └─ gradle-wrapper.properties
├─ settings.gradle.kts
├─ build.gradle.kts
├─ README.md
└─ src/
   └─ main/
      ├─ java/
      │  └─ com/
      │     └─ example/
      │        └─ readlater/
      │           ├─ ReadLaterApplication.java
      │           └─ ConsoleBanner.java
      └─ resources/
         └─ application.properties

Щоб це дерево не лишилося просто «страшною картинкою», корисно один раз зрозуміти роль кожного елемента. Нижче — компактна таблиця, до якої ви ще не раз повертатиметеся. І це нормально.

Що це Де лежить Для чого потрібно
Wrapper-скрипти gradlew,
gradlew.bat
Єдина точка входу в проєкт: запускаємо Gradle «з проєкту», а не «із системи».
Wrapper-налаштування gradle/wrapper/* Фіксують версію Gradle й дають змогу автоматично завантажувати потрібний Gradle.
Ім’я збирання settings.gradle.kts Повідомляє Gradle, як називається проєкт і де взагалі починається збирання.
Правила збирання build.gradle.kts Головний файл, де описано, як збирати й запускати проєкт.
Документація запуску README.md Щоб проєкт запускався не «на словах», а за інструкцією в репозиторії.
Java-код src/main/java «Бойовий» код застосунку: не тести й не конфіги.
Ресурси src/main/resources Не-Java файли: конфіги, шаблони, зразковий JSON тощо.

Якщо ви зараз дивитеся на це й думаєте: «Занадто багато папок заради одного рядка в консолі», вітаю — це класична правильна реакція. Саме тому в реальних проєктах каркас часто генерують. Але в навчальному курсі нам важливо один раз зібрати його вручну, щоб потім не сприймати структуру як магію.

3. Корінь проєкту: навігація й опора для Gradle

Корінь репозиторію — не місце для «всього поспіль». Це як панель приладів: подивилися й зрозуміли, де запуск, де збирання, де документація, де код. Якщо в корені лежать десятки випадкових файлів, проєкт починає виглядати як робочий стіл у Windows після важкого тижня — ніби все десь є, але знайти неможливо.

У нашому каркасі корінь містить лише те, що дійсно відповідає за життя проєкту як артефакта: Wrapper, два Gradle-файли, README й папку src. І зверніть увагу на важливу звичку: ми не кладемо Java-файли поруч із build.gradle.kts. Код живе в src/main/java, тому що Gradle, та й уся Java-екосистема, очікує саме такого порядку. А отже, сюрпризів буде менше.

Ще один момент, який краще знати наперед: згодом у вас з’являться папки на кшталт build/ і .gradle/. Їх Gradle створює сам. Це згенеровані директорії, і в «чистому» репозиторії їх зазвичай не тримають як вихідники. Зараз ми їх не створюємо вручну й докладно не розбираємо — просто не лякайтесь, коли побачите.

4. settings.gradle.kts: ім’я проєкту

Файл settings.gradle.kts — коротка, але важлива річ: він допомагає Gradle зрозуміти, що перед ним за збирання, і задає ім’я проєкту. Початківці часто плутають його з build.gradle.kts — і, якщо чесно, назви в них не найпривітніші. Але ролі різні: settings — це радше про проєкт цілком, а build — про правила збирання й запуску.

У нашому курсі ми тримаємо settings.gradle.kts максимально простим. Він лежить у корені й містить один рядок, який задає ім’я збирання. Це ім’я потім буде видно в логах, у назві артефактів і взагалі в загальному відчутті «що я зараз збираю».

Створіть файл settings.gradle.kts у корені й покладіть туди:

// Ім’я проєкту, яке буде видно в логах і артефактах
rootProject.name = "readlater-starter"

Тут важливе не стільки саме ім’я — воно може бути трохи іншим, — скільки принцип: ім’я має бути стабільним, зрозумілим і збігатися з тим, як ви називаєте репозиторій. Якщо репозиторій називається readlater-starter, а Gradle-проєкт — demo-final-v3-real-last, то це, звісно, весело… але лише перші 30 секунд.

5. build.gradle.kts: мінімум для збирання

build.gradle.kts — головний файл, який зазвичай лякає найбільше. Він виглядає як код, але це не ваш Java-код, а опис збирання на Kotlin DSL. Важливо відразу виробити спокійне ставлення: вам не потрібно розуміти весь Gradle, щоб нормально стартувати. На цьому етапі достатньо, щоб файл був мінімальним, читабельним і відповідав технічному baseline курсу: Java 25, Kotlin DSL, запуск через Gradle.

Ми зараз зробимо build.gradle.kts настільки маленьким, наскільки можливо, але при цьому достатньо корисним, щоб проєкт міг компілюватися і — трохи згодом — запускатися через ./gradlew run. При цьому ми свідомо не заглиблюємося в подробиці плагінів і залежностей: для цього буде окремий рівень. Тут ми просто фіксуємо каркас.

Почнімо з мінімального блоку plugins. Ми підключаємо два базові плагіни: java і application.

plugins {
    // Плагін для компіляції Java-коду
    java
    // Плагін для запуску застосунку через `gradlew run`
    application
}

Ці два рядки дають проєкту потрібну поведінку: Gradle починає розуміти, що потрібно компілювати Java-код, і додає можливість запускати застосунок як програму. Не сприймайте це як магію — сприймайте як «увімкнули режим Java-проєкту».

Тепер додамо репозиторій. Навіть якщо ми поки не підключаємо зовнішні бібліотеки, репозиторій — стандартна частина каркаса: згодом Gradle завантажуватиме залежності саме звідти. Ми використовуємо mavenCentral() — це найбазовіший варіант, і для всього курсу його достатньо.

repositories {
    // Основний репозиторій залежностей для курсу
    mavenCentral()
}

Далі йде дуже важлива частина саме для нашого навчального baseline: фіксуємо Java 25 через toolchain. Це допомагає тримати проєкт в одному «мовному коридорі» й зменшує кількість сюрпризів, якщо в когось локально стоїть інша версія JDK.

java {
    toolchain {
        // Фіксуємо версію Java для збирання, незалежно від локальної JDK
        languageVersion = JavaLanguageVersion.of(25)
    }
}

І, нарешті, «клей», який пов’язує Gradle-запуск із вашим стартовим класом. Ми заздалегідь домовимося, що точка входу застосунку називається ReadLaterApplication і лежить у пакеті com.example.readlater.

application {
    // Повне ім’я класу з `public static void main(...)`
    mainClass = "com.example.readlater.ReadLaterApplication"
}

Якщо зібрати все разом, вийде короткий і читабельний build.gradle.kts. Я покажу його цілком, але майте на увазі: це не «єдино правильна» версія, а мінімально достатній каркас для курсу.

plugins {
    // Компілюємо Java-код
    java
    // Додаємо задачу `run` для запуску застосунку
    application
}

repositories {
    // Звідси Gradle буде завантажувати залежності
    mavenCentral()
}

java {
    toolchain {
        // Використовуємо Java 25 в усіх середовищах
        languageVersion = JavaLanguageVersion.of(25)
    }
}

application {
    // Точка входу застосунку
    mainClass = "com.example.readlater.ReadLaterApplication"
}

Зараз найкорисніша вправа — не «запам’ятати», а навчитися розпізнавати очима ці блоки. Бачите plugins — значить, «увімкнули поведінку». Бачите repositories — значить, «знаємо, звідки завантажувати бібліотеки». Бачите java.toolchain — значить, «ми в Java 25». Бачите application.mainClass — значить, «у застосунку є зрозуміла точка входу».

Щоб зв’язати все це в одну картинку, можна уявити, що Gradle під час запуску робить приблизно такий маршрут:

flowchart TD
    A["./gradlew ..."] --> B["settings.gradle.kts
імʼя збирання"] A --> C["build.gradle.kts
правила збирання"] C --> D["src/main/java
компіляція Java"] C --> E["src/main/resources
ресурси на classpath"] C --> F["application.mainClass
запуск застосунку"]

І так, це виглядає як «занадто багато кроків заради Hello World». Але backend-життя таке: краще мати передбачувані правила, ніж магію й несподіванки.

6. src/main/java: код застосунку

Папка src/main/java — стандартне місце для основного коду застосунку. І важливе слово тут — «стандартне»: Gradle за замовчуванням очікує код саме там. Якщо ви покладете ReadLaterApplication.java у корінь проєкту або в src/java, ви не «переможете систему», а просто купите собі набір дивних помилок на рівному місці.

У межах курсу ми відразу дисциплінуємо себе: код — у src/main/java, а структура папок усередині відображає структуру пакетів. Це просте правило економить величезну кількість часу, тому що IDE, Gradle й ви самі починають думати однаково.

Поки що нам не потрібен складний набір пакетів — ми лише стартуємо. Тому на поточному рівні достатньо одного базового пакета com.example.readlater і пари класів. Згодом проєкт розростеться, але старт має бути простим і впевненим.

7. Пакет com.example.readlater: package і папки

Пакети в Java — це не декоративний рядок, який пишуть «тому що так прийнято». Пакет — це адреса вашого класу всередині проєкту. І адреса має бути узгоджена: якщо клас оголошує package com.example.readlater;, то файл має лежати в папці com/example/readlater.

Створіть папки:

src/main/java/com/example/readlater

І далі кладіть туди класи. Чому ми використовуємо com.example, а не ваш реальний домен? Тому що це навчальний проєкт. У реальному продукті ви б використовували домен компанії в зворотному порядку. Зараз нам важливіше стабільно виробити звичку, ніж сперечатися про «ідеальний неймінг» (спойлер: за рік усе одно перейменовуватимете).

8. ReadLaterApplication: точка входу й банер

У проєкту має бути одна очевидна стартова точка. У нашому курсі це ReadLaterApplication. Зараз це буде простий клас із main, який друкує повідомлення «я живий» і викликає невеликий банер. Жодної бізнес-логіки й жодних «архітектурних» рішень. Нам потрібно лише довести, що структура коректна і що проєкт — це саме проєкт, а не один файл.

Створіть файл src/main/java/com/example/readlater/ReadLaterApplication.java:

package com.example.readlater;

public class ReadLaterApplication {
    public static void main(String[] args) {
        // Друкуємо банер — простий маркер, що застосунок запустився
        ConsoleBanner.print();

        // Основне повідомлення запуску (поки без логування)
        System.out.println("ReadLater Starter працює"); // ReadLater Starter працює
    }
}

Тепер додамо другий клас, щоб одразу відчути: проєкт — це не один файл, і це нормально. Створіть src/main/java/com/example/readlater/ConsoleBanner.java:

package com.example.readlater;

public final class ConsoleBanner {
    private ConsoleBanner() {
        // Забороняємо створювати екземпляри: це утилітний клас
    }

    public static void print() {
        // Банер у консоль — щоб старт було помітно очима
        System.out.println("=== ReadLater Starter ==="); // === ReadLater Starter ===
    }
}

Зверніть увагу на маленьку інженерну деталь: ConsoleBanner зроблений final і з приватним конструктором. Це не «обов’язкове правило», а просто чесний спосіб показати намір: перед нами утилітний клас, екземпляри якого нам не потрібні. Так, можна було й не ускладнювати. Але краще звикати до акуратності там, де це не збільшує когнітивне навантаження.

І ще один момент: зараз ми використовуємо System.out.println() спеціально як видимий маркер запуску. Згодом, коли перейдемо до логування, ви побачите доросліший підхід. А поки нам потрібно, щоб застосунок подавав сигнал і це було видно очима.

9. src/main/resources: конфіги й ресурси

Папка src/main/resources часто сприймається як «якась загадкова річ, яку створює IDE». Насправді це дуже практична частина проєкту: сюди кладуть файли, які мають потрапити до збирання й бути доступними застосунку як ресурси. Конфігурація, шаблони, зразковий JSON для mock-режимів, logback.xml — усе це зазвичай живе саме тут.

Сьогодні ми не будемо читати ресурси з Java-коду й не будемо будувати конфігураційну систему — це буде значно пізніше. Але саму папку створюємо відразу, тому що вона частина каркаса. Навіть порожня папка працює як якір: ви заздалегідь знаєте, куди класти не-Java файли, і не розводите хаос із config/, resources2/, new_config_final/.

Створіть файл src/main/resources/application.properties з мінімальним вмістом-заглушкою:

# Ім’я застосунку (поки просто заглушка для структури ресурсів)
app.name=readlater-starter

Зараз цей файл ніяк не впливає на виконання застосунку, і це нормально. Ми робимо його не заради ефекту «прямо зараз», а заради дисципліни структури. У реальних проєктах конфігурація майже ніколи не живе в Java-коді, і чим раніше ви звикнете до окремого місця для неї, тим спокійніше піде подальший курс.

10. README.md: команди збирання й запуску

README для новачка часто виглядає як «ну, файл із текстом, можна потім». Але саме README робить ваш проєкт дружнім і для іншої людини, і для вас самих через місяць. Причому дружність тут вимірюється дуже просто: якщо я клонував репозиторій, відкрив README й одразу зрозумів, що вводити в термінал, — отже, проєкт зі мною розмовляє.

Сьогодні нам потрібен мінімум: назва, вимоги й команди збирання та запуску, записані прямо в репозиторії. Ми відразу зафіксуємо варіант для macOS/Linux і Windows, щоб проєкт не виглядав так, ніби його можна оживити лише з однієї конкретної оболонки.

Створіть README.md у корені:

# ReadLater Starter

Навчальний проєкт курсу `Java Server`.

## Вимоги
- JDK 25

## Збирання й запуск (macOS / Linux)
./gradlew build
./gradlew run

## Збирання й запуск (Windows)
gradlew.bat build
gradlew.bat run

Це виглядає просто, але вже дає величезну різницю порівняно з README з одного рядка «Відкрийте в IDE й натисніть Run». Такий README чесно прив’язує запуск до проєкту, а не до персональних звичок.

11. Типові помилки під час збирання каркаса проєкту

Помилка №1: Java-клас лежить «поруч із build.gradle.kts», а не в src/main/java.
Таке часто трапляється, коли ви створюєте файл «швидко, щоб перевірити ідею». Потім Gradle не знаходить вихідники, IDE починає вдавати, що все розуміє, а запуск через CLI розвалюється. Лікується однією звичкою: код завжди живе в src/main/java, без винятків.

Помилка №2: папка й пакет не збігаються.
Наприклад, файл лежить у src/main/java/com/example/readlater/ReadLaterApplication.java, а всередині написано package com.example.app;. IDE може це підсвітити, але якщо ви не звикли дивитися уважно, помилку легко пропустити. Далі виникають дивні «Class not found» під час запуску. Дисципліна проста: шлях папки має повторювати package.

Помилка №3: плутанина між settings.gradle.kts і build.gradle.kts.
Початківці іноді намагаються писати plugins { ... } у settings.gradle.kts або задавати rootProject.name у build.gradle.kts. Технічно є сценарії, де це можливо, але на старті це лише плутає. Запам’ятайте просту модель: ім’я проєкту — у settings, правила збирання — у build.

Помилка №4: неправильний рядок mainClass — друкарська помилка або не той пакет.
Якщо в build.gradle.kts стоїть mainClass = "com.example.ReadLaterApplication", а реальний клас — com.example.readlater.ReadLaterApplication, Gradle не зможе запустити застосунок. Ця помилка неприємна тим, що виглядає як «Gradle зламаний», хоча насправді помилився один рядок. Перевіряйте package у файлі й рядок mainClass як пару.

Помилка №5: створення «зайвих кишень» для ресурсів.
Іноді з’являються папки на кшталт resources/ у корені або src/resources. Потім туди кладуть конфіги, потім ще кудись — і за тиждень уже ніхто не пам’ятає, де що лежить. На старті найдешевша дисципліна — одразу створювати src/main/resources і класти не-Java файли туди, навіть якщо поки вони не використовуються.

1
Задача
Java Server, 2 рівень, 2 лекція
Недоступна
Базовий каркас проєкту з однією точкою входу
Базовий каркас проєкту з однією точкою входу
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ