Обработка ошибок spring mvc

Время на прочтение
9 мин

Количество просмотров 72K

image

Часто на практике возникает необходимость централизованной обработки исключений в рамках контроллера или даже всего приложения. В данной статье разберём основные возможности, которые предоставляет Spring Framework для решения этой задачи и на простых примерах посмотрим как всё работает. Кому интересна данная тема — добро пожаловать под кат!

Изначально до Spring 3.2 основными способами обработки исключений в приложении были HandlerExceptionResolver и аннотация @ExceptionHandler. Их мы ещё подробно разберём ниже, но они имеют определённые недостатки. Начиная с версии 3.2 появилась аннотация @ControllerAdvice, в которой устранены ограничения из предыдущих решений. А в Spring 5 добавился новый класс ResponseStatusException, который очень удобен для обработки базовых ошибок для REST API.

А теперь обо всём по порядку, поехали!

Обработка исключений на уровне контроллера — @ExceptionHandler

С помощью аннотации @ExceptionHandler можно обрабатывать исключения на уровне отдельного контроллера. Для этого достаточно объявить метод, в котором будет содержаться вся логика обработки нужного исключения, и проаннотировать его.

В качестве примера разберём простой контроллер:

@RestController
public class Example1Controller {

    @GetMapping(value = "/testExceptionHandler", produces = APPLICATION_JSON_VALUE)
    public Response testExceptionHandler(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testExceptionHandler");
        }
        return new Response("OK");
    }

    @ExceptionHandler(BusinessException.class)
    public Response handleException(BusinessException e) {
        return new Response(e.getMessage());
    }

}

Тут я сделал метод testExceptionHandler, который вернёт либо исключение BusinessException, либо успешный ответ — всё зависит от того что было передано в параметре запроса. Это нужно для того, чтобы можно было имитировать как штатную работу приложения, так и работу с ошибкой.

А вот следующий метод handleException предназначен уже для обработки ошибок. У него есть аннотация @ExceptionHandler(BusinessException.class), которая говорит нам о том что для последующей обработки будут перехвачены все исключения типа BusinessException. В аннотации @ExceptionHandler можно прописать сразу несколько типов исключений, например так: @ExceptionHandler({BusinessException.class, ServiceException.class}).

Сама обработка исключения в данном случае примитивная и сделана просто для демонстрации работы метода — по сути вернётся код 200 и JSON с описанием ошибки. На практике часто требуется более сложная логика обработки и если нужно вернуть другой код статуса, то можно воспользоваться дополнительно аннотацией @ResponseStatus, например @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR).

Пример работы с ошибкой:

Пример штатной работы:

Основной недостаток @ExceptionHandler в том что он определяется для каждого контроллера отдельно, а не глобально для всего приложения. Это ограничение можно обойти если @ExceptionHandler определен в базовом классе, от которого будут наследоваться все контроллеры в приложении, но такой подход не всегда возможен, особенно если перед нами старое приложение с большим количеством легаси.

Обработка исключений с помощью HandlerExceptionResolver

HandlerExceptionResolver является общим интерфейсом для обработчиков исключений в Spring. Все исключений выброшенные в приложении будут обработаны одним из подклассов HandlerExceptionResolver. Можно сделать как свою собственную реализацию данного интерфейса, так и использовать существующие реализации, которые предоставляет нам Spring из коробки. Давайте разберем их для начала:

ExceptionHandlerExceptionResolver — этот резолвер является частью механизма обработки исключений с помощью аннотации @ExceptionHandler, о которой я уже упоминал ранее.

DefaultHandlerExceptionResolver — используется для обработки стандартных исключений Spring и устанавливает соответствующий код ответа, в зависимости от типа исключения:

Основной недостаток заключается в том что возвращается только код статуса, а на практике для REST API одного кода часто не достаточно. Желательно вернуть клиенту еще и тело ответа с описанием того что произошло. Эту проблему можно решить с помощью ModelAndView, но не нужно, так как есть способ лучше.

ResponseStatusExceptionResolver — позволяет настроить код ответа для любого исключения с помощью аннотации @ResponseStatus.

В качестве примера я создал новый класс исключения ServiceException:

@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public class ServiceException extends Exception {

    public ServiceException(String message) {
        super(message);
    }

}

В ServiceException я добавил аннотацию @ResponseStatus и в value указал что данное исключение будет соответствовать статусу INTERNAL_SERVER_ERROR, то есть будет возвращаться статус-код 500.

Для тестирования данного нового исключения я создал простой контроллер:

@RestController
public class Example2Controller {

    @GetMapping(value = "/testResponseStatusExceptionResolver", produces = APPLICATION_JSON_VALUE)
    public Response testResponseStatusExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws ServiceException {
        if (exception) {
            throw new ServiceException("ServiceException in testResponseStatusExceptionResolver");
        }
        return new Response("OK");
    }

}

Если отправить GET-запрос и передать параметр exception=true, то приложение в ответ вернёт 500-ю ошибку:

Из недостатков такого подхода — как и в предыдущем случае отсутствует тело ответа. Но если нужно вернуть только код статуса, то @ResponseStatus довольно удобная штука.

Кастомный HandlerExceptionResolver позволит решить проблему из предыдущих примеров, наконец-то можно вернуть клиенту красивый JSON или XML с необходимой информацией. Но не спешите радоваться, давайте для начала посмотрим на реализацию.

