Библиотека Java разработчика
10.5K subscribers
1.17K photos
594 videos
58 files
1.5K links
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate.


По всем вопросам @evgenycarter

РКН clck.ru/3KoGeP
Download Telegram
⌨️ Открытый урок «Spring AI: от изображения к данным. Практика распознавания документов».

🗓 15 января в 20:00 МСК

🆓 Бесплатно. Урок в рамках старта курса «Разработчик на Spring Framework».

На вебинаре:
✔️ Введение в Spring AI для обработки документов.
✔️ Настройка проекта: зависимости и конфигурация модели.
✔️ Ключевые концепции: работа с изображениями, системные промпты, OutputParser.
✔️ Сервисный слой: оркестрация шагов AI-пайплайна.
✔️ REST API для загрузки/анализа, обработка ошибок и масштабирование.

Кому будет интересно:
Java-разработчикам на Spring, backend-инженерам, архитекторам и тимлидам, которым нужно встроить распознавание документов в сервисы.

Результаты после вебинара:
Соберете простой пайплайн: загрузка изображения → извлечение текста → JSON. Поймете, где в Spring AI применять промпты и OutputParser.

🔗 Ссылка на регистрацию: https://vk.cc/cTkeIQ

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
💿 Java Records: Убийцы бойлерплейта

Сколько раз вы создавали класс просто чтобы "перенести данные" из точки А в точку Б?
Вы пишете 3 поля, а потом IDE генерирует вам 50 строк кода: конструктор, геттеры, equals, hashCode, toString... 🤯

В Java 16+ этому положили конец. Встречайте Records.

📉 Было vs Стало

Допустим, нам нужен простой DTO для пользователя.

Классический POJO (Java 1.0 - 15):


public class User {
private final String name;
private final int age;

public User(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() { return name; }
public int getAge() { return age; }

// + equals()
// + hashCode()
// + toString() ... еще 30 строк кода
}



Record (Java 16+):


public record User(String name, int age) {}



Всё. Это одна строка. 🔥

⚙️ Что происходит под капотом?

Компилятор делает всю грязную работу за вас. Создавая record, вы автоматически получаете:

1. Приватные финальные поля (private final).
2. Конструктор со всеми аргументами.
3. Геттеры (без префикса get! Просто .name(), .age()).
4. equals() и hashCode() (идеально для ключей в Map или Set).
5. toString() (красивый вывод: User[name=Alex, age=25]).

🛠 Кастомизация (Compact Constructor)

"А что, если мне нужна валидация? Нельзя же создать юзера с отрицательным возрастом!"
Для этого есть Компактный конструктор. Вам даже не нужно перечислять аргументы:


public record User(String name, int age) {
// Компактный конструктор
public User {
if (age < 0) {
throw new IllegalArgumentException("Возраст не может быть меньше 0");
}
// Присваивание this.age = age происходит автоматически!
}
}



⚠️ Ограничения (Важно знать)

Records, это не замена обычным классам во всем.

1. Они неизменяемы (Immutable). Сеттеров нет и не будет. Хотите поменять поле? Создавайте новый объект.
2. Нет наследования. Record не может наследовать (extends) другой класс (потому что он уже наследует java.lang.Record). Но имплементировать интерфейсы (implements) можно!

💡 Когда использовать?

🔴DTO (Data Transfer Objects): Ответы от API, запросы в БД.
🔴Ключи для Map: Благодаря гарантированному equals/hashCode.
🔴Внутри методов: Можно объявлять локальные рекорды прямо внутри метода, чтобы временно сгруппировать данные.

Records делают код чище и безопаснее. Они идеально сочетаются со Stream API, где данные постоянно передаются и преобразуются.
Если ваш класс это просто "мешок с данными", превращайте его в record.

#Java #Records #NewJava #CleanCode

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍63
🔀 Switch Expressions: Прощай, break!

Помните это чувство, когда забыл написать break в switch-case, и код пошел выполняться дальше, создав неуловимый баг? 😫
В современных версиях Java (стандарт с Java 14) оператор switch прокачали. Теперь это не просто управляющая конструкция, а выражение, возвращающее результат.

💀 Было (Statement)

Громоздко, опасно (fall-through), переменная вынесена наружу.


DayOfWeek day = DayOfWeek.SATURDAY;
int numLetters;

switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break; // Забыл break? Получи баг!
case TUESDAY:
numLetters = 7;
break;
default:
throw new IllegalStateException("Wat: " + day);
}



Стало (Expression)

Лаконично, безопасно, функционально.


int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
default -> throw new IllegalStateException("Wat: " + day);
};



🚀 Главные фишки

1. Стрелочный синтаксис (->)
Если используется стрелка, переход к следующему кейсу (fall-through) отключен по умолчанию. Никаких break больше писать не надо!
2. Возврат значения
switch теперь работает как формула. Вы можете сразу присвоить результат переменной или вернуть его из метода (return switch(...)).
3. Несколько условий в одну строку
case MONDAY, FRIDAY, SUNDAY — просто перечисляем через запятую.

🛑 Сложная логика и yield

Что делать, если в одном case нужно не просто вернуть число, а выполнить несколько строк кода (например, залоггировать)?
Для этого появились фигурные скобки и ключевое слово yield.

Важно: return использовать нельзя, так как он прервет выполнение всего метода, а не только свича.


String result = switch (day) {
case SATURDAY, SUNDAY -> "Выходной";
case MONDAY -> {
System.out.println("Тяжелый день...");
yield "Будни"; // yield возвращает значение из switch
}
default -> "Будни";
};



Exhaustiveness (Полнота)

Если вы делаете switch по Enum, компилятор проверит, все ли варианты вы обработали. Если добавите в Enum новый день, а в свич - нет, код просто не скомпилируется. Это отличная защита от забывчивости!

🔥 Итог

Новый switch это чистый кайф. Он делает код компактнее и убирает целый класс ошибок, связанных с пропущенными break.

