Service: “мозок” застосунку
Service-шар — це місце, де живе логіка: перевірки, правила, обробка помилок, транзакції. Controller приймає HTTP, Repository працює з БД, а Service зв’язує все в нормальну систему.
Рис. 13.1. Клас UserService з анотацією @Service, який використовує UserRepository для доступу до таблиці users.

### 1) Навіщо взагалі потрібен Service (а не “все в контролері”)

На малих прикладах здається, що можна робити все в контролері: прийняв запит → викликав репозиторій → повернув відповідь. Але в реальному проєкті так швидко починається хаос.

- Controller має бути тонким: HTTP-вхід/вихід (Request/Response).
- Repository має бути простим: CRUD і доступ до даних.
- Service має бути розумним: правила, перевірки, логіка.

Правило для студентів: якщо ти відчуваєш, що в контролері з’являються перевірки, if-и, додаткова логіка — значить це треба винести в Service.

### 2) Схема шарів (як це працює в Spring Boot проєкті)

HTTP запит → Controller → Service → Repository → Database ↑ ↓ HTTP відповідь ← DTO/Entity

Ідея: кожен шар робить своє. Якщо потім ти додаси нові правила (наприклад “email має бути унікальним”) — ти змінюєш Service, а не переписуєш весь проєкт.

### 3) Розбір @Service: що це за анотація і що вона дає

@Service — це “мітка”, що клас є сервісом (Spring Bean).

- Spring автоматично знаходить цей клас під час сканування пакетів.
- Створює об’єкт (bean) і керує його життєвим циклом.
- Дозволяє іншим класам “вколоти” (inject) цей сервіс.

Технічно @Service — це спеціалізація @Component. Але @Service читається людиною: “це бізнес-логіка”.

### 4) Dependency Injection: чому ми передаємо repository в конструктор

Ось ключова частина:

private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; }

- Spring сам створює об’єкт UserRepository (проксі).
- Потім, коли створює UserService, передає репозиторій у конструктор.
- Ти не пишеш new UserRepository() — це робить контейнер Spring.

Чому саме конструктор: це найбільш “чистий” і надійний варіант. Поле стає обов’язковим, сервіс не може існувати без репозиторію.

### 5) Чому поле зроблено final

- final означає: після ініціалізації поле не можна переприсвоїти.
- це зменшує кількість помилок (хтось випадково не затре репозиторій).
- це хороший стиль для DI: залежності мають бути незмінні.

У нормальному проєкті “залежності” сервісу — це константа: сьогодні userRepository, завтра він не має стати іншим.

### 6) Розбір методів сервісу (що робить кожен)

getAllUsers()

public List<User> getAllUsers() { return userRepository.findAll(); }

- повертає список всіх користувачів з таблиці users
- під капотом findAll() → SQL типу SELECT * FROM users
- це “читання” (read) з БД

Тут логіки поки мало — але це правильне місце, щоб додати її потім (фільтри, сортування, пагінацію).

createUser(User user)

public User createUser(User user) { return userRepository.save(user); }

- зберігає користувача в БД
- save() зробить INSERT, якщо id немає
- після збереження об’єкт може повернутись вже з заповненим id

Саме тут найчастіше з’являються перевірки: валідність email, унікальність, мінімальна довжина імені.

### 7) Де саме має бути “реальна логіка” (приклади для пояснення студентам)

Зараз сервіс просто викликає репозиторій. Але в реальності тут буде, наприклад:

- перевірка, що email не порожній і має нормальний формат;
- перевірка, що такого email ще немає: userRepository.findByEmail();
- нормалізація: trim(), toLowerCase() для email;
- обробка помилок і повернення зрозумілої відповіді клієнту;
- логування: хто створив користувача, коли, з яким email;
- транзакції: якщо треба виконати кілька дій як один “атомарний” крок.

Висновок: Service — це місце, де система стає “розумною”. Repository лише зчитує/пише, а Service вирішує “можна чи не можна”.

### 8) Анотація @Transactional (важливо, але можна підключати пізніше)

Часто сервісні методи позначають @Transactional. Це означає: виконати всі дії всередині методу як одну транзакцію.

- якщо всередині методу кілька операцій — вони або всі успішні, або всі відкотяться;
- це критично для грошей, статусів, складних сценаріїв.

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

### 9) Типові помилки (попередження)

- Controller напряму викликає Repository → логіка роз’їжджається по всьому проєкту.
- Service починає будувати HTTP-відповідь (ResponseEntity) → це вже зона Controller.
- Валідації немає ніде → в БД з’являються “сміттєві” дані.

Підсумок: ми створили UserService як правильний шар між Controller і Repository. Поки він простий, але саме тут потім з’являться перевірки, правила і “реальна логіка”.