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 файлы: конфиги, шаблоны, sample 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 is running"); // ReadLater Starter is running
    }
}

Теперь добавим второй класс, чтобы сразу почувствовать: проект — это не один файл, и это нормально. Создайте 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». На самом деле это очень практичная часть проекта: сюда кладут файлы, которые должны попасть в сборку и быть доступны приложению как ресурсы. Конфигурация, шаблоны, sample 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`.

## Requirements
- JDK 25

## Build & Run (macOS / Linux)
./gradlew build
./gradlew run

## Build & 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 лекция
Недоступна
Базовый каркас проекта с одной точкой входа
Базовый каркас проекта с одной точкой входа
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