В качестве примера я сделал кастомный резолвер:

@Component
public class CustomExceptionResolver extends AbstractHandlerExceptionResolver {

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
        if (ex instanceof CustomException) {
            modelAndView.setStatus(HttpStatus.BAD_REQUEST);
            modelAndView.addObject("message", "CustomException was handled");
            return modelAndView;

        }
        modelAndView.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
        modelAndView.addObject("message", "Another exception was handled");
        return modelAndView;
    }

}

Ну так себе, прямо скажем. Код конечно работает, но приходится выполнять всю работу руками: сами проверяем тип исключения, и сами формируем объект древнего класса ModelAndView. На выходе конечно получим красивый JSON, но в коде красоты явно не хватает.

Такой резолвер может глобально перехватывать и обрабатывать любые типы исключений и возвращать как статус-код, так и тело ответа. Формально он даёт нам много возможностей и не имеет недостатков из предыдущих примеров. Но есть способ сделать ещё лучше, к которому мы перейдем чуть позже. А сейчас, чтобы убедиться что всё работает — напишем простой контроллер:

@RestController
public class Example3Controller {

    @GetMapping(value = "/testCustomExceptionResolver", produces = APPLICATION_JSON_VALUE)
    public Response testCustomExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws CustomException {
        if (exception) {
            throw new CustomException("CustomException in testCustomExceptionResolver");
        }
        return new Response("OK");
    }

}

А вот и пример вызова:

Видим что исключение прекрасно обработалось и в ответ получили код 400 и JSON с сообщением об ошибке.

Обработка исключений с помощью @ControllerAdvice

Наконец переходим к самому интересному варианту обработки исключений — эдвайсы. Начиная со Spring 3.2 можно глобально и централизованно обрабатывать исключения с помощью классов с аннотацией @ControllerAdvice.

Разберём простой пример эдвайса для нашего приложения:

@ControllerAdvice
public class DefaultAdvice {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        Response response = new Response(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

}

Как вы уже догадались, любой класс с аннотацией @ControllerAdvice является глобальным обработчиком исключений, который очень гибко настраивается.
В нашем случае мы создали класс DefaultAdvice с одним единственным методом handleException. Метод handleException имеет аннотацию @ExceptionHandler, в которой, как вы уже знаете, можно определить список обрабатываемых исключений. В нашем случае будем перехватывать все исключения BusinessException.

Можно одним методом обрабатывать и несколько исключений сразу: @ExceptionHandler({BusinessException.class, ServiceException.class}). Так же можно в рамках эдвайса сделать сразу несколько методов с аннотациями @ExceptionHandler для обработки разных исключений.
Обратите внимание, что метод handleException возвращает ResponseEntity с нашим собственным типом Response:

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;
    }

}

Таким образом у нас есть возможность вернуть клиенту как код статуса, так и JSON заданной структуры. В нашем простом примере я записываю в поле message описание ошибки и возвращаю HttpStatus.OK, что соответствует коду 200.

Для проверки работы эдвайса я сделал простой контроллер:

@RestController
public class Example4Controller {

    @GetMapping(value = "/testDefaultControllerAdvice", produces = APPLICATION_JSON_VALUE)
    public Response testDefaultControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testDefaultControllerAdvice");
        }
        return new Response("OK");
    }

}

В результате, как и ожидалось, получаем красивый JSON и код 200:

А что если мы хотим обрабатывать исключения только от определенных контроллеров?
Такая возможность тоже есть! Смотрим следующий пример:

@ControllerAdvice(annotations = CustomExceptionHandler.class)
public class CustomAdvice {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        String message = String.format("%s %s", LocalDateTime.now(), e.getMessage());
        Response response = new Response(message);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

}

Обратите внимание на аннотацию @ControllerAdvice(annotations = CustomExceptionHandler.class). Такая запись означает что CustomAdvice будет обрабатывать исключения только от тех контроллеров, которые дополнительно имеют аннотацию @CustomExceptionHandler.

Аннотацию @CustomExceptionHandler я специально сделал для данного примера:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomExceptionHandler {
}

А вот и исходный код контроллера:

@RestController
@CustomExceptionHandler
public class Example5Controller {

    @GetMapping(value = "/testCustomControllerAdvice", produces = APPLICATION_JSON_VALUE)
    public Response testCustomControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testCustomControllerAdvice");
        }
        return new Response("OK");
    }

}

В контроллере Example5Controller присутствует аннотация @CustomExceptionHandler, а так же на то что выбрасывается то же исключение что и в Example4Controller из предыдущего примера. Однако в данном случае исключение BusinessException обработает именно CustomAdvice, а не DefaultAdvice, в чём мы легко можем убедиться.

Для наглядности я немного изменил сообщение об ошибке в CustomAdvice — начал добавлять к нему дату:

На этом возможности эдвайсов не заканчиваются. Если мы посмотрим исходный код аннотации @ControllerAdvice, то увидим что эдвайс можно повесить на отдельные типы или даже пакеты. Не обязательно создавать новые аннотации или вешать его на уже существующие.

Исключение ResponseStatusException.

Сейчас речь пойдёт о формировании ответа путём выброса исключения ResponseStatusException:

