Spring Boot Exception Handling
Abid Anjum
Senior Full Stack Developer Architect | Java Spring Boot Microservices | Angular & React | Mobile Apps Engineer Android IOS Flutter | Asp.net Core C# | BI Expert | GIS Expertise
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.
pom.xml
src
├── main
│ ├── java
│ │ └── com
│ │ └── anjum
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── MyController.java
│ │ ├── exception
│ │ │ └── MyDataException.java
│ │ └── service
│ │ ├── IDataService.java
│ │ └── MyDataService.java
│ └── resources
│ ├── static
│ │ ├── index.html
│ │ └── showError.html
│ └── templates
│ └── showData.ftl
└── test
└── java
This is the project structure of the Spring application.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.anjum</groupId>
<artifactId>springbootexceptionhandlerex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
com/anjum/controller/MyController.java
package com.aanjum.controller;
import com.anjum.exception.MyDataException;
import com.anjum.service.IDataService;
import org.springframework.beans.factory.annotation.Autowired;
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 {
@Autowired
private IDataService 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
com/anjum/exception/MyDataException.java
package com.anjum.exception;
public class MyDataException extends RuntimeException {
public MyDataException(String message) {
super(message);
}
}
We define a custom?MyDataException.
com/anjum/service/IDataService.java
package com.anjum.service;
import java.util.List;
public interface IDataService {
List<String> findAll();
}
IDataService?contains the contract method.
领英推荐
com/anjum/service/MyDataService.java
package com.anjum.service;
import com.anjum.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.
resources/static/index.html
<!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.
resources/static/showError.html
<!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.
resources/templates/showData.ftl
<!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>${val}</td>
</#list>
</ul>
</body>
</html>
The?showData.ftl?is a Freemarker template file which shows all retrieved data in an HTML list.
com/anjum/Application.java
package com.anjum;
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 tutorial, we have shown how to handle exceptions in a Spring application with?@ExceptionHandler