🔴Используйте ->, когда нужно просто сопоставить значение.
🔴Используйте yield, если нужна логика внутри блока.

#Java #SwitchExpression #CleanCode #NewJava

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍114😁1
🧑‍💻Пишете на Vue и давно работаете с Vue Router по привычке? Сейчас в экосистеме появляется новая опция — Kitbag Router. Лёгкий повод пересобрать подход к роутингу и обновить стек.

На открытом уроке разберём, как подключить его к проекту, настроить под свой стек и чем он принципиально отличается от Vue Router. Пошагово пройдём путь от установки до рабочих маршрутов в SPA.

Вы познакомитесь с новой библиотекой роутинга для VueJS, научитесь создавать приложения с клиентским роутингом на Kitbag Router, сравнивать его с Vue Router и осознанно выбирать инструмент под задачу.

📆Встречаемся 21 января в 20:00 МСК в преддверие старта курса «Vue.js разработчик». Регистрация открыта: https://vk.cc/cTo0LX

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🔮 Pattern Matching в Switch: Типизируй это!

Помните этот бесконечный кошмар, когда вам приходит Object, и нужно понять, что внутри?
Раньше мы писали "лестницу" из if-else и instanceof с кучей ручного кастинга (приведения типов).

Было (Боль и слезы):


Object obj = getUnknownObject();

if (obj instanceof String) {
String s = (String) obj; // Ручной каст
System.out.println("Строка: " + s.length());
} else if (obj instanceof Integer) {
Integer i = (Integer) obj; // Опять каст
System.out.println("Число: " + i);
} else if (obj instanceof Long) {
// ... и так до бесконечности
}



Стало (Java 21 LTS):
Теперь switch умеет проверять типы! Больше никаких instanceof и ручных приведений. Переменная создается прямо в кейсе.


switch (obj) {
case String s -> System.out.println("Строка: " + s.length());
case Integer i -> System.out.println("Число: " + i);
case Long l -> System.out.println("Длинное число: " + l);
default -> System.out.println("Непонятно что");
}



🛡 Guarded Patterns (Охрана в кейсах)

Но это еще не всё. Часто бывает, что тип нам подходит, но нужно проверить еще и значение.
Раньше пришлось бы ставить if внутри case. Теперь у нас есть ключевое слово when.


switch (obj) {
// Попадет сюда, ТОЛЬКО если это строка И она длиннее 10 символов
case String s when s.length() > 10 ->
System.out.println("Длинная строка: " + s);

// Любая другая строка
case String s ->
System.out.println("Короткая строка: " + s);

case Integer i ->
System.out.println("Число: " + i);

default -> {}
}



👻 А как же Null?

В старом switch, если передать null, мы мгновенно получали NullPointerException.
В новом switch можно (и нужно!) обрабатывать null легально:


switch (obj) {
case String s -> System.out.println("Это строка");
case null -> System.out.println("Пришел null!"); // Никакого NPE
default -> System.out.println("Что-то другое");
}




Это не просто "сахар". Это изменение подхода к полиморфизму.
Если раньше логика часто размазывалась по методам классов (animal.makeSound()), то теперь можно собирать логику обработки разных типов в одном месте, что часто бывает удобнее при написании бизнес-логики (например, обработка разных типов ивентов или DTO).

🔥 Итог

🔴Switch теперь принимает любые объекты.
🔴Кастинг происходит автоматически (case String s).
🔴Можно уточнять условия через when.
🔴Можно безопасно ловить null.

#PatternMatching #NewJava #CleanCode

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🎯 Открытый урок «Сетевой чат на C#».

🗓 22 января в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «C# Developer».

На вебинаре:
✔️ Рассмотрим написание сетевого приложения на C#.
✔️ Мы реализуем простые клиент и сервер с помощью одного из сетевых протоколов.
✔️Также затронем темы многопточности и асинхронности

Кому будет полезно:
- Вебинар будет полезен начинающим разработчикам, желающим разобраться в сетевом и многопочном\асинхронном программировании.

Что вы получите:
- По итогам вебинара смогут проектировать сетевые приложения.
- Получат представление о работе сетевых протоколов, и многопоточности\асинхронности в приложениях.
- На практике попробуют разработать такое приложение.

🔗 Ссылка на регистрацию: https://vk.cc/cTqyyY

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
🔒 Sealed Classes: Архитектурный фейсконтроль

В ООП всегда была проблема с наследованием. Либо ваш класс открыт для всех («Наследуйся кто хочет!»), либо он закрыт наглухо (final).
Но что, если я хочу, чтобы мой класс Shape (Фигура) могли наследовать только Circle и Square, и больше никто?

Раньше это решалось костылями (пакетная видимость, скрытые конструкторы). В Java 17 появился официальный механизм: Sealed Classes.

🚧 Как это работает?

Вы помечаете класс (или интерфейс) ключевым словом sealed и после слова permits перечисляете тех, кому "можно".


// Родитель: Разрешает наследование ТОЛЬКО этим двум классам
public sealed interface Payment
permits CreditCard, Cash {
}



Теперь, если Вася из соседнего отдела попытается написать class Crypto extends Payment, компилятор ударит его по рукам. 🚫

🚦 Правило трех дорог

Наследники запечатанного класса обязаны выбрать свою судьбу. Они должны иметь один из трех модификаторов:

1. final - Цепочка наследования обрывается. Дальше наследовать нельзя.

public final class Cash implements Payment { ... }




2. sealed - Иерархия продолжается, но снова под контролем.

public sealed class CreditCard implements Payment permits Visa, MasterCard { ... }




3. non-sealed - "Открываем шлюзы". Дальше от этого класса может наследоваться кто угодно (возврат к старому поведению Java).

public non-sealed class DebitCard implements Payment { ... }





🧩 Главная фишка: Комбо со Switch

Зачем это нужно, кроме запретов? Ради безопасности.
Когда вы используете sealed иерархию в новом switch, компилятор знает все возможные варианты.