@RestController
public class Example6Controller {

    @GetMapping(value = "/testResponseStatusException", produces = APPLICATION_JSON_VALUE)
    public Response testResponseStatusException(@RequestParam(required = false, defaultValue = "false") boolean exception) {
        if (exception) {
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "ResponseStatusException in testResponseStatusException");
        }
        return new Response("OK");
    }

}

Выбрасывая ResponseStatusException можно также возвращать пользователю определённый код статуса, в зависимости от того, что произошло в логике приложения. При этом не нужно создавать кастомное исключение и прописывать аннотацию @ResponseStatus — просто выбрасываем исключение и передаём нужный статус-код. Конечно тут возвращаемся к проблеме отсутствия тела сообщения, но в простых случаях такой подход может быть удобен.

Пример вызова:

Резюме: мы познакомились с разными способами обработки исключений, каждый из которых имеет свои особенности. В рамках большого приложения можно встретить сразу несколько подходов, но при этом нужно быть очень осторожным и стараться не переусложнять логику обработки ошибок. Иначе получится что какое-нибудь исключение обработается не в том обработчике и на выходе ответ будет отличаться от ожидаемого. Например если в приложении есть несколько эдвайсов, то при создании нового нужно убедиться, что он не сломает существующий порядок обработки исключений из старых контроллеров.
Так что будьте внимательны и всё будет работать замечательно!

Ссылка на исходники из статьи

Prerequisites: Spring MVC

When something goes wrong with your application, the server displays an exception page defining the type of exception, the server-generated exception page is not user-friendly. Spring MVC provides exception handling for your web application to make sure you are sending your own exception page instead of the server-generated exception to the user. The @ExceptionHandler annotation is used to detect certain runtime exceptions and send responses according to the exception. In this article we’ll Spring Mvc project to show how to intercept and define exceptions, we’ll look at how to define method level as well as the class level exception.

Steps to Create the Application

First, create a maven project, we are using Eclipse IDE for this project. Now, search for webapp, as we are creating a web application. Choose to create maven while creating a new project and add a maven webapp archetype. Enter the group id and the artifact id for your project and click finish.

After clicking finish your project structure would look something like this:

The pom.xml is auto-created with any maven project, it defines all the dependencies required for the project. Make sure to add all the dependencies mentioned in this file.

XML

<?xml version="1.0" encoding="UTF-8"?>

  <modelVersion>4.0.0</modelVersion>

  <groupId>com.gfg</groupId>

  <artifactId>SpringMvcExceptionHandling</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>

  <name>SpringMvcExceptionHandling Maven Webapp</name>

  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <maven.compiler.source>1.7</maven.compiler.source>

    <maven.compiler.target>1.7</maven.compiler.target>

  </properties>

  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.11</version>

      <scope>test</scope>

    </dependency>

    <dependency

        <groupId>org.springframework</groupId

        <artifactId>spring-webmvc</artifactId

        <version>5.1.1.RELEASE</version

    </dependency

    <dependency

        <groupId>org.apache.tomcat</groupId

        <artifactId>tomcat-jasper</artifactId

        <version>9.0.12</version

    </dependency

    <dependency>   

        <groupId>javax.servlet</groupId>   

        <artifactId>servlet-api</artifactId>   

        <version>3.0-alpha-1</version>   

    </dependency

    <dependency

        <groupId>javax.servlet</groupId

        <artifactId>jstl</artifactId

        <version>1.2</version

    </dependency

  </dependencies>

  <build>

    <finalName>SpringMvcExceptionHandling</finalName>

    <pluginManagement>

      <plugins>

        <plugin>

          <artifactId>maven-clean-plugin</artifactId>

          <version>3.1.0</version>

        </plugin>

        <plugin>

          <artifactId>maven-resources-plugin</artifactId>

          <version>3.0.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-compiler-plugin</artifactId>

          <version>3.8.0</version>

        </plugin>

        <plugin>

          <artifactId>maven-surefire-plugin</artifactId>

          <version>2.22.1</version>

        </plugin>

        <plugin>

          <artifactId>maven-war-plugin</artifactId>

          <version>3.2.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-install-plugin</artifactId>

          <version>2.5.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-deploy-plugin</artifactId>

          <version>2.8.2</version>

        </plugin>

      </plugins>

    </pluginManagement>

  </build>

</project>

The web.xml defines mapping with different URLs and servlets to handle requests for those URLs. 

XML

The gfg-servlet.xml file handles all HTTP requests for the web applications. The component scan locates and allocated beans according to the defined annotation. The annotation-driven enable the spring annotation classes. The bean configuration helps in identifying and scanning the JSP located in the views folder. 

XML

The Student class in the com.gfg.model defines the student object with three objects firstName, lastName, and rollNo. Notice that we have kept the roll number as a string instead of an integer, this will help us to check for possible NumberFormat exceptions.

Java

package com.gfg.model;

public class Student {

    private String firstName;

    private String lastName;

    private String rollNo;

    public Student(String firstName, String lastName,

                   String rollNo)

    {

        super();

        this.firstName = firstName;

        this.lastName = lastName;

        this.rollNo = rollNo;

    }

    public Student() {}

    public String getFirstName() { return firstName; }

    public void setFirstName(String firstName)

    {

        this.firstName = firstName;

    }

