У веб-розробці є два напрямки руху даних:
- Клієнт → Сервер (обробка запитів).
- Сервер → Клієнт (формування відповідей).
Якщо на перший напрям ми вже поглянули, то другий вимагає нашої пильної уваги. Давай розберемося, як сервер може "відповідати" клієнту і чому це важливо для успішної взаємодії.
Варіанти відповідей
- HTML-сторінки.
- Сервер повертає HTML-код, який браузер рендерить користувачу.
- JSON/XML.
- Серійовані дані для клієнтів (наприклад, у REST API).
- Файли або інші ресурси.
- Наприклад, зображення, PDF або ZIP-файли.
У Spring MVC ми гнучко формуємо відповіді завдяки потужній системі анотацій та інструментів.
Анотація @ResponseBody
Якщо ти прийшов із світу REST API, то фраза "JSON-відповіді" має бути для тебе як музика. Ця анотація саме відповідає за відправку даних у форматі JSON або XML з контролера клієнту.
По суті, @ResponseBody каже Spring: "Досить грати в ці гарні стендапчики з HTML-сторінками. Просто відправ дані клієнту, без зайвої драматургії". Тобто вона скасовує view resolution, і натомість повертає дані безпосередньо в HTTP-відповідь.
Приклад: Відправка JSON-відповіді
Ось найпростіший приклад:
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/user")
public User getUser() {
return new User(1, "John Doe");
}
}
Тут ми використовуємо @RestController, яка, по суті, є скороченням для @Controller + @ResponseBody. Це означає, що кожен метод повертає JSON-відповідь. Якщо ти повернеш об'єкт, Spring автоматично перетворить його в JSON (серіалізує) завдяки вбудованій бібліотеці Jackson.
Як це працює? Spring вміє серіалізувати об'єкти в JSON завдяки бібліотеці Jackson. Вона входить "з коробки", тож ніяких додаткових танців не потрібно. Але якщо захочеш серіалізувати об'єкт в XML, то знадобиться трохи доопрацювань.
Приклад: Використання @ResponseBody без @RestController
Якщо з якоїсь причини ти використовуєш звичайний контролер, а не @RestController, нічого страшного! Просто додай @ResponseBody до методу.
@Controller
@RequestMapping("/api")
public class UserController {
@ResponseBody
@GetMapping("/user")
public User getUser() {
return new User(1, "Jane Doe");
}
}
Ця анотація каже Spring, що дані потрібно повертати напряму, а не шукати представлення.
А можна повернути не тільки JSON?
Звісно. Якщо хочеш повернути, наприклад, рядок або будь-який інший тип даних, @ResponseBody з радістю це зробить.
@Controller
@RequestMapping("/api")
public class ExampleController {
@ResponseBody
@GetMapping("/hello")
public String sayHello() {
return "Hello, Spring MVC!";
}
}
Клієнт отримає просто рядок: Hello, Spring MVC!.
Типові помилки при використанні @ResponseBody
- Помилка: "Cannot serialize object". Це трапляється, якщо об'єкт не може бути перетворений у JSON. Наприклад, у нього немає
public-гетерів, або ти забув підключити Jackson. - Випадкове повернення HTML. Якщо ти забудеш
@ResponseBodyабо використаєш@Controllerбез неї, Spring може спробувати знайти HTML-сторінку з іменем, що співпадає з поверненим значенням (наприклад, "user" для методуgetUser).
Анотація @ModelAttribute
Якщо @ResponseBody — твій найкращий друг для REST API, то @ModelAttribute незамінний для роботи з класичним MVC, де використовують HTML і серверні шаблони.
Анотація @ModelAttribute допомагає передавати дані з контролера у представлення. Вона завантажує об'єкт у модель (ми про org.springframework.ui.Model!), щоб потім передати його в шаблон.
Приклад: передача об'єкта у представлення
Припустимо, у нас є HTML-сторінка, яка відображає інформацію про користувача. Спочатку потрібно передати дані:
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/profile")
public String userProfile(Model model) {
User user = new User(1, "Jane Doe");
model.addAttribute("user", user);
return "userProfile";
}
}
Тут ми додаємо об'єкт user у модель, а потім повертаємо ім'я представлення (userProfile), яке його відобразить. Представлення може бути, наприклад, Thymeleaf-шаблоном.
Використання @ModelAttribute
Але навіщо вручну додавати в модель, якщо є @ModelAttribute?
@Controller
@RequestMapping("/users")
public class UserController {
@ModelAttribute("user")
public User getUser() {
return new User(1, "Jane Doe");
}
@GetMapping("/profile")
public String userProfile() {
return "userProfile";
}
}
Spring викличе метод з @ModelAttribute автоматично при будь-якому запиті до контролера, і об'єкт буде доданий у модель під вказаним іменем (user). Це скорочує код і робить твій контролер чистішим.
Приклад: робота з формами
@ModelAttribute також використовується для прив'язки даних з форм у Java-об'єкти.
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/register")
public String showRegistrationForm(Model model) {
model.addAttribute("user", new User());
return "register";
}
@PostMapping("/register")
public String processRegistration(@ModelAttribute("user") User user) {
System.out.println("Registered user: " + user);
return "registrationSuccess";
}
}
- GET-запит відображає форму реєстрації з порожнім об'єктом
User. - POST-запит автоматично зв'язує дані з форми з об'єктом
User.
Типові помилки при використанні @ModelAttribute
- Помилка: "NullPointerException". Якщо ти забув додати об'єкт у модель, представлення не зможе відрендерити дані.
- Помилка прив'язки даних. Якщо в тебе складний об'єкт і дані з форми не можуть бути проставлені, Spring викине помилку. Переконайся, що всі поля форми відповідають полям об'єкта.
Коли використовувати @ResponseBody і @ModelAttribute?
| Анотація | Коли використовувати |
|---|---|
@ResponseBody |
Коли потрібно повернути JSON/XML або рядок |
@ModelAttribute| Коли ти працюєш з HTML-формами або шаблонами |
Тепер ти озброєний знаннями про те, як формувати відповіді в Spring MVC. Пам'ятай: @ResponseBody — найкращий вибір для REST API, а @ModelAttribute врятує тебе у світі форм і серверної генерації HTML.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