Вам больше не нужно писать ветку default!


// Метод обработки платежа
String process(Payment p) {
return switch (p) {
case CreditCard c -> "Processing card: " + c.getNumber();
case Cash c -> "Processing cash amount: " + c.getAmount();
// default НЕ НУЖЕН! Компилятор знает, что третьго не дано.
};
}



Если завтра вы добавите в permits новый класс Crypto, код перестанет компилироваться, пока вы не обработаете этот новый кейс в свитче.
Это спасает от багов, когда в бизнес-логику добавили новый тип, а обработчики обновить забыли.

🔥 Итог

Sealed Classes + Records + Switch Pattern Matching = 💎
Это "Святая Троица" современной Java. Используйте запечатанные классы для моделирования доменной области, где количество вариантов конечно и известно заранее (статусы заказа, типы платежей, виды пользователей).

#Java17 #SealedClasses #Architecture #CleanCode

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥81
🧵 Виртуальные потоки: Революция производительности

Представьте, что вы строите высоконагруженный сервер. Раньше у вас было два пути:

1. Классика (Thread): Простой код, но один поток весит ~2 Мб памяти. Создадите 5,000 потоков - сервер упадет с OutOfMemoryError.
2. Асинхронность (WebFlux/Netty): Сервер держит 100k соединений, но код превращается в лапшу из callbacks и CompletableFuture, которую невозможно отлаживать.

В Java 21 появились Виртуальные потоки. Они объединяют простоту первого подхода и производительность второго.

🪶 В чем магия?

Классический поток Java (Platform Thread) привязан 1-к-1 к потоку операционной системы (OS Thread). Это дорогой ресурс.

Виртуальный поток, это просто объект в куче (heap) JVM. Он не привязан к ОС намертво.

🔴Вес: Несколько килобайт (вместо мегабайт).
🔴Количество: Можно создать миллион виртуальных потоков на обычном ноутбуке.

⚙️ Как это работает (Carrier Threads)

Под капотом работает схема Mount/Unmount:

1. JVM запускает небольшой пул обычных потоков ОС (называются Carrier Threads, обычно их число = числу ядер CPU).
2. Ваш виртуальный поток "садится верхом" на Carrier-поток и выполняет код.
3. ⚠️ Самое важное: Как только ваш код блокируется (ждет ответа от БД, читает файл, делает Thread.sleep), JVM снимает виртуальный поток с ядра.
4. Поток ОС освобождается и тут же берет в работу другой виртуальный поток.

Итог: Ядра процессора молотят на 100%, никогда не простаивая в ожидании ввода-вывода.

💻 Код: Найди 1 отличие

API практически не изменился. Вам не нужно учить новые фреймворки.


// Старый способ (Тяжелый поток ОС)
Thread.ofPlatform().start(() -> {
System.out.println("Я ем много памяти!");
});

// Новый способ (Легкий виртуальный поток)
Thread.ofVirtual().start(() -> {
System.out.println("Я ничего не вешу!");
});

// Использование с ExecutorService (для старого кода)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 1_000_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(1000); // Блокировка теперь БЕСПЛАТНАЯ
return i;
});
});
}
// Этот код запустит миллион задач за секунду, не положив сервер.



⚰️ Конец Reactive Programming?

Многие эксперты говорят: Да.
Смысл использования сложных реактивных библиотек (RxJava, Reactor) был в том, чтобы не блокировать потоки. Виртуальные потоки делают блокировку дешевой.
Теперь вы можете писать простой, последовательный код:
var user = db.findUser();
var data = http.sendRequest(user);
...и он будет работать так же эффективно, как сложный асинхронный код.

⚠️ Когда НЕ использовать?

Виртуальные потоки идеальны для I/O задач (ждать сеть, ждать диск).
Они бесполезны для CPU-Intensive задач (майнинг, шифрование, обработка видео). Если поток не ждет, а считает, он занимает поток ОС, и виртуалка тут не поможет.

🔥 Итог
Project Loom вернул нам девиз: "Один запрос - Один поток".
Больше никаких пулов потоков с ограниченным размером. Просто создавайте новый виртуальный поток для каждой задачи.

#Java #Loom #VirtualThreads #Concurrency #HighLoad

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥113
🍃 Spring Boot: Магия или Логика? (IoC & Beans)

Когда вы запускаете Spring-приложение, происходит магия: все нужные объекты создаются сами, базы данных подключаются, сервер стартует.
Но за этой магией стоит четкий механизм - IoC Container (Inversion of Control / Инверсия управления).

📦 Что такое Application Context?

Представьте Spring как огромный завод.

🔴Context (Контейнер) - это сам завод. Он управляет жизненным циклом объектов.
🔴Bean (Бин) - это любая деталь (объект), которую этот завод создал и хранит у себя на складе.

Суть IoC:

🔴Обычный подход: Вы сами управляете объектами (Service s = new Service()). Вы - главный.
🔴Spring подход: Вы отдаете управление фреймворку. "Спринг, создай мне сервис и дай его, когда он понадобится". Spring - главный.

🏷 Как сделать Бин? (Аннотации)

Чтобы Spring узнал про ваши классы, их нужно пометить.

1. @Component — Самая базовая аннотация. "Эй, Спринг, это бин, управляй им!".
2. @Service - Тот же @Component, но семантически говорит: "Здесь бизнес-логика".
3. @Repository - Тот же @Component, но для работы с БД (ловит специфичные ошибки баз данных).
4. @Controller / @RestController - Для обработки HTTP-запросов.
5. @Configuration + @Bean - Используется, когда нужно создать бин из чужого класса (библиотеки), код которого вы не можете пометить аннотацией @Component.

💉 Dependency Injection (DI)

Главная фишка. Как один бин попадает внутрь другого?
Например, UserService нуждается в UserRepository.

Способ 1: Через поле (Field Injection)


@Service
public class UserService {
@Autowired // ⚠️ Не рекомендуется!
private UserRepository repository;
}