    public String getLastName() { return lastName; }

    public void setLastName(String lastName)

    {

        this.lastName = lastName;

    }

    public String getRollNo() { return rollNo; }

    public void setRollNo(String rollNo)

    {

        this.rollNo = rollNo;

    }

}

The LoginController class in the com.gfg.controller package defines two methods, the showForm method defines a Get mapping and simply shows the student login form. The processForm method has two parameters of @ModelAttribute for students and a Model to set attributes in our view pages. The model parameter sets all the attributes to the view page. Remember, in the Student class we defined rollNo as a String. Now, we will parse it into int: this will help in catching two NumberFormat exceptions. If the string is empty or the string has alphabets for both it will send a NumberFormatException. Now, to catch that exception and handle it separately for better user experience we define a method numberformatHandler and annotate it with the @ExceptionHandler, and set the value to NumberFormatException.class. So, this was a way to handle Exception at the method level.

Java

package com.gfg.controller;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ModelAttribute;

import org.springframework.web.bind.annotation.RequestMapping;

import com.gfg.model.Student;

@Controller

public class LoginController {

    @RequestMapping("/login")

    public String showForm(Model theModel) {

        theModel.addAttribute("student", new Student());

        return "portal";

    }

    @RequestMapping("/welcome")

    public String processForm(@ModelAttribute("welcome") Student student, Model mod) {   

        mod.addAttribute("FirstName", student.getFirstName());

        mod.addAttribute("LastName", student.getLastName());       

        int n = Integer.parseInt(student.getRollNo());

        mod.addAttribute("RollNo", n);   

        return "welcome";

    }

      @ExceptionHandler(value = NumberFormatException.class)

    public String numberformatHandler(Model theModel) {       

        theModel.addAttribute("err", "NumberFormatException");

        return "error";

    }

}

The  MyExceptionHandler class in the com.gfg.errorhandler defines all the exceptions for our application so that for a different kind of exception the user sees a proper and simple error page. To make it available for all the classes in our project we just have to add the annotation @ControllerAdvice, this will advise spring MVC to use our exception method instead of server-generated pages. So, In this we have defines an Exception Handler at the class level.

Java

package com.gfg.errorhandler;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice

public class MyExceptionHandler {

    @ExceptionHandler(value = NullPointerException.class)

    public String nullPointerHandler(Model theModel) {

        theModel.addAttribute("err", "NullPointerException");

        return "error";

    }

    @ExceptionHandler(value = Exception.class)

    public String AnyOtherHandler() {

        return "error";

    }

}

The portal.jsp file in the views folder defines the Student login portal. 

HTML

 <html

<head

</head

<body

    <h1>Student Portal</h1>

    <form:form action="welcome" modelAttribute="student"

       <label>First name:</label>

         <form:input path="firstName" />

        <br><br

         <label>Last name:</label>

         <form:input path="lastName" /> 

        <br><br>   

         <label>Roll No:</label>

          <form:input path="rollNo" />

         <br><br>   

        <input type="submit" value="Submit" /> 

    </form:form

</body

</html>

The welcome.jsp page in the views folder defines the welcome page for our application.

HTML

 <html

<head

</head

<body

    <h1>Student Portal</h1>

    <form:form action="welcome" modelAttribute="student"

       <label>First name:</label>

         <form:input path="firstName" />

        <br><br

         <label>Last name:</label>

         <form:input path="lastName" /> 

        <br><br>   

         <label>Roll No:</label>

          <form:input path="rollNo" />

         <br><br>   

        <input type="submit" value="Submit" /> 

    </form:form

</body

</html>

The error.jsp page is a simple exception handler page that defines the name of the exception and informs the user about an exception.

HTML

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

</head>

<body>

    <h1>Opps....</h1>

    <h1> ${err} Exception caused</h1>

</body>

</html>

After adding all the classes and configuration files your project would look something like this:

Now that we have completed our project, it’s time to run it on a tomcat server, just start the tomcat server and type http:localhost:8080/SpringMvcExceptionHandling/login

OutputOutputOutputOutputOutput

So, in this Spring MVC project, we defined exception handlers at the method as well as at class level and defined our own custom exception view page for better user experience.

Last Updated :
11 Mar, 2022

Like Article

Save Article

In this tutorial we take a look at how to use Spring MVC Exception Handling. We can design our application to deal with exceptions in various ways. We could handle the exceptions in the methods where they occur, but most of the time this leads to cluttered and duplicated exception handling code, so we are not showing you this. The following is an overview of what we’ll see in this article:

  • Handling controller local exceptions – We can catch the exceptions using a @ExceptionHandler locally in the controller. This will override any pre-defined global exception handler.
  • Global exception handler – Catch exceptions globally across all controllers.
  • Custom 404 response – Instead of the default 404 page, we return a JSON response containing a detailed message.
  • Custom error pages – Instead of showing the default error pages of your servlet container, we create a custom error page displaying the occurred error message.
  • Business Exceptions – by annotating custom business methods with @ResponseStatus spring automatically returns the status code defined in the annotation.

Spring MVC Exception Handling

To start, we are using the following Java Object to return a fault code together with a detailed message. As this class will be used across all examples, we show you this first. Later on we look at the previous examples into more detail.

package com.memorynotfound.model;

public class Error {

