Spring Boot @ExceptionHandler
last modified July 16, 2023
Spring Boot @ExceptionHandler tutorial shows how to handle exceptions with Spring @ExceptionHandler.
Spring is a popular Java application framework and Spring Boot is an evolution of Spring that helps create stand-alone, production-grade Spring based applications easily.
@ExceptionHandler is an annotation for handling exceptions in
specific handler classes or handler methods. In Servlet environments, we can
combine the @ExceptionHandler annotation with
@ResponseStatus to define the response status for the HTTP
response.
Spring Boot @ExceptionHandler example
In the following application, we demonstrate the usage of the
@ExceptionHandler. A HTML link in the home page calls a
controller's method, which either returns data or throws an exception.
build.gradle
...
src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── MyController.java
│ │ ├── exception
│ │ │ └── MyDataException.java
│ │ └── service
│ │ ├── IDataService.java
│ │ └── MyDataService.java
│ └── resources
│ ├── static
│ │ ├── index.html
│ │ └── showError.html
│ └── templates
│ └── showData.ftlh
└── test
├── java
└── resources
This is the project structure of the Spring application.
plugins {
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
id 'java'
}
group = 'com.zetcode'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
}
This is the Gradle build file. The spring-boot-starter-freemarker
is a dependency for Freemarker template engine.
package com.zetcode.controller;
import com.zetcode.exception.MyDataException;
import com.zetcode.service.IDataService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.Map;
@Controller
public class MyController {
private final IDataService dataService;
public MyController(IDataService dataService) {
this.dataService = dataService;
}
@RequestMapping(value = "/getData")
public ModelAndView getData() {
var data = dataService.findAll();
Map<String, Object> params = new HashMap<>();
params.put("values", data);
return new ModelAndView("showData", params);
}
@ExceptionHandler(MyDataException.class)
public String handleError(MyDataException e) {
return "redirect:/showError.html";
}
}
The MyController's getData method calls a service
method and stores the retrieved data into a list. The data is sent to the
showData view. In case of a MyDataException, the
controller redirects to an error page.
@ExceptionHandler(MyDataException.class)
public String handleError(MyDataException e) {
return "redirect:/showError.html";
}
The handleError is decorated with @ExceptionHandler.
The handler is activated for the MyDataException. In the body of
the method, we redirect to the showError.html page.
package com.zetcode.exception;
public class MyDataException extends RuntimeException {
public MyDataException(String message) {
super(message);
}
}
We define a custom MyDataException.
package com.zetcode.service;
import java.util.List;
public interface IDataService {
List<String> findAll();
}
IDataService contains the contract method.
package com.zetcode.service;
import com.zetcode.exception.MyDataException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.springframework.stereotype.Service;
@Service
public class MyDataService implements IDataService {
@Override
public List<String> findAll() {
var r = new Random();
if (r.nextBoolean()) {
throw new MyDataException("Failed to retrieve data");
}
var data = new ArrayList<String>();
data.add("yellow moon");
data.add("brisk pace");
data.add("empty bottle");
data.add("beautiful weather");
return data;
}
}
MyDataService implements IDataService's
findAll method. The method either returns data or throws a
MyDataException.
var r = new Random();
if (r.nextBoolean()) {
throw new MyDataException("Failed to retrieve data");
}
The findAll method randomly throws MyDataException.
The exception is then handled in the controller.
var data = new ArrayList<>();
data.add("yellow moon");
data.add("brisk pace");
data.add("empty bottle");
data.add("beautiful weather");
return data;
When there is no exception, we return a list of strings.
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<a href="/getData">Get data</a>
</body>
</html>
This is the home page. It contains a link that calls our controller method to fetch some data.
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>Failed to retrieve data</p>
</body>
</html>
This is an error page. It is shown when MyDataException is thrown.
<!DOCTYPE html>
<html>
<head>
<title>Data</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>Data</h2>
<ul>
<#list values as val>
<li><td>${val}</td></li>
</#list>
</ul>
</body>
</html>
The showData.ftlh is a Freemarker template file which shows all
retrieved data in an HTML list.
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application is the entry point which bootstraps Spring Boot
application.
In this article we have shown how to handle exceptions in a Spring application
with @ExceptionHandler.