Почему плохо: Невозможно протестировать (как подсунуть мок?), скрытые зависимости, возможен NullPointerException.

Способ 2: Через конструктор (Constructor Injection)
Золотой стандарт современного Spring.


@Service
public class UserService {
private final UserRepository repository;

// @Autowired здесь не обязателен (в новых версиях Spring)
public UserService(UserRepository repository) {
this.repository = repository;
}
}



Плюсы: Поле final (неизменяемое), легко тестировать (можно передать любой репозиторий в конструктор), сразу видно все зависимости класса.

Лайфхак: Lombok

Чтобы не писать конструктор руками, используйте Lombok:


@Service
@RequiredArgsConstructor // Генерирует конструктор для final полей
public class UserService {
private final UserRepository repository; // Всё внедрится само!
}



🔥 Итог

Spring, это просто "мешок с объектами" (Context), которые он создает сам и связывает друг с другом (DI).

🔴Забудьте про new Service().
🔴Используйте внедрение через конструктор.
🔴Помечайте классы правильными аннотациями (@Service, @Repository).

#SpringBoot #Java #IoC #DI #SpringTips

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍2🤡2
⌨️ Открытый урок «Неожиданное введение в Spring Context».

🗓 22 января в 20:00 МСК

🆓 Бесплатно. Урок в рамках старта курса «Разработчик на Spring Framework».

На очередном открытом уроке курса "Разработчик на Spring Framework", мы на примере своего приложения попробуем реализовать свой IoC-контейнер, которой отдаленно будет напоминать Spring Context

Кому будет интересно:
Начинающим Java-бэкенд-разработчикам.

Результаты после вебинара:
Поймете общую идею IoC/Spring IoC.

🔗 Ссылка на регистрацию: https://vk.cc/cTwZTO

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
2👍1
🧙‍♂️ Spring Boot: Магия под капотом (Starters & AutoConfig)

Вы когда-нибудь задумывались: почему вы просто добавляете одну строчку в pom.xml, пишете main метод, и у вас волшебным образом поднимается Tomcat, настраивается JSON-конвертер и подключается логирование?

За этим стоят два кита Spring Boot: Starters и AutoConfiguration.

1️⃣ Starters (Стартеры) - "Всё включено"

В старом Spring, чтобы сделать веб-приложение, нужно было вручную найти версии для Spring MVC, Tomcat, Jackson, Validation API... и молиться, чтобы они были совместимы.

Starter — это готовый набор зависимостей (dependencies), собранный в один пакет. Это как "Комбо-обед" в ресторане.

🔴Хотите Веб? Добавляете spring-boot-starter-web.
* Внутри: Tomcat + Spring MVC + Jackson + Logback.


🔴Хотите Тесты? Добавляете spring-boot-starter-test.
*Внутри: JUnit + Mockito + AssertJ + Hamcrest.



Вам больше не нужно думать о версиях библиотек. Spring Boot следит за "BOM" (Bill of Materials) и гарантирует, что все версии внутри стартера дружат друг с другом.

2️⃣ AutoConfiguration - "Умный детектив"

Это мозг фреймворка. Когда приложение запускается, Spring Boot начинает сканировать ваш classpath (все подключенные библиотеки jar).

Он рассуждает примерно так:

1. "Так, я вижу, что в зависимостях есть класс H2Driver?" "Значит, программист хочет базу данных. Создам-ка я ему бин DataSource с настройками для H2!"
2. "Я вижу классы Tomcat и Spring MVC?" "Значит, нужно поднять встроенный веб-сервер на порту 8080 и настроить DispatcherServlet."
3. "О, программист сам создал свой бин DataSource?" "Окей, тогда я отступаю и свою автоконфигурацию не применяю."

Вся эта логика держится на аннотациях @Conditional...:

🔴@ConditionalOnClass: Создать бин, если найден класс X.
🔴@ConditionalOnMissingBean: Создать бин, ТОЛЬКО если программист не создал такой же сам.

⚙️ Главная кнопка: @SpringBootApplication

Вы вешаете эту аннотацию над main классом. На самом деле это "матрешка", внутри которой спрятаны 3 другие аннотации:


@SpringBootConfiguration // Говорит: "Это конфигурационный класс"
@EnableAutoConfiguration // Говорит: "ВКЛЮЧИ МАГИЮ!" (запусти сканирование classpath)
@ComponentScan // Говорит: "Ищи пользовательские бины в этом пакете"
public @interface SpringBootApplication { ... }



🕵️‍♂️ Pro-Tip: Как увидеть магию?

Иногда автоконфигурация мешает, или вы не понимаете, почему Spring решил подключить ту или иную базу.
Добавьте в application.properties одну строчку:


debug=true



При запуске в консоль вывалится Condition Evaluation Report. Там будет честно написано:

🔴 Positive Matches: Что Spring настроил сам (и почему).
🔴 Negative Matches: Что Spring проигнорировал (потому что не нашел нужных классов или вы перекрыли это своим бином).

🔥 Итог

🔴Starters экономят время на подбор зависимостей.
🔴AutoConfiguration экономит время на написание рутинных конфигов.
🔴Spring Boot работает по принципу Convention over Configuration (Соглашение важнее конфигурации): "Я дам тебе лучшие настройки по умолчанию, но ты всегда можешь их изменить".

#SpringBoot #Java #Starters #AutoConfig

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🎮 Анатомия REST Controller: Входящие и Исходящие

Раньше, чтобы вернуть JSON, нужно было танцевать с бубном. В Spring Boot это делается "из коробки" благодаря библиотеке Jackson, которая тихо работает в фоне.

1️⃣ @RestController vs @Controller

Это первый вопрос на собеседовании.

🔴@Controller: Олдскул. Используется, когда мы возвращаем HTML-страницы (Thymeleaf, JSP). Чтобы вернуть JSON, нужно над каждым методом вешать @ResponseBody.
🔴@RestController: Современный стандарт для REST API.
🔴Это просто @Controller + @ResponseBody над всеми методами.
🔴Всё, что возвращает метод, автоматически превращается в JSON.