    private int code;
    private String message;

    public Error() {
    }

    public Error(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

Handling Controller Local Exceptions

Using Spring MVC we can handle the exceptions occurred in a controller locally. We have two options, either by annotating a method with the @ExceptionHandler annotation and provide the class of the exception that needs to be handled. Or, we can also implement the HandlerExceptionResolver where we need to implement the resolveException(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex), this method will resolve any exceptions occurred inside the controller methods.

Controller Local Exceptions with @ExceptionHandler

Here is an example how to handle exceptions locally in the controller they occurred. We annotate a method using the @ExceptionHandler annotation and provide the exception (or an array of exceptions) the method needs to handle. The more specific exception takes priority over the general one.

package com.memorynotfound.controller;

import com.memorynotfound.model.Error;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/courses")
public class CourseController {

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<Object> get(){
        throw new RuntimeException("courses not yet supported");
    }

    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Error> handle(RuntimeException ex){
        System.out.println("controller local exception handling @ExceptionHandler");
        Error error = new Error(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());
        return new ResponseEntity<Error>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }

}

The return type can be a String, which is interpreted as a view name, a ModelAndView object, a ResponseEntity, or you can also add the @ResponseBody to have the method return value converted with message converters and written to the response stream.

URL: http://localhost:8081/spring-mvc-controller-local-exception-handling/courses

spring mvc controller local exception handler

Controller local Exceptions with HandlerExceptionResolver

Here is an example implementing the HandlerExceptionResolver. By implementing this interface we must override the resolveException() method. This method will handle all exceptions thrown by the controller. In order to get the type of the exception, we need to do an instanceof operation.

package com.memorynotfound.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/students")
public class StudentController implements HandlerExceptionResolver {

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<Object> get(){
        throw new RuntimeException("students not yet supported");
    }

    @Override
    public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) {
        System.out.println("controller local exception handling HandlerExceptionResolver");

        resp.reset();
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/json");

        ModelAndView model = new ModelAndView(new MappingJackson2JsonView());
        if (ex instanceof RuntimeException){
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            model.addObject("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
            model.addObject("message", ex.getMessage());
        } else {
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            model.addObject("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
            model.addObject("message", ex.getMessage());
        }
        return model;
    }
}

In this example we return a JSON response by setting the view of the ModelAndView to an instance of the MappingJackson2JsonView class. We also add a status code to the response via the HttpServletResponse#setStatus() in order to tell the client some error has occurred.

URL: http://localhost:8081/spring-mvc-controller-local-exception-handling/students

spring mvc controller local exception handler

Global Exceptions Handler

The following example shows how to handle exceptions globally, across all controllers. This really encapsulates the DRY-principle. Because our exception handling code is located only in a single place.

package com.memorynotfound.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/courses")
public class CourseController {

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<Object> getList(){
        throw new RuntimeException("courses not yet supported");
    }

}

The @ExceptionHandler method becomes a global exception handler when we move this method in a separate class annotated with the @ControllerAdvice annotation. The ResponseEntityExceptionHandler is not mandatory but by using ResponseEntityExceptionHandler you can override the standard Spring MVC exceptions.

package com.memorynotfound.exception;

import com.memorynotfound.model.Error;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Error> handle(RuntimeException ex){
        Error error = new Error(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());
        return new ResponseEntity<Error>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }

}

URL: http://localhost:8081/spring-mvc-global-exception-handling/courses

spring mvc global exception handler example

Custom 404 Response

By default, when a page/resource does not exist the servlet container will throw a 404 page. When you are developing API’s and you want a custom 404 JSON response, here is how.

package com.memorynotfound.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
        final DispatcherServlet servlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
        servlet.setThrowExceptionIfNoHandlerFound(true);
        return servlet;
    }
}

We need to tell the DispatcherServlet to throw the exception if no handler is found. We can do this by setting the throwExceptionIfNoHandlerFound servlet initialization parameter to true. The previous code will set the property to true when you are configuring your servlet container using java configuration.

When using XML to configure the servlet container, you can set the property using the following code.

<servlet>
    <servlet-name>rest-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>throwExceptionIfNoHandlerFound</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>

Next, we catch the NoHandlerFoundException and return a custom error message containing an error code and detailed description.

package com.memorynotfound.exception;

import com.memorynotfound.model.Error;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.NoHandlerFoundException;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<Error> handle(NoHandlerFoundException ex){
        String message = "HTTP " + ex.getHttpMethod() + " for " + ex.getRequestURL() + " is not supported.";
        Error error = new Error(HttpStatus.NOT_FOUND.value(), message);
        return new ResponseEntity<Error>(error, HttpStatus.NOT_FOUND);
    }

}

URL: http://localhost:8081/spring-mvc-custom-404-response/not-found

spring mvc custom 404 JSON response example

Custom Error Pages

The following example shows how you can create custom error pages. Take a look at the CourseController, there are two controller methods registered. The first will throw a RuntimeException, the second will throw a ArithmeticException. We define a controller-local exception handler using the @ExceptionHandler annotation and return a ModelAndView containing the occurred exception and forward it to the error page.

package com.memorynotfound.controller;

import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@RestController
@RequestMapping("/courses")
public class CourseController {

