JavaRush /Курси /Модуль 5. Spring /Анотації @RequestBody, @ResponseBody

Анотації @RequestBody, @ResponseBody

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

Коли ми створюємо REST API, часто потрібно обробляти дані, які передаються в запитах. Наприклад, створюємо новий запис або оновлюємо існуючий. Ці дані зазвичай передаються в тілі HTTP-запиту. Також, коли сервер відповідає клієнту, ми відправляємо дані назад, наприклад, у форматі JSON. В цей момент на сцену виходять анотації @RequestBody і @ResponseBody.

  • @RequestBody: допомагає "витягнути" дані з тіла HTTP-запиту і перетворити їх у Java-об'єкт, який ми можемо легко використовувати в коді.
  • @ResponseBody: автоматично перетворює Java-об'єкт у JSON (або інший формат) і відправляє його в тіло HTTP-відповіді.

Це схоже на "телепортацію даних" між клієнтом і сервером. Ви передаєте JSON на сервер, і він чарівним чином перетворюється на нормальний Java-об'єкт. А сервер, у свою чергу, повертає об'єкт, який чудесним чином стає JSON.


Робота з тілом запиту: @RequestBody

Spring Boot використовує бібліотеку Jackson (за замовчуванням) для перетворення даних. Коли приходить HTTP-запит з JSON, анотація @RequestBody каже Spring: "Гей, візьми тіло запиту, розпарси його і передай мені Java-об'єкт!".

Припустімо, у нас є сутність User:


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

    // Геттери та сеттери
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Ми хочемо написати контролер, який буде отримувати об'єкт User в тілі запиту:


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

    @PostMapping
    public String createUser(@RequestBody User user) {
        // Логуємо вхідні дані
        System.out.println("Отримано користувача: " + user.getName() + ", вік: " + user.getAge());
        return "Користувач " + user.getName() + " успішно створений!";
    }
}

Клієнт відправляє POST-запит:


{
    "name": "Іван",
    "age": 30
}

І на сервері це перетворюється в об'єкт User. Жодного додаткового коду для парсингу JSON не потрібно — про все дбає Spring.


Валідація даних

Іноді передані дані можуть бути недопустимими. Наприклад, порожнє ім'я або вік менше нуля. У таких випадках ми можемо використати анотацію @Valid для автоматичної валідації:


import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;

public class User {
    @NotNull(message = "Ім'я не повинно бути порожнім")
    private String name;

    @Min(value = 0, message = "Вік не може бути від'ємним")
    private int age;

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

І в контролері:


@PostMapping
public String createUser(@Valid @RequestBody User user) {
    return "Користувач " + user.getName() + " успішно створений!";
}

Якщо клієнт відправить некоректні дані, наприклад:


{
    "name": "",
    "age": -1
}

Сервер поверне помилку 400 Bad Request з деталями:


{
    "timestamp": "2023-10-22T10:12:45.123+00:00",
    "status": 400,
    "error": "Bad Request",
    "messages": [
        "Ім'я не повинно бути порожнім",
        "Вік не може бути від'ємним"
    ]
}

Робота з відповідями: @ResponseBody

Коли потрібно відправити дані клієнту, @ResponseBody приходить на допомогу. Ця чарівна анотація підказує Spring, що Java-об'єкт треба перетворити в JSON (або інший формат) і зробити його частиною відповіді.

А знаєте, що цікаво? Якщо ви використовуєте @RestController, то Spring автоматично додасть @ResponseBody до всіх методів контролера. Саме тому REST-контролери пишуться швидше і елегантніше — Spring вже подбав про це за вас.

Продовжимо роботу з UserController. Тепер додамо метод для отримання користувача:


@GetMapping("/{id}")
public @ResponseBody User getUser(@PathVariable int id) {
    // Заглушка: повернемо фіктивного користувача
    User user = new User();
    user.setName("Іван");
    user.setAge(30);
    return user;
}

Клієнт відправляє GET-запит:


GET /users/1

Відповідь сервера:


{
    "name": "Іван",
    "age": 30
}

Поради по роботі з @ResponseBody

  1. Ви можете повертати не тільки об'єкти, але й колекції. Наприклад:

@GetMapping
public List<User> getAllUsers() {
    List<User> users = new ArrayList<>();
    User user1 = new User();
    user1.setName("Іван");
    user1.setAge(30);
    users.add(user1);

    User user2 = new User();
    user2.setName("Анна");
    user2.setAge(25);
    users.add(user2);

    return users;
}

Відповідь сервера:


[
    {
        "name": "Іван",
        "age": 30
    },
    {
        "name": "Анна",
        "age": 25
    }
]

Особливості роботи анотації

Якщо ви використовуєте анотацію @ResponseBody з звичайним @Controller (не @RestController), не забудьте додати її до всіх методів, які повинні повертати дані в HTTP-відповіді. Наприклад:


@Controller
public class MyController {

    @GetMapping("/hello")
    public @ResponseBody String sayHello() {
        return "Привіт!";
    }
}

Типові помилки при використанні @RequestBody і @ResponseBody

Дуже важливо розуміти, як працюють ці анотації, щоб уникнути помилок. Наприклад:

  1. Помилка десеріалізації: якщо JSON, надісланий клієнтом, не відповідає структурі об'єкта, Spring викине виключення. Наприклад, якщо клієнт забув поле "name", то ви отримаєте помилку HttpMessageNotReadableException.
    • Рішення: Переконайтеся, що структура JSON узгоджується з моделлю об'єкта.
  2. Відмова від використання анотації @Valid: без валідації ви можете отримати некоректні дані в базі. Використовуйте @Valid і обробники помилок.
  3. Ігнорування рівнів логування: логируйте JSON-запити та відповіді — це врятує ваш час при налагодженні.

Практичне застосування

@RequestBody і @ResponseBody — це два киті, на яких тримається REST API. Вони беруть на себе всю головну біль щодо обробки JSON — більше ніякого ручного парсингу і форматування! У реальних проєктах ці анотації стають вашими вірними помічниками при роботі з даними, їх перевіркою і перетворенням.

Неможливо уявити сучасний REST API без цих анотацій — це як намагатися писати код без IDE. Освоївши їх, ви зможете створювати елегантні і надійні API. І, звісно, не забувайте тестувати свої ендпоінти — але це вже зовсім інша історія!

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