2️⃣ Принимаем данные (3 главных способа)

Как вытащить информацию из запроса?

А. Из пути URL (@PathVariable)
Используем, когда параметр - это часть адреса ресурса.

🔴URL: GET /users/42
🔴Код:

@GetMapping("/users/{id}")
public User getById(@PathVariable Long id) { ... }





Б. Из параметров запроса (@RequestParam)
Используем для фильтрации, сортировки или опциональных параметров.

URL: GET /users?role=ADMIN&age=25
Код:

@GetMapping("/users")
public List<User> search(
@RequestParam String role,
@RequestParam(required = false) Integer age // Опционально
) { ... }





В. Из тела запроса (@RequestBody)
Используем для отправки сложных объектов (обычно в POST/PUT запросах). Spring возьмет JSON и сам превратит его в Java-объект (DTO).

JSON: { "name": "Alex", "email": "[email protected]" }
Код:

@PostMapping("/users")
public User create(@RequestBody UserDto userDto) { ... }





3️⃣ Управляем ответом (ResponseEntity)

Просто вернуть объект User, это хорошо (статус будет 200 OK). Но что, если мы хотим вернуть 404 (Not Found) или 201 (Created)?

Для этого используем обертку ResponseEntity<T>.

💻 Пример: Идеальный контроллер


@RestController
@RequestMapping("/api/v1/users") // Общий префикс для всех методов
public class UserController {

private final UserService service; // Внедряем через конструктор

public UserController(UserService service) {
this.service = service;
}

// 1. Получить всех (GET 200 OK)
@GetMapping
public List<User> getAll() {
return service.findAll();
}

// 2. Найти одного (с управлением статусом)
@GetMapping("/{id}")
public ResponseEntity<User> getOne(@PathVariable Long id) {
return service.findById(id)
.map(user -> ResponseEntity.ok(user)) // 200 OK
.orElse(ResponseEntity.notFound().build()); // 404 Not Found
}

// 3. Создать (POST 201 Created)
@PostMapping
public ResponseEntity<User> create(@RequestBody UserDto dto) {
User created = service.save(dto);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
}



Jackson Magic (Pro-Tip)

Иногда вам не нужно отдавать все поля объекта (например, пароль).
Не пишите код для скрытия! Используйте аннотации Jackson прямо в DTO:

@JsonIgnore - поле не попадет в JSON.
@JsonProperty("full_name") - поле fullName в Java станет full_name в JSON.

🔥 Итог

• Используйте @RestController для API.
@PathVariable - для ID (/users/1).
@RequestParam - для фильтров (/users?sort=name).
@RequestBody - для больших данных (JSON).
• Возвращайте ResponseEntity, чтобы контролировать HTTP-статусы.

#SpringBoot #REST #Controller #API #Java


📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍61
🔴 Завтра тестовое собеседование с Java-разработчиком

21 января(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.

Как это будет:
📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Сергею

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.

Переходи в нашего бота, чтобы получить ссылку на эфир →
@shortcut_sh_bot

Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
💾 Spring Data JPA: SQL больше не нужен?

Spring Data JPA это абстракция над Hibernate (который, в свою очередь, является реализацией JPA).
Его главная киллер-фича: Генерация запросов из названий методов.

🏗 1. Сущность (@Entity)

Сначала мы объясняем Java, как выглядит наша таблица. Обычный класс превращается в таблицу с помощью пары аннотаций.


@Entity // Это таблица в БД
@Table(name = "users")
public class User {
@Id // Это Primary Key
@GeneratedValue(strategy = GenerationType.IDENTITY) // Авто-инкремент
private Long id;

private String email;
private int age;
private boolean active;

// Геттеры, сеттеры...
}



🪄 2. Репозиторий (Магия)

Вместо написания класса UserDao, мы просто создаем интерфейс.


public interface UserRepository extends JpaRepository<User, Long> {
// Здесь пусто! Но методы уже есть.
}



Наследуясь от JpaRepository, вы сразу получаете готовые методы:

🔴.save(user) - сохранить/обновить.
🔴.findById(id) - найти по ID (возвращает Optional).
🔴.findAll() - найти всех.
🔴.deleteById(id) - удалить.

Ни одной строчки SQL писать не пришлось! 😎

🔮 3. Derived Queries (Запросы из имени)

Что, если нужно найти пользователя по email? Или всех активных пользователей старше 18 лет?
Вы просто пишете метод в интерфейсе с правильным названием, и Spring сам составляет SQL-запрос.


public interface UserRepository extends JpaRepository<User, Long> {

// SQL: SELECT * FROM users WHERE email = ?
Optional<User> findByEmail(String email);

// SQL: SELECT * FROM users WHERE active = true AND age > ?
List<User> findByActiveTrueAndAgeGreaterThan(int age);

// SQL: EXISTS (SELECT 1 FROM users WHERE email = ?)
boolean existsByEmail(String email);
}



Синтаксис простой: find + By + ИмяПоля + Условие (если нужно).

🛠 4. Если магия не справилась (@Query)

Иногда названия методов становятся слишком длинными и уродливыми (findByNameAndAgeAndActiveAnd...). Или нужен сложный JOIN.
Тогда мы берем управление в свои руки и пишем запрос на JPQL (Java Persistence Query Language) - это SQL, но оперирующий классами, а не таблицами.


@Query("SELECT u FROM User u WHERE u.email LIKE %:domain%")
List<User> findUsersByEmailDomain(@Param("domain") String domain);



Транзакции (@Transactional)

База данных требует транзакций (всё или ничего).
В Spring Boot методы репозитория уже транзакционны (только на чтение).
Если же вы в сервисе делаете несколько операций подряд (снять деньги, перевести деньги), вешайте @Transactional над методом сервиса.


@Service
public class PaymentService {
@Transactional // Если упадет ошибка, все изменения откатятся
public void transferMoney() {
repo.withdraw(...);
repo.deposit(...);
}
}



🔥 Итог

Spring Data JPA убирает 90% рутинной работы с БД.

1. Создали @Entity.
2. Создали интерфейс extends JpaRepository.
3. Нужен поиск? Написали метод findByField.
4. Сложный запрос? Написали @Query.

#SpringBoot #JPA #Hibernate #Database #SQL

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6👎2
🚑 Global Exception Handling: Красиво падаем

Представьте: пользователь запрашивает ID, которого нет.

🔴Плохой сценарий: Сервер выплевывает стэктрейс на 500 строк, раскрывая внутренности БД. Статус 500 Internal Server Error. Клиент в шоке.
🔴Хороший сценарий: Клиент получает аккуратный JSON: {"status": 404, "message": "User not found"}.

Раньше, чтобы добиться хорошего сценария, приходилось писать try-catch в каждом методе контроллера. Это ужасно.
В Spring Boot есть элегантное решение - @ControllerAdvice.

🛡 Что это такое?

Это перехватчик (Interceptor), который работает по принципу Аспектно-Ориентированного Программирования (AOP). Он "сидит" над всеми вашими контроллерами и ловит исключения, которые вылетели из них, прежде чем они дойдут до пользователя.

🛠 Как настроить? (3 шага)

1. Создаем DTO для ошибки

Нам нужен красивый формат ответа, чтобы фронтенд всегда знал, чего ожидать.


public record ErrorResponse(int statusCode, String message, LocalDateTime timestamp) {}



2. Создаем Глобальный Обработчик

Используем аннотацию @RestControllerAdvice. Это тот же @ControllerAdvice, но он автоматически добавляет @ResponseBody ко всем ответам (мы же пишем REST API).

Внутри класса мы пишем методы-обработчики с аннотацией @ExceptionHandler.


@RestControllerAdvice
public class GlobalExceptionHandler {

// 1. Ловим конкретную ошибку (например, сущность не найдена)
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(404, ex.getMessage(), LocalDateTime.now()));
}

// 2. Ловим ошибки валидации (если передали кривой JSON)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
String errors = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.joining(", "));