    @RequestMapping(method = RequestMethod.GET)
    public String getList(){
        throw new RuntimeException("courses not yet supported");
    }

    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    public String get(@PathVariable int id){
        throw new ArithmeticException("cannot divide by zero");
    }

    @ExceptionHandler(RuntimeException.class)
    public ModelAndView handle(RuntimeException ex){
        ModelAndView model = new ModelAndView("error");
        model.addObject("exception", ex);
        return model;
    }

}

This is an example how to configure the SimpleMappingExceptionResolver using Java configuration. This resolver enables you to take the class name of any exception that might be thrown and map it to a view name.

@Bean
public SimpleMappingExceptionResolver exceptionResolver(){
    SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
    Properties exceptions = new Properties();
    exceptions.put(ArithmeticException.class, "error");
    resolver.setExceptionMappings(exceptions);
    return resolver;
}

This is an example how to configure the SimpleMappingExceptionResolver using XML configuration

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.ArithmeticException">error</prop>
        </props>
    </property>
 </bean>

The error.jsp page displays the occurred exception.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Spring MVC Exception Handling</title>
</head>
<body>

<h1>Spring MVC Exception Handling</h1>

${exception.message}

</body>
</html>

URL: http://localhost:8081/spring-mvc-custom-error-pages/courses

When we access the controller method, the page is forwarded to the error page displaying the occurred exception.

spring mvc custom error page

Custom Exceptions annotated with @ResponseStatus

You can annotate an exception with the @ResponseStatus. Here you can provide a status code and a detailed exception message. When the exception is raised, the ResponseStatusExceptionResolver handles it by setting the status of the response accordingly.

package com.memorynotfound.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Course not found")
public class CourseNotFoundException extends RuntimeException {

    public CourseNotFoundException() {
    }

}

You can just throw the exception inside the controller and the ResponseStatusExceptionResolver will handle it automatically.

package com.memorynotfound.controller;

import com.memorynotfound.exception.CourseNotFoundException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/courses")
public class CourseController {

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<Object> getList(){
        throw new CourseNotFoundException();
    }

}

URL: http://localhost:8081/spring-mvc-response-status/courses

When we access the controller, the following page is displayed.

spring mvc response status example

References

  • Spring MVC Documentation
  • @ControllerAdvice JavaDoc
  • @ExceptionHandler JavaDoc
  • ResponseEntityExceptionHandler JavaDoc
  • HandlerExceptionResolver JavaDoc
  • SimpleMappingExceptionResolver JavaDoc
  • @ResponseStatus JavaDoc

Download

Download it –

  • spring-mvc-global-exception-handler-example
  • spring-mvc-custom-error-page-example
  • spring-mvc-custom-404-response-example
  • spring-mvc-controller-local-exception-handling-example
  • spring-mvc-handling-business-exceptions-example

<?xml version=«1.0» encoding=«UTF-8»?>

