Некоторое время назад я написал блог, в котором рассказывалось о том, как я обновил пример кода Spring до версии 3.2, и продемонстрировал несколько возникших маленьких «ошибок». С тех пор как я просматривал новый список возможностей Spring 3.2, и, хотя он не содержит каких-либо революционных изменений, я подозреваю, что ребята из Spring сохраняют его для версии 4, он содержит несколько аккуратных обновлений. Первым, что привлекло мое внимание, была новая аннотация @ControllerAdvice, которая, кажется, аккуратно закрывает пробел в функциональности Spring 3. Позволь мне объяснить…
Если вы посмотрите на мой блог, посвященный обработчикам исключений MVC Spring 3, то увидите, что в примере кода содержится нестабильный контроллер с методом обработчика запросов, который выдает
IOException . IOException затем обрабатывается другим методом в том же
контроллер, аннотированный @ExceptionHandler(IOException.class) . Проблема в том, что ваш метод, аннотированный @ExceptionHandler(IOException.class) может обрабатывать только IOException выбрасываемые содержащим его контроллером. Если вы хотите создать глобальный обработчик исключений, который обрабатывает исключения, генерируемые всеми контроллерами, тогда вам нужно вернуться к чему-то вроде SimpleMapingExceptionHandler в Spring 2 и некоторой конфигурации XML . Теперь все по-другому. Чтобы продемонстрировать использование @ControllerAdvice я создал простое приложение Spring 3.2 MVC, которое вы можете найти на github . Домашняя страница приложения, как правило, позволяет пользователю отображать либо свой адрес, либо данные кредитной карты,
… За исключением того, что когда пользователь пытается сделать это, связанные контроллеры
IOException и приложение отображает следующую страницу ошибки:
Контроллеры, которые генерируют исключения, довольно просты и перечислены ниже:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Controllerpublic class UserCreditCardController { private static final Logger logger = LoggerFactory.getLogger(UserCreditCardController.class); /** * Whoops, throw an IOException */ @RequestMapping(value = "userdetails", method = RequestMethod.GET) public String getCardDetails(Model model) throws IOException { logger.info("This will throw an IOException"); boolean throwException = true; if (throwException) { throw new IOException("This is my IOException"); } return "home"; }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Controllerpublic class UserAddressController { private static final Logger logger = LoggerFactory.getLogger(UserAddressController.class); /** * Whoops, throw an IOException */ @RequestMapping(value = "useraddress", method = RequestMethod.GET) public String getUserAddress(Model model) throws IOException { logger.info("This will throw an IOException"); boolean throwException = true; if (throwException) { throw new IOException("This is my IOException"); } return "home"; }} |
Как видите, все, что делает этот код, это сопоставляет userdetails и useraddress с getCardDetails(...) и getUserAddress(...) соответственно. Когда любой из этих методов генерирует IOException , исключение перехватывается следующим классом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@ControllerAdvicepublic class MyControllerAdviceDemo { private static final Logger logger = LoggerFactory.getLogger(MyControllerAdviceDemo.class); @Autowired private UserDao userDao; /** * Catch IOException and redirect to a 'personal' page. */ @ExceptionHandler(IOException.class) public ModelAndView handleIOException(IOException ex) { logger.info("handleIOException - Catching: " + ex.getClass().getSimpleName()); return errorModelAndView(ex); } /** * Get the users details for the 'personal' page */ private ModelAndView errorModelAndView(Exception ex) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("error"); modelAndView.addObject("name", ex.getClass().getSimpleName()); modelAndView.addObject("user", userDao.readUserName()); return modelAndView; }} |
Приведенный выше класс аннотирован новой аннотацией @ControllerAdvice и содержит единственный открытый метод handleIOException(IOException.class) . Этот метод перехватывает все исключения IOException, выданные вышеприведенными контроллерами, генерирует модель, содержащую некоторую релевантную информацию о пользователе, а затем отображает страницу ошибок. Приятно то, что независимо от того, сколько контроллеров содержит ваше приложение, когда любой из них выдает IOException , он будет обрабатываться обработчиком исключений MyControllerAdviceDemo .
@ModelAttribute и @InitBinder одна последняя вещь, которую следует помнить: хотя аннотация ControllerAdvice полезна для обработки исключений, ее также можно использовать для глобальной обработки аннотаций @ModelAttribute и @InitBinder . Комбинация ControllerAdvice и @ModelAttribute дает вам возможность настроить объекты модели для всех контроллеров в одном месте, а также комбинация ControllerAdvice и @InitBinder позволяет вам присоединить один и тот же пользовательский валидатор ко всем вашим контроллерам, опять же, в одном месте.
Ссылка: обработка исключений с помощью Spring 3.2 @ControllerAdvice Аннотация от нашего партнера по JCG Роджера Хьюза в блоге Captain Debug’s Blog .