return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(400, errors, LocalDateTime.now()));
}

// 3. Ловим всё остальное (Fallback)
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(500, "Произошла внутренняя ошибка", LocalDateTime.now()));
}
}



3. Бросаем исключения в Сервисе

Теперь в коде сервиса можно не бояться и просто бросать ошибки. Обработчик их поймает.


public User getUser(Long id) {
return repo.findById(id)
.orElseThrow(() -> new EntityNotFoundException("User with id " + id + " not found"));
}



Почему это круто?

1. Чистота кода: В контроллерах нет try-catch блоков. Только "счастливый путь" (happy path).
2. Единообразие: Весь API возвращает ошибки в одинаковом формате.
3. Безопасность: Вы контролируете, какой текст ошибки увидит пользователь, и скрываете системные детали.

🔥 Итог

🔴Не используйте try-catch в контроллерах.
🔴Создайте один класс с @RestControllerAdvice.
🔴Маппите Java-исключения (EntityNotFoundException) на HTTP-статусы (404 Not Found).

#SpringBoot #Java #ExceptionHandling #BestPractices

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍61🔥1
🎛 Конфигурация Spring Boot: YAML, Профили и Секреты

Хардкодить настройки (порты, пароли, URL-ы) в Java-коде - это моветон. Если вам нужно поменять порт сервера, вы не должны перекомпилировать приложение.

Spring Boot следует принципу: "Код отдельно, настройки отдельно".

1️⃣ Properties vs YAML

По умолчанию Spring создает application.properties. Это старый формат (ключ=значение).
Весь мир переходит на YAML (.yaml или .yml). Он читабельнее и поддерживает иерархию.

Было (.properties):


spring.datasource.url=jdbc:postgresql://localhost/db
spring.datasource.username=admin
server.port=8080



Стало (.yaml):


server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost/db
username: admin



Меньше дублирования, глазам приятнее.

2️⃣ Как достать настройки в коде?

Способ А: Простой (@Value)
Подходит для точечных настроек.


@Value("${server.port}")
private int port;



Способ Б: Профессиональный (@ConfigurationProperties)
Если настроек много (например, настройки почты или API), лучше собрать их в отдельный класс. Это дает типизацию и проверку данных!


@ConfigurationProperties(prefix = "mail")
public record MailConfig(String host, int port, String username) {}



Теперь вы просто внедряете MailConfig в свои сервисы, как обычный бин.

3️⃣ Профили (Profiles) - Киллер-фича

На локальной машине у вас H2 база данных, а на продакшене - PostgreSQL. Как не менять конфиги вручную?
Используйте Профили.

Вы создаете несколько файлов рядом с основным application.yaml:

🔴application-dev.yaml (для разработки)
🔴application-prod.yaml (для боевого сервера)

В основном файле вы указываете, какой профиль активен по умолчанию:


spring:
profiles:
active: dev # По умолчанию грузим dev-настройки



А при запуске на сервере вы просто передаете флаг, и Spring подхватит нужный файл, перетерев дефолтные настройки:
java -jar app.jar -Dspring.profiles.active=prod

4️⃣ Секреты (Никаких паролей в Git!)

Самая страшная ошибка - закоммитить application-prod.yaml с паролем от боевой БД в репозиторий. ☠️

Правило: В файлах храним только дефолтные/безопасные значения. Реальные пароли передаем через Переменные Окружения (Environment Variables).

Spring Boot имеет строгий приоритет загрузки. Переменные окружения OS имеют более высокий приоритет, чем файлы.

🔴В файле: spring.datasource.password=secret
🔴В переменной ОС: SPRING_DATASOURCE_PASSWORD=SuperSecurePass123

Spring увидит переменную в системе и проигнорирует то, что написано в файле. Ваш секрет в безопасности.

🔥 Итог