<project xmlns=«http://maven.apache.org/POM/4.0.0»

         xmlns:xsi=«http://www.w3.org/2001/XMLSchema-instance»

         xsi:schemaLocation=«http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd»>

    <modelVersion>4.0.0</modelVersion>

    <groupId>ru.javastudy</groupId>

    <artifactId>mvc_html5_angular</artifactId>

    <version>1.0</version>

    <properties>

        <! Generic properties >

        <java.version>1.8</java.version>

        <! Web >

        <jsp.version>2.2</jsp.version>

        <jstl.version>1.2</jstl.version>

        <servlet.version>3.1.0</servlet.version>

        <! Spring >

        <springframework.version>4.2.4.RELEASE</springframework.version>

        <! JUnit test >

        <junit.version>4.12</junit.version>

        <! Logging >

        <!logback improved version of log4j>

        <logback.version>1.0.13</logback.version>

        <slf4j.version>1.7.13</slf4j.version>

        <! jackson json JSON Processing API >

        <jackson.databindversion>2.2.3</jackson.databindversion>

        <! Hibernate / JPA >

        <hibernate.version>5.0.1.Final</hibernate.version>

        <! I dont know why, but with 5.0.5 final app not working! >

        <! Spring Data >

        <springframework.data.version>1.9.1.RELEASE</springframework.data.version>

    </properties>

    <dependencyManagement>

        <!all spring dependencies >

        <dependencies>

            <dependency>

                <groupId>org.springframework</groupId>

                <artifactId>springframeworkbom</artifactId>

                <version>${springframework.version}</version>

                <type>pom</type>

                <scope>import</scope>

            </dependency>

        </dependencies>

    </dependencyManagement>

    <!bootstrap webjars.org>

    <dependencies>

        <! Spring MVC >

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>springwebmvc</artifactId>

        </dependency>

        <! Other Servlet Web dependencies >

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>jstl</artifactId>

            <version>${jstl.version}</version>

        </dependency>

        <!Servlet API>

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>javax.servletapi</artifactId>

            <version>${servlet.version}</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet.jsp</groupId>

            <artifactId>jspapi</artifactId>

            <version>${jsp.version}</version>

            <scope>provided</scope>

        </dependency>

        <! Apache Commons File Upload >

        <dependency>

            <groupId>commonsfileupload</groupId>

            <artifactId>commonsfileupload</artifactId>

            <version>1.3.1</version>

        </dependency>

        <dependency>

            <groupId>commonsio</groupId>

            <artifactId>commonsio</artifactId>

            <version>2.4</version>

        </dependency>

        <! Excel view >

        <dependency>

            <groupId>org.apache.poi</groupId>

            <artifactId>poi</artifactId>

            <version>3.12</version>

        </dependency>

        <! PDF view >

        <dependency>

            <groupId>com.lowagie</groupId>

            <artifactId>itext</artifactId>

            <version>2.1.5</version>

        </dependency>

        <! HSQLDB embedded database. Встроенная база данных>

        <dependency>

            <groupId>org.hsqldb</groupId>

            <artifactId>hsqldb</artifactId>

            <version>2.3.3</version>

        </dependency>

        <! Spring JDBC >

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>springjdbc</artifactId>

        </dependency>

        <!JUnit Test>

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>${junit.version}</version>

            <scope>test</scope>

        </dependency>

        <! Test Artifacts with Spring>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>springtest</artifactId>

            <scope>test</scope>

        </dependency>

        <! Logging with SLF4J & LogBack >

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4japi</artifactId>

            <version>${slf4j.version}</version>

            <scope>compile</scope>

        </dependency>

        <dependency>

            <groupId>ch.qos.logback</groupId>

            <artifactId>logbackclassic</artifactId>

            <version>${logback.version}</version>

            <scope>runtime</scope>

        </dependency>

        <!Contains org.springframework.mail.javamail>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>springcontextsupport</artifactId>

            <version>${springframework.version}</version>

        </dependency>

        <! Spring MVC Mail Related Dependency >

        <dependency>

            <groupId>javax.mail</groupId>

            <artifactId>mail</artifactId>

            <version>1.4.7</version>

        </dependency>

        <dependency>

            <groupId>org.apache.velocity</groupId>

            <artifactId>velocity</artifactId>

            <version>1.7</version>

        </dependency>

        <! Spring REST jackson JSON Processing API >

        <dependency>

            <groupId>com.fasterxml.jackson.core</groupId>

            <artifactId>jacksondatabind</artifactId>

            <version>${jackson.databindversion}</version>

        </dependency>

        <!Hibernate ORM>

        <dependency>

            <groupId>org.hibernate</groupId>

            <artifactId>hibernateentitymanager</artifactId>

            <version>${hibernate.version}</version>

        </dependency>

        <!Hibernate validator (contains @NotEmpty)>

        <dependency>

            <groupId>org.hibernate</groupId>

            <artifactId>hibernatevalidator</artifactId>

            <version>5.1.0.Final</version>

        </dependency>

        <!Spring Data>

        <dependency>

            <groupId>org.springframework.data</groupId>

            <artifactId>springdatajpa</artifactId>

            <version>${springframework.data.version}</version>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>mavencompilerplugin</artifactId>

                <version>3.0</version>

                <configuration>

                    <source>1.8</source>

                    <target>1.8</target>

                    <compilerArgument>Xlint:all</compilerArgument>

                    <showWarnings>true</showWarnings>

                    <showDeprecation>true</showDeprecation>

                </configuration>

            </plugin>

        </plugins>

        <!need to find configs in tests in package webinf like

        @ContextConfiguration(locations = {«classpath:/config/application-context.xml»

        >

        <testResources>

            <testResource>

                <directory>src/main/webapp/WEBINF/config</directory>

            </testResource>

        </testResources>

    </build>

</project>

Details
Written by  
Last Updated on 17 May 2020   |   Print  Email

This Spring tutorial helps you understand how to handle exceptions in a Spring MVC web application with code examples.

You know, in Spring MVC, unexpected exceptions might be thrown during execution of its controllers. Spring provides two approaches for handling these exceptions:

    • Using XML configuration: this is similar to exception handling in Servlet/JSP, by declaring a SimpleMappingExceptionResolverbean in Spring’s application context file and map exception types with view names. This approach applies to all controllers in the application.
    • Using exception handler method: Spring provides the @ExceptionHandler annotation type which is used to annotate a method to handle exceptions raised by the controller’s methods. This approach applies to only the controller in which the handler method is declared.

Let’s look at each approach in details.

 

1. Using XML configuration

This approach uses XML to configure exceptions handling declaratively. Consider the following bean declaration in Spring’s application context file:

<bean
	class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.ArithmeticException">MathError</prop>
		</props>
	</property>

</bean>

That will map any exceptions of type java.lang.ArithmeticException (or its sub types) to the view named MathError. During execution of a Spring controller, if such an exception is thrown, the client will be redirected to the mapped view. For example, if we configure a view resolver likes this:

<bean id="viewResolver"
	class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/WEB-INF/views/" />
	<property name="suffix" value=".jsp" />
</bean>

Then Spring will redirect the client to the page /WEB-INF/views/MathError.jsp in case a java.lang.ArithmeticException exception is thrown. Accessing the exception in the MathError.jsp page as follows:

Arithmetic Error: ${exception}

Assuming we have the following controller class:

@Controller
@RequestMapping("/doMath")
public class MathController {
	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView calculateSum(@RequestParam int a, @RequestParam int b) {
		ModelAndView model = new ModelAndView("MathResult");
		
		model.addObject("sum", (a + b));
		model.addObject("subtract", (a - b));
		model.addObject("multiply", (a * b));
		model.addObject("divide", (a / b));
		
		return model;
	}
}

The method calculateSum() will handle the request /doMath, it takes two numbers a and b from the request and calculates sum, subtract, multiply and divide of them. The results are added to the model of the view called “MathResult”. In this code, there are two possible exceptions:

    • Either a or b is not a number.
    • b is zero, so the operation a / b will throw a java.lang.ArithmeticException exception.

Following is code of the MathResult.jsp page:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sum Result</title>
</head>
<body>
	<center>
		<b>Sum: ${sum} </b><br/>
		<b>Subtract: ${subtract} </b><br/>
		<b>Multiply: ${multiply} </b><br/>
		<b>Divide: ${divide} </b><br/>
	</center>
</body>
</html>

Code of the MathError.jsp page:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Error</title>
</head>
<body>
	<h2>
		Mathematical Error: ${exception} <br/>
	</h2>
</body>
</html>

Output when testing the application with two numbers a = 2000 and b = 100:

test handling exception in Spring MVC

If we pass b = 0, then the MathError.jsp page will be displayed:

 

spring mvc exception handling - error thrown

We can configure a default error view for all exceptions which are not specified in the exceptionMappings property, by specifying a view name for the defaultErrorView property. For example:

<bean
	class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.ArithmeticException">MathError</prop>
		</props>
	</property>

	<property name="defaultErrorView" value="Error" />

</bean>

That tells Spring to redirect the client to the Error.jsp page if any exceptions other than the java.lang.ArithmeticException is thrown. Code of the Error.jsp page is similar to the MathError.jsp page:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Error</title>
</head>
<body>
	<h3>
		General Error: ${exception}
	</h3>
</body>
</html>

Output when testing the application with a = 2000 and b = ten (not a number):

spring mvc exception handling - error thrown 2

As we can see, the Error.jsp page is displayed because the exception thrown is of type TypeMismatchException, not ArithmeticException.

We also can specify multiple mappings for exception types — view names as follows:

<bean
	class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.ArithmeticException">MathError</prop>
			<prop key="java.io.IOException">IOError</prop>
		</props>
	</property>

</bean>

  

2. Using exception handler method

This approach uses the @ExceptionHandler annotation to annotate a method in controller class to handle exceptions raised during execution of the controller’s methods. Consider the following controller class:

@Controller
public class FileUploadController {
	
	@RequestMapping(value = "/uploadFile", method = RequestMethod.GET)
	public String doFileUpload(@RequestParam int a) throws IOException, SQLException {
		
		// handles file upload stuff...
		if (a == 1) {
			throw new IOException("Could not read upload file.");
		} else if (a == 2) {
			throw new SQLException("Database exception!!!");
		}
		
		return "done";
	}
	
	@ExceptionHandler({IOException.class, java.sql.SQLException.class})
	public ModelAndView handleIOException(Exception ex) {
		ModelAndView model = new ModelAndView("IOError");

		model.addObject("exception", ex.getMessage());
		
		return model;
	}
}

The method doFileUpload() may throw an IOException, and the handler method is declared as follows:

@ExceptionHandler(IOException.class)
public ModelAndView handleIOException(IOException ex) {
	ModelAndView model = new ModelAndView("IOError");

	model.addObject("exception", ex.getMessage());

	return model;
}

This handleIOException() method will be invoked whenever an exception of type java.io.IOException (or its sub types) is raised within the controller class. Spring will pass the exception object into the method’s argument.

Using exception handler method is very flexible, as it allows us doing some processing before returning to the error view. We can also pass additional information to the view’s model when necessary, for example:

model.addObject("info", "extra info for the exception");

It’s also possible to specify a list of exception classes in the @ExceptionHanlder annotation, for example:

@ExceptionHandler({IOException.class, java.sql.SQLException.class})
public ModelAndView handleIOException(Exception ex) {
	ModelAndView model = new ModelAndView("IOError");

	model.addObject("exception", ex.getMessage());

	return model;
}

If the exception being thrown is one of the types (or sub types) in the list, the annotated method will be invoked. In the code above, if the exception is either of type IOException or SQLException, then the handleIOException() method will be invoked.

3. Conclusion

Using XML configuration (declaration of SimpleMappingExceptionResolverbean) will apply exception handling rules for the entire application, whereas using handler method (annotated by @ExceptionHandler annotation) will have effect only within the enclosing controller class. The XML declaration approach takes precedence over the annotation approach, so if we declared a SimpleMappingExceptionResolverbean in Spring’s application context file, then any @ExceptionHandler annotations will be ignored.

 

Related Spring Tutorials:

  • Understand the core of Spring framework
  • Understand Spring MVC
  • Spring MVC Form Handling Tutorial
  • Spring MVC Form Validation Tutorial
  • Spring MVC with JdbcTemplate Example
  • Spring MVC + Spring Data JPA + Hibernate — CRUD Example
  • 14 Tips for Writing Spring MVC Controller
  • How to use log4j in Spring MVC

About the Author:

Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on Facebook and watch his Java videos you YouTube.

Add comment

Понравилась статья? Поделить с друзьями:
  • Обратная ошибка хиндсайта
  • Обращение гуманно ошибки исправлены друзья образованы история безнравственна
  • Обозначения ошибок на панели приборов газель
  • Обработка ошибок rust
  • Обратно идет дождь где ошибка