This is sample error page

Spring @ControllerAdvice and @ExceptionHandler

Exception handling is a very essential feature of any Java application. Every good open-source framework allows writing the exception handlers in such a way that we can separate them from our application code. Well, Spring framework also allows us to do so using annotation @ExceptionHandler.

The @ExceptionHandler annotation is used for handling exceptions in specific handler classes and/or handler methods.

1. Spring @ExceptionHandler

To handle exceptions in Spring MVC, we can define a method in @Controller class and use the annotation @ExceptionHandler on it. Spring configuration will detect this annotation and register the method as an exception handler for the argument exception class and its subclasses.

@Controller public class PageController < @RequestMapping(value = "/", method = RequestMethod.GET) public ModelAndView getPage(@PathVariable("id") String id) throws Exception < Page page = . ; if(page == null) < throw new RecordNotException("Page not found for id : " + id); >return new ModelAndView("index"); > @ExceptionHandler(NullPointerException.class) public ModelAndView handleException(NullPointerException ex) < ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("error"); modelAndView.addObject("message", ex.getMessage()); return modelAndView; >@ExceptionHandler(RecordNotException.class) public ModelAndView handleException(RecordNotException ex) < . return modelAndView; >>

Now every time, the controller encounter NullPointerException in request processing for any web request in this controller, control will automatically come to this handler method.

Handler methods that are annotated with this annotation are allowed to have very flexible signatures. They can accept arguments of different types. For example, an exception argument, request and/or response objects, session object, locale object and model object etc.

@ExceptionHandler(NullPointerException.class) public ModelAndView handleException(NullPointerException ex, HttpServletRequest request, Model model)

Similar to arguments, return types can be of different types. For example, ModelAndView object, Model object, View object, view name as String etc. We can mark the method to void also if the method handles the response itself by writing the response content directly to HttpServletResponse .

Читайте также:  Java jdbc postgresql пример

We may combine the ExceptionHandler annotation with @ResponseStatus for a specific HTTP error status.

@ExceptionHandler(AjaxException.class) @ResponseBody public ErrorResponse handleException(AjaxException ex, HttpServletResponse response)

2. Handling Multiple Exceptions

As mentioned earlier, the above exception handler will handle all exceptions, either instance of a given class or sub-classes of argument exceptions. But, if we want to configure @ExceptionHandler for multiple exceptions of different types, then we can specify all such exceptions in form of an array.

@ExceptionHandler() public ModelAndView handleException(Exception ex)

3. Global @ExceptionHandler with @ControllerAdvice

If we want to centralize the exception-handling logic to one class that is capable of handling exceptions thrown from any handler class/ controller class – then we can use @ControllerAdvice annotation.

By default, the methods in an @ControllerAdvice apply globally to all controllers. We can create a class and add @ControllerAdvice annotation on top. Then add @ExceptionHandler methods for each type of specific exception class in it.

Notice we extended the exception handler class with ResponseEntityExceptionHandler. It is a convenient base class for @ControllerAdvice classes that wish to provide centralized exception handling across all @RequestMapping methods through @ExceptionHandler methods.

@ControllerAdvice public class CustomExceptionHandler extends ResponseEntityExceptionHandler < @ExceptionHandler(Exception.class) public final ResponseEntityhandleAllExceptions(Exception ex, WebRequest request) < Listdetails = new ArrayList<>(); details.add(ex.getLocalizedMessage()); ErrorResponse error = new ErrorResponse(ApplicationConstants.SERVER_ERROR, details); return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); > @ExceptionHandler(RecordNotFoundException.class) public final ResponseEntity handleUserNotFoundException(RecordNotFoundException ex, WebRequest request) < Listdetails = new ArrayList<>(); details.add(ex.getLocalizedMessage()); ErrorResponse error = new ErrorResponse(ApplicationConstants.RECORD_NOT_FOUND, details); return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); > >

Where supporting classes are. This is for example only. Please create your application-specific exception and handle them.