1. Используйте YAML вместо properties.
2. Группируйте настройки через @ConfigurationProperties.
3. Разделяйте среды через Профили (dev, test, prod).
4. Никогда не храните боевые пароли в файлах. Используйте ENV vars.

#SpringBoot #Configuration #YAML #DevOps #BestPractices

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍1🤔1
🎥 Открытый урок «Apache Camel: масштабируемые интеграции для Highload».

🗓 28 января в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса
«Java Developer. Advanced».

Как сделать так, чтобы ваши интеграции на Camel не стали узким местом при росте нагрузки?


Что будет на вебинаре:
✔️ Архитектурные паттерны отказоустойчивости для распределённых систем.
✔️ Тонкая настройка производительности: пулы потоков, back-pressure, мониторинг.
✔️ Стратегии масштабирования: горизонталь, шардинг, разделение нагрузки.
✔️ Разбор реальных проблем и решений в highload-сценариях.
✔️ Live-сессия: ответы на вопросы по архитектуре.

В результате вебинара вы:
- Получите готовые архитектурные подходы, чек-листы и настройки, чтобы ваши Camel-интеграции масштабировались вместе с бизнесом и выдерживали пиковые нагрузки

Кому будет интересно:
Архитекторы интеграций и backend-разработчики, техлиды и DevOps, которым нужно держать высокую нагрузку без деградации сервисов.

🔗 Ссылка на регистрацию: https://vk.cc/cTLgty

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
🧪 Тестирование в Spring Boot: Спите спокойно

Глобально тесты делятся на два лагеря:

1. Unit-тесты (Модульные): Быстрые, изолированные. Проверяем только логику одного класса (обычно Service). Никаких баз данных и поднятия Spring Context.
2. Integration-тесты (Интеграционные): Проверяем, как компоненты работают вместе (Controller + Service + DB). Здесь поднимается Spring Context.

1. Unit-тесты: Изоляция и Скорость

Когда вы тестируете UserService, вам не нужно, чтобы он реально лез в базу данных. Вам нужно проверить: "Если репозиторий вернет null, выбросит ли сервис ошибку?"

Для этого мы используем Mockito - библиотеку, которая создает "фейковые" объекты (моки).

Ключевые аннотации:

🔴@ExtendWith(MockitoExtension.class) - включаем Mockito.
🔴@Mock - "Создай фейковый объект" (например, UserRepository).
🔴@InjectMocks - "Создай тестируемый объект (UserService) и вставь в него моки".

💻 Пример Unit-теста:


@ExtendWith(MockitoExtension.class) // 1. Включаем Mockito
class UserServiceTest {

@Mock
private UserRepository userRepository; // Фейк

@InjectMocks
private UserService userService; // Реальный сервис с фейком внутри

@Test
void shouldReturnUser_WhenExists() {
// GIVEN (Дано) - Настраиваем поведение мока
User mockUser = new User("Alex");
// "Если кто-то вызовет findById(1), верни mockUser"
Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));

// WHEN (Когда) - Вызываем метод сервиса
User result = userService.findById(1L);

// THEN (Тогда) - Проверяем результат
Assertions.assertEquals("Alex", result.getName());
// Проверяем, что метод репозитория действительно вызывался 1 раз
Mockito.verify(userRepository, times(1)).findById(1L);
}
}



🐢 2. Integration-тесты: Тяжелая артиллерия

Иногда нужно проверить, правильно ли мапится JSON в контроллере или работает ли SQL-запрос. Тут нам нужен Spring Context.

Ключевые аннотации:

🔴@SpringBootTest - Поднимает весь контекст приложения (тяжело и медленно, но честно).
🔴@WebMvcTest - Поднимает только веб-слой (Контроллеры). Сервисы и БД не грузятся.
🔴@MockBean - Главная магия Spring Test. Это как @Mock, только этот мок кладется прямо в Spring Context, заменяя собой настоящий бин.

💻 Пример теста Контроллера (@WebMvcTest):


@WebMvcTest(UserController.class) // Грузим только контроллер
class UserControllerTest {

@Autowired
private MockMvc mockMvc; // Инструмент для имитации HTTP-запросов

@MockBean // Заменяем настоящий сервис заглушкой в контексте Spring
private UserService userService;

@Test
void shouldReturnStatus200() throws Exception {
Mockito.when(userService.findById(1L)).thenReturn(new User("Alex"));

mockMvc.perform(get("/users/1")) // Делаем GET запрос
.andExpect(status().isOk()) // Ждем 200 OK
.andExpect(jsonPath("$.name").value("Alex")); // Проверяем JSON
}
}



⚔️ @Mock vs @MockBean - Не путать!

Это самый частый вопрос.

1. @Mock (из org.mockito): Используется в Unit-тестах. Быстро. Spring про него ничего не знает.
2. @MockBean (из spring-boot-test): Используется в Integration-тестах. Spring находит этот бин в контексте и подменяет его на мок. Медленнее.

🔥 Итог

🔴Пишите много Unit-тестов (они быстрые). Используйте Mockito.when(...).
🔴Пишите немного Integration-тестов (они проверяют связки). Используйте MockMvc.
🔴Никогда не тестируйте внешней API или боевую БД - мокайте их!

#SpringBoot #Testing #JUnit5 #Mockito #QualityAssurance

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
📦 От Кода к Продакшену: JAR и Docker

В старые времена (Java EE) процесс деплоя был адом: нужно было установить на сервер Tomcat, настроить его, скомпилировать .war файл, закинуть его в папку... 🤯

Spring Boot принес концепцию Fat JAR (Жирный JAR).

🍔 1. Fat JAR - "Всё своё ношу с собой"

Spring Boot упаковывает ваше приложение, все библиотеки (зависимости) и даже сам веб-сервер (Tomcat) в один единственный файл .jar.

Этот файл работает как .exe в Windows. Ему ничего не нужно, кроме установленной Java.

Как собрать?
В терминале (в папке проекта):


# Для Maven
./mvnw clean package

