JavaRush /Курси /Модуль 5. Spring /Формування користувацьких повідомлень про помилки

Формування користувацьких повідомлень про помилки

Модуль 5. Spring
Рівень 8 , Лекція 7
Відкрита

Уявіть, що ви намагаєтеся заповнити форму на сайті, а система у відповідь видає: "Ошибка 400. Неправильный запрос. Поле user_input не соответствует требованиям валидации." Відчуваєте цей холодний роботизований тон? Користувачу важко зрозуміти, що пішло не так і як це виправити.

Правильно оформлені повідомлення про помилки допомагають:

  1. Направити користувача в правильному напрямку, вказавши, що саме він зробив неправильно.
  2. Зменшити рівень фрустрації і підвищити задоволеність користувача вашим застосунком.
  3. Допомогти розробникам швидше знаходити проблеми, використовуючи логування помилок.

Тепер, коли ми знаємо, навіщо це потрібно, приступимо до справи.


Автоматичне формування повідомлень з Bean Validation API

У попередніх лекціях ми вже додавали анотації для валідації даних. Нагадаємо простий приклад:


import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class UserDto {

    @NotNull(message = "Ім'я користувача не може бути порожнім")
    @Size(min = 2, max = 30, message = "Ім'я користувача має бути від 2 до 30 символів")
    private String username;

    @NotNull(message = "Електронна пошта обов'язкова")
    @Size(max = 50, message = "Електронна пошта не може містити більше 50 символів")
    private String email;

    // Геттери і сеттери
}

Тут message передає рядок, який буде показаний користувачу при порушенні правила. Це відмінний старт, але ми можемо зробити ще краще.


Локалізація повідомлень з використанням MessageSource

Якщо ви розробляєте застосунок для різних мов (наприклад, російська і англійська), було б круто підтримувати локалізацію. Дивіться, як це робиться.

Налаштування MessageSource

Додамо в проєкт клас конфігурації для локалізації:


import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

@Configuration
public class MessageConfig {

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource =
                new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages/validation");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
}

Цей MessageSource буде читати файли локалізації. Наприклад, створимо файл validation.properties (за замовчуванням для англійської) і validation_ru.properties для російської мови:

validation.properties


username.notNull=Username is required
username.size=Username must be between 2 and 30 characters
email.notNull=Email is required
email.size=Email cannot exceed 50 characters

validation_ru.properties


username.notNull=Ім'я користувача не може бути порожнім
username.size=Ім'я користувача має бути від 2 до 30 символів
email.notNull=Електронна пошта обов'язкова
email.size=Електронна пошта не може містити більше 50 символів

Зміна DTO для використання локалізованих повідомлень

Тепер ми можемо використовувати message з ключами з файлів локалізації:


import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class UserDto {

    @NotNull(message = "{username.notNull}")
    @Size(min = 2, max = 30, message = "{username.size}")
    private String username;

    @NotNull(message = "{email.notNull}")
    @Size(max = 50, message = "{email.size}")
    private String email;

    // Геттери і сеттери
}

Ось так! Тепер повідомлення автоматично підтягуються залежно від мови користувача.


Валідація і формування повідомлень в контролерах

Припустимо, у нас є контролер для обробки запиту на створення користувача:


import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/users")
@Validated
public class UserController {

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody UserDto userDto) {
        // Логіка збереження користувача...
        return ResponseEntity.ok("Користувача успішно створено!");
    }
}

Якщо користувач відправить некоректні дані, наприклад порожнє ім'я, Spring кине помилку MethodArgumentNotValidException. Щоб її обробити і повернути красиве повідомлення, додамо наступний обробник:


import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationExceptions(
            MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
            errors.put(error.getField(), error.getDefaultMessage())
        );
        return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
    }
}

Якщо користувач відправить запит:


{
    "username": "",
    "email": "anInvalidEmail@verylongemailthatexceedsfiftycharacters.com"
}

На виході ми отримаємо структурований і зрозумілий JSON:


{
    "username": "Ім'я користувача не може бути порожнім",
    "email": "Електронна пошта не може містити більше 50 символів"
}

Локалізація через HTTP-заголовки

Spring дозволяє змінювати мову в запитах через заголовок Accept-Language. Наприклад:


Accept-Language: en

У такому випадку повідомлення про помилки будуть відображатися англійською. Якщо вказати ru, то повідомлення автоматично переключаться на російську. Це робиться через вбудований LocaleResolver.

Додамо LocaleResolver:


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;

import java.util.Locale;

@Configuration
public class LocaleConfig {

    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
        localeResolver.setDefaultLocale(Locale.ENGLISH);
        return localeResolver;
    }
}

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


Корисні поради

  1. Пишіть зрозумілі повідомлення. Уникайте абревіатур і технічного жаргону. Користувач має зрозуміти, що йому робити.
  2. Логуйте помилки. Якщо користувач бачить лише частину інформації, решту логуйте на сервері — це допоможе в пошуку і усуненні проблем.
  3. Тестуйте локалізацію. Переконайтеся, що повідомлення коректно відображаються всіма підтримуваними мовами.

Тепер у нас є потужний інструмент для виводу повідомлень про помилки, які зрозумілі і користувачу, і розробнику. Такі підходи роблять застосунок більш професійним і дружнім. У наступній лекції ми розглянемо, як налаштувати локалізацію повідомлень ще глибше і підключити обробку помилок на глобальному рівні.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