@ResponseStatus(HttpStatus.NOT_FOUND) public class RecordNotFoundException extends RuntimeException < private static final long serialVersionUID = 1L; public RecordNotFoundException(String exception) < super(exception); >>
public class ErrorResponse < private String message; private Listdetails; >

For the demo, the below handler method is intentionally returning NullPointerException .

@RequestMapping(value="/demo/not-exist", method = RequestMethod.GET, headers="Accept=*/*") public @ResponseBody ModelAndView oneFaultyMethod() < if(true) < throw new NullPointerException("This error message if for demo only."); >return null; >

If we deploy the above application and hit the URL [/SpringApplication/users/demo/not-exist] in the browser, it will show the “error” page as configured in the first section.

 < %@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> < %@ taglib prefix="x" uri="http://java.sun.com/jstl/xml" %> < %@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> < %@ taglib prefix="sql" uri="http://java.sun.com/jstl/sql" %>    

This is sample error page :

Below will be the output in the browser.

Источник

Обработка исключений в контроллерах Spring Boot

Java-университет

СОДЕРЖАНИЕ ЦИКЛА СТАТЕЙ И снова здравствуйте! Пришло время стряхнуть пыль с клавиатуры. Создаем spring-boot проект. Из зависимостей мавена нам нужны:

  1.8 1.8 1.8  org.springframework.boot spring-boot-starter-parent 2.2.0.RELEASE   org.springframework.boot spring-boot-starter-web   

Обработка исключений в контроллерах Spring Boot - 1

Прежде чем читать дальше, создайте структуру проекта: BusinessException и CustomException:

 public class BusinessException extends Exception < public BusinessException(String message) < super(message); >> public class CustomException extends Exception < public CustomException(String message) < super(message); >> 
 public class Response < private String message; public Response() < >public Response(String message) < this.message = message; >public String getMessage() < return message; >public void setMessage(String message) < this.message = message; >> 

А теперь, я сделаю финт ушами, и передам слово Алексею Кутепову, в своей статье Обработка исключений в контроллерах Spring он нам расскажет, как эти файлы наполнить правильным содержимым. Читайте не торопясь, все примеры аккуратно переписываете к себе в проект, запускайте и тестируйте в постмане. Если в статье Алексея, у вас вызвала вопросы следующая строчка: produces = APPLICATION_JSON_VALUE, то знайте, что к обработке исключений она отношения не имеет, она говорит, что по умолчанию все методы этого контроллера будут отдавать JSON. При необходимости в конкретном методе это значение можно переопределить на другой MediaType Если вы прочитали, идем дальше. В предлагаемой выше статье рассмотрены разные варианты обработчиков. Самый гибкий из них: @ControllerAdvice – он позволяет изменить как код, так и тело стандартного ответа при ошибке. Кроме того, он позволяет в одном методе обработать сразу несколько исключений. Но это еще не все, если вы прочитаете дальше, то получите улучшенный @ControllerAdvice совершенно бесплатно. Проведем подготовительные работы: хочу что бы в ответе выводились как кастомное так и стандартное сообщения об ошибке. Для этого внесем изменение в класс Response: добавим еще одно поле

 private String debugMessage; 
 public Response(String message, String debugMessage)
 @RestController public class Example7Controller < @GetMapping(value = "/testExtendsControllerAdvice") public ResponseEntitytestExtendsControllerAdvice(@RequestBody Response response) < return ResponseEntity.ok(response); >> 

В ответ получим статус 400 (если забыли, что он значит, гляньте в интернете) и пустое тело ответа. Конечно же, никого это не устраивает, давайте с этим бороться. Ранее мы создавали @ControllerAdvice с нуля, но в Spring Boot существует заготовка – ResponseEntityExceptionHandler. В ней уже обработаны многие исключения, например: NoHandlerFoundException, HttpMessageNotReadableException, MethodArgumentNotValidException и другие. Данный класс занимается обработкой ошибок. У него куча методов, название которых построено по принципу handle + название исключения. Если мы хотим обработать какое-то базовое исключение, то наследуемся от этого класса и переопределяем нужный метод. Доработаем класс дефолтного эдвайса

 @ControllerAdvice public class DefaultAdvice extends ResponseEntityExceptionHandler(response, HttpStatus.OK); > //Небольшое отступление: В обработчике выше, обратите внимание на HttpStatus.OK, //он может быть и HttpStatus.BAD_REQUEST или другим, тут ограничений нет, //попробуйте поменять статусы и потестить этот обработчик @Override//переопределили метод родительского класса protected ResponseEntity handleHttpMessageNotReadable (HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) < Response response = new Response("Не правильный JSON",ex.getMessage()); return new ResponseEntity<>(response, status); > > 