# Для Gradle
./gradlew build



В папке target (или build/libs) появится файл myapp-0.0.1-SNAPSHOT.jar.

Как запустить?
Где угодно (на сервере, на ноутбуке друга), где есть Java:


java -jar myapp.0.0.1-SNAPSHOT.jar



Всё! Сервер стартует.



🐳 2. Docker - "Работает везде"

JAR это хорошо. Но что, если на сервере стоит Java 11, а у вас Java 17? Или другая ОС? Начинается проблема "На моем компьютере работало!".

Docker решает это, упаковывая ваше приложение вместе с Java и операционной системой в Контейнер.

Пишем Dockerfile
Создайте файл без расширения с именем Dockerfile в корне проекта.

Вариант для новичков (Простой):


# 1. Берем базовый образ с Java 17 (легковесный Alpine Linux)
FROM eclipse-temurin:17-jre-alpine

# 2. Копируем наш JAR внутрь образа
# (Предварительно нужно сделать mvn package руками!)
COPY target/*.jar app.jar

# 3. Говорим, какую команду запустить при старте контейнера
ENTRYPOINT ["java", "-jar", "/app.jar"]



Как запустить:


# 1. Собираем образ (Image)
docker build -t my-spring-app .

# 2. Запускаем контейнер
# -p 8080:8080 пробрасывает порт наружу
docker run -p 8080:8080 my-spring-app





🏗 3. Multi-stage Build (Уровень Pro)

В варианте выше вам нужно сначала собрать JAR руками. Это неудобно для CI/CD.
В профессиональном Dockerfile мы делаем сборку внутри Docker.


# --- Этап 1: Сборка (Build) ---
FROM maven:3.8.5-openjdk-17 AS builder
WORKDIR /app
COPY . .
# Собираем JAR, пропуская тесты (для скорости)
RUN mvn clean package -DskipTests

# --- Этап 2: Запуск (Run) ---
# Берем чистый, маленький образ для запуска
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# Копируем ТОЛЬКО готовый jar из первого этапа
COPY --from=builder /app/target/*.jar app.jar

ENTRYPOINT ["java", "-jar", "app.jar"]



Почему это круто? В финальном образе нет исходного кода и тяжелого Maven. Только Java и ваш JAR. Образ весит минимум, а собрать его можно одной командой docker build, даже если на компьютере вообще не установлена Java!

🔥 Итог

1. Maven/Gradle собирают код в один Fat JAR.
2. Dockerfile описывает среду для запуска.
3. Multi-stage build позволяет собирать и запускать приложение в изолированной среде, не засоряя систему.

#SpringBoot #Docker #DevOps #Deployment #Java

📲 Мы в MAX

👉@BookJava
👍61👎1
🧩 Микросервисы: Укрощение хаоса (Spring Cloud)

Когда у вас один сервис, всё просто. Но когда их становится 10, 20 или 50, возникают вопросы:

1. Как сервису А узнать IP-адрес сервиса Б? (А если он меняется динамически?)
2. Как не писать тонны кода для HTTP-запросов?
3. Как клиенту (фронтенду) обращаться ко всей этой куче сервисов?

Для этого есть три главных инструмента.

1️⃣ Eureka: Телефонная книга (Service Discovery)

В облаке сервисы постоянно перезапускаются, меняют IP-адреса и порты. Хардкодить https://localhost:8081 в коде - самоубийство.

Eureka Server - это реестр.

🔴Когда сервис (например, OrderService) запускается, он звонит в Eureka: "Привет, я OrderService, мой IP такой-то".

🔴Когда UserService хочет найти заказы, он спрашивает Eureka: "Где сейчас живет OrderService?".

В коде:
Вам нужно просто добавить аннотацию @EnableDiscoveryClient, и магия произойдет сама. Сервисы будут находить друг друга по имени, а не по IP.

2️⃣ OpenFeign: Магия общения

Окей, адрес мы нашли. Теперь нужно отправить запрос.
Раньше мы использовали RestTemplate - это было громоздко и некрасиво.
Feign позволяет вызывать удаленный REST-сервис так, будто это обычный метод интерфейса в вашем коде.

Было (RestTemplate):


String url = "https://order-service/orders/" + userId;
List<Order> orders = restTemplate.getForObject(url, List.class); // Фу, нетипизированно



Стало (FeignClient):
Вы просто пишете интерфейс, а реализацию Spring сгенерирует сам!


@FeignClient(name = "order-service") // Имя сервиса в Eureka
public interface OrderClient {

@GetMapping("/orders/{userId}")
List<Order> getUserOrders(@PathVariable Long userId);
}

// Использование в сервисе:
// List<Order> orders = orderClient.getUserOrders(123L);



Это называется Декларативный REST-клиент. Чисто, красиво, типизировано.

3️⃣ API Gateway: Единая точка входа

Представьте, что у вас 50 микросервисов. Фронтенд не должен знать адреса каждого из них (api.com:8081, api.com:8082...). Это небезопасно и сложно (CORS error, привет 👋).

Spring Cloud Gateway - это вахтер на входе.
Весь внешний мир стучится только в него (например, на порт 8080), а он уже сам разруливает, куда отправить запрос.

Что он делает:

1. Маршрутизация: /users/** -> лети в UserService, /orders/** -> лети в OrderService.

2. Безопасность: Проверяет JWT токен один раз на входе.

3. Rate Limiting: "Не больше 10 запросов в секунду от этого юзера".

Пример конфига (application.yaml):


spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE # lb = Load Balancer (через Eureka)
predicates:
- Path=/users/**



Итог: Как это работает вместе?

1. Сервисы просыпаются и регистрируются в Eureka.

2. Фронтенд шлет запрос на Gateway.

3. Gateway спрашивает у Eureka адрес нужного сервиса и пересылает запрос.

4. Если сервисам нужно пообщаться между собой, они используют Feign.

#Java #Microservices #SpringCloud #Eureka #Feign

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝6👍4