Класи з анотацією @Controller та @ControllerAdvice можуть мати методи, позначені анотацією @ExceptionHandler, для обробки винятків із методів контролера, як показано в наступному прикладі:

Java
@Controller public class SimpleController { // ... @ExceptionHandler public ResponseEntity<String> handle(IOException ex) { // ... } }
Kotlin
@Controller class SimpleController { / / ... @ExceptionHandler fun handle(ex: IOException): ResponseEntity<String> { // ... } }

Виняток може збігатися з поширюваним високорівневим винятком (наприклад, прямо генерований IOException) або з вкладеною причиною всередині виключення-обгортки (наприклад, IOException, обернене всередині IllegalStateException). Починаючи з 5.3, це може збігатися на довільних рівнях причин, тоді як раніше бралася до уваги тільки безпосередня причина. При збігу кількох методів виключення, як правило, краще збіг винятку кореня, ніж збіг виключення причини. Зокрема, ExceptionDepthComparator використовується для сортування винятків на основі їх глибини від типу згенерованого винятку. :

Java
@ExceptionHandler({FileSystemException.class, RemoteException.class}) public ResponseEntity<String> handle(IOException ex) { // ... }
Kotlin
@ExceptionHandler(FileSystemException::class , RemoteException::class) fun handle(ex: IOException): ResponseEntity<String> { // ... }

Можна навіть використовувати список конкретних типів винятків з дуже загальною сигнатурою аргументів, як показано в наступному прикладі:

Java
@ExceptionHandler({FileSystemException.class, RemoteException.class}) public ResponseEntity<String> handle(Exception ex) { // ... }
Kotlin
@ExceptionHandler(FileSystemException::class , RemoteException::class) fun handle(ex: Exception): ResponseEntity<String> { // ... }

Відмінність між зіставленням винятків кореня і причини може здивувати.

У варіанті IOException, показаному раніше, метод зазвичай викликається з використанням фактичного екземпляра FileSystemException або RemoteException як аргумент, оскільки обидва вони розширюються від IOException. Однак, якщо будь-який такий випадок, що збігається, поширюється всередині виключення-обертки, яке саме є IOException, то переданий екземпляр виключення є цим винятком-оберткою.

У варіанті handle(Exception ) логіка роботи ще простіше. Її виклик відбувається за допомогою вилучення-обертки в сценарії обгортання, при цьому фактично відповідний виняток можна знайти через ex.getCause() у цьому випадку. Переданий виняток є фактичним екземпляром FileSystemException або RemoteException тільки в тому випадку, якщо вони генеруються як високорівневі винятки.

Зазвичай рекомендується давати як можна більше конкретики у сигнатурі аргументів, щоб знизити ймовірність невідповідності між типами винятків кореня та причини. Розглянемо можливість розбити метод з кількома збігами на окремі методи, анотовані @ExceptionHandler, кожен із яких відповідає одному певному типу виключення через свою сигнатуру.

У конфігурації з декількома анотаціями @ ControllerAdvice рекомендуємо оголошувати відображення основних винятків кореня в анотації @ControllerAdvice у відповідному пріоритетному порядку. Хоча порівняння винятку кореня краще, ніж зіставлення винятку причини, визначення відбувається серед методів даного контролера або класу, анотованого @ControllerAdvice. Це означає, що збіг причини для бина, анотованого @ControllerAdvice, з більш високим пріоритетом кращий за будь-який збіг (наприклад, кореня) для бина, анотованого @ControllerAdvice з нижчим пріоритетом.

І останнє, але не менш важливе: реалізація методу, позначеного анотацією @ExceptionHandler, може відмовитися працювати з цим екземпляром виключення, повторно згенерувавши його у вихідній формі. Це корисно в тих випадках, коли вас цікавлять виключно збіги на кореневому рівні або збіги у певному контексті, який не може бути визначений статично. Повторна генерація виключення поширюється по ланцюжку дозволу, що залишився, як би даний метод з анотацією @ExceptionHandler не співпав з першим.

Підтримка методів з анотацією @ExceptionHandler Spring MVC побудована на рівні DispatcherServlet, механізмі HandlerExceptionResolver.

Аргументи методу

Методи з анотацією @ExceptionHandler підтримують наступні аргументи:

Аргумент методу Опис

Тип виключення

Забезпечує доступ до згенерованого виключення.

HandlerMethod

Забезпечує доступ до методу контролера, який згенерував виняток.

WebRequest, NativeWebRequest

Типізований доступ до параметрів запиту та атрибутів запиту та сесії без прямого використання Servlet API.

javax. servlet.ServletRequest, javax.servlet.ServletResponse

Виберіть будь-який тип запиту або відповіді (наприклад, ServletRequest або HttpServletRequest, або MultipartRequest або MultipartHttpServletRequest з Spring).

javax.servlet.http.HttpSession

Забезпечує наявність сесії. Як наслідок, такий аргумент ніколи не є null.
Зверніть увагу, що доступ до сесії не є безпечним. Розгляньте можливість встановлення прапора synchronizeOnSession екземпляра RequestMappingHandlerAdapter у true, якщо кільком запитам дозволено одночасний доступ до сесії.

java.security.Principal

Поточний автентифікований користувач – можливо, конкретний клас реалізації Principal, якщо він відомий.

HttpMethod

HTTP-метод запиту.

java.util.Locale

Поточні регіональні налаштування запиту, що визначаються найбільш конкретним доступним LocaleResolver – по суті, налаштованим LocaleResolver або LocaleContextResolver.

java.util.TimeZone, java.time.ZoneId

Годовий пояс, пов'язаний з поточним запитом, визначений LocaleContextResolver.

java.io.OutputStream, java.io.Writer

Забезпечує доступ до сирого тіла відповіді, як це передбачено Servlet API.

java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap

Забезпечує доступ до моделі для надання відповіді на помилку. Завжди порожній.

RedirectAttributes

Задайте атрибути, що використовуються у разі перенаправлення - (які будуть додані до рядка запиту) та flash атрибути для тимчасового зберігання до надходження запиту після перенаправлення.

@SessionAttribute

Призначений для забезпечення доступу до будь-якого атрибуту сесії, на відміну від атрибутів моделі, що зберігаються в сесії в результаті оголошення анотації @SessionAttributes на рівні класу.

@RequestAttribute

Призначений для забезпечення доступу до атрибутів запиту.

Повертані значення

Методи з анотацією @ExceptionHandler підтримують наступні значення, що повертаються:

Return value Description

@ResponseBody

Повертане значення перетворюється через екземпляри HttpMessageConverter і записується у відповіді.

HttpEntity<B>, ResponseEntity<B>

Повертане значення задає, що повна відповідь (включаючи HTTP-заголовки та тіло) буде перетворена через екземпляри HttpMessageConverter і записана у відповідь.

String

Ім'я уявлення, яке має бути розпізнане за допомогою реалізацій ViewResolver та використовуватися разом з неявною моделлю – визначається через об'єкти команд та методи з анотацією @ModelAttribute. Метод обробника також може програмно доопрацювати модель, оголосивши аргумент Model (описаний раніше).

View

Екземпляр View, призначений для візуалізації разом з неявною моделлю – визначається через об'єкти команд та методи з анотацією @ModelAttribute. Метод обробника може також програмно доопрацювати модель, оголосивши аргумент Model (описаний раніше).

java.util .Map, org.springframework.ui.Model

Атрибути для додавання в неявну модель з ім'ям уявлення, неявно визначеним через RequestToViewNameTranslator.

@ModelAttribute

Атрибут, що додається до моделі з іменем представлення, неявно визначеним через RequestToViewNameTranslator.

Зверніть увагу, що інструкція @ModelAttribute є необов'язковою. Див. розділ "Будь-яке інше значення, що повертається" в кінці цієї таблиці.

ModelAndView object

Атрибути представлення та моделі, що використовуються, і, при необхідності, статус відповіді.

void

Вважається, що метод з повертаним типом void (або значенням, що повертається null) повністю обробив відповідь, якщо він також має аргумент ServletResponse або OutputStream, або анотацію @ResponseStatus. Те саме вірно, якщо контролер виконав позитивну перевірку ETag або тимчасової мітки lastModified.

Якщо жодне з вищеперелічених значень не вірне, повертається тип void може також вказувати на "відсутність тіла відповіді" для REST-контролерів або вибір імені подання за промовчанням для HTML-контролерів.

Будь-яке інше значення, що повертається

Якщо повертається значення не відповідає жодному з вищеперелічених і не є простим типом (як визначено BeanUtils#isSimpleProperty), за За умовчанням воно вважається атрибутом моделі, який має бути доданий до моделі. Якщо це простий тип, він залишається невирішеним.

Робота з винятками в REST API

Загальною вимогою для служб REST є включення інформації про помилку у тіло відповіді. Spring Framework не автоматично цього не робить, оскільки подання інформації про помилку в тілі відповіді залежить від конкретної програми. Однак анотація @RestController може використовувати методи, позначені анотацією @ExceptionHandler, з значенням ResponseEntity, що повертається, для встановлення статусу і тіла відповіді. Такі методи також можуть бути оголошені в класах, анотованих @ControllerAdvice, щоб можна було застосовувати їх глобально.

Додатки, що реалізують глобальну обробку винятків із докладним описом помилки в тілі відповіді, повинні враховувати можливість розширення ResponseEntityExceptionHandler, який забезпечує обробку винятків, що виникають у Spring MVC, і надає перехоплювачі для налаштування тіла відповіді. Щоб скористатися цим, створіть підклас ResponseEntityExceptionHandler, анотуйте його за допомогою @ControllerAdvice, перевизначте необхідні методи та оголосіть його як бін Spring.