Как вы заметили, был переопределен обработчик, отвечающий за HttpMessageNotReadableException. Это исключение возникает тогда, когда тело запроса, приходящего в метод контроллер, нечитаемое – например, некорректный JSON. За это исключение отвечает метод handleHttpMessageNotReadable(). Еще раз сделаем запрос с некорректным JSON: на http://localhost:8080/testExtendsControllerAdvice

Теперь ответ содержит не только корректный код, но и тело с информативными сообщениями. Проверим как работает с корректным JSON Запрос:

Если честно, мне не нравиться что в ответе есть поле со значением null, сейчас быстренько это исправим. Переходим в класс Response и ставим аннотацию над нужным полем

 @JsonInclude(JsonInclude.Include.NON_NULL) private String debugMessage; 

Благодаря аннотации @JsonInclude(JsonInclude.Include.NON_NULL) это поле будет включено в ответ только в том случае, если мы его зададим. @JsonInclude входит в библиотеку аннотаций Jackson, очень полезно знать, что она может. Вот две статьи на выбор: Джексон аннотации. Автор переводил, но не допереводил, гугл транслит отлично справиться. Валидация Необходимо дополнить эту тему таким понятием как валидация. Просто говоря, это проверка что объект это тот объект который мы ожидаем. Например: если мы в приложении «Телефонный справочник» должны проверять наличие телефонных номеров в БД, то прежде чем лезть в базу, логично проверять, а не ввел ли пользователь вместо цифр буквы. Три статьи по валидации, по возврастанию сложности: Валидация бинов в Spring Настройка валидации DTO в Spring Framework Валидация данных в Spring Boot С теорией, на сегодня закончили. Для тренировки предлагаю следующее задание: Необходимо реализовать приложение NightclubBouncer (Вышибала ночного клуба). Требования: 1) Приложение должно принимать на вход JSON и делать запись в базу данных. Пример JSON:

И в теле ответа должна быть надпись: Welcome + name ! 2) У приложения должны быть реализованы методы: — вывод записи по id из БД в клиент (Postman). — удаление записи по полю: name. 3) Должен быть реализован маппинг из слоя dto в entity и обратно. 4) Приложение должно выбрасывать ошибку KickInTheAssException (ее нужно разработать самим) если поле status, во входящем JSON не равно: super star 5) Ошибка KickInTheAssException должна обрабатываться ControllerAdvice, и в теле ответа должно быть сообщение: «Don’t let me see you here again!». Статус ответа должен быть 400. 6) Стандартная ошибка EntityNotFoundException, возникающая, например, если в клуб зашла только Кэти Пери и сохранилась в базу с id = 1, а вы вызвали метод «вывод записи по id» и захотели вывести запись с id = 2, которой нет в базе. Эту ошибку необходимо обработать переопределенным методом класса ResponseEntityExceptionHandler, каким именно — предстоит разобраться вам самим. Ответ должен иметь соответствующий статус. 7) Сделайте валидацию: простой вариант — поля JSON должны быть не null, по сложнее поле «name» должно состоять из двух слов латинского алфавита и они оба должны начинаться с заглавной буквы. Невалидные значения должны вызывать исключение, обработайте его любым способом, выведите соотвествующий код ошибки и сообщение об ошибке: No validate. И реализуйте это все без использования библиотеки Lombok, не включайте ее в зависимости проекта 😅

Источник

Оцените статью