Spring Boot Controller-Based Exception Handler Examples
- Details
- Written by Nam Ha Minh
- Last Updated on 26 March 2022   |   Print Email
You know, Spring framework provides several ways which developers can use to handle exceptions in their applications. One of them is controller-based exception handing or exception handler per controller.
And in this guide, you will learn how to code controller-based exception handlers for your Spring applications.
1. Why Controller-based exception handling?
In this kind of exception handling, you write exception handling code in a separate handler method in a controller class. Then only matching exceptions thrown in that controller is handled by the exception handler method. The same exceptions thrown in other controllers are not handled.
The following code illustrates this approach:
The following code illustrates this approach: public class ControllerA { // normal handler methods... @ExceptionHandler(Exception1.class) public String handleException1() { // handle Exception1 in ControllerA } } public class ControllerB { // normal handler methods... @ExceptionHandler(Exception1.class) public String handleException1() { // handle Exception1 in ControllerB } }
You see, both ControllerA and ControllerB handles Exception1 in their separate handler method annotated with @ExceptionHandler annotation. So consider using controller-based exception handler if:
- the logics of handling an exception is very specific to a controller. It cannot be applied for the same exceptions thrown by other controllers.
- there’s only one controller in your application.
2. Exception Handler Examples in Spring Web Controller
Consider the following Spring web controller class that works with view template (JSP or Thymeleaf):
package net.codejava; @Controller public class AppController { @RequestMapping("/edit/{id}") public ModelAndView editProduct(Long id) { // code that may throw ProductNotFoundException } @RequestMapping("/delete/{id}") public String deleteProduct(Long id) { // code that may throw ProductNotFoundException } }
You see, in this controller, two handler methods have code that may throw ProductNotFoundException so we want to handle that exception right in this class, such as directing clients to a separate error view. For example, put an exception handler method as follows:
package net.codejava; @Controller public class AppController { // normal handler methods... @ExceptionHandler(ProductNotFoundException.class) public ModelAndView handleProductNotFoundError(Exception ex) { ModelAndView mav = new ModelAndView("productNotFound"); mav.addObject("message", ex.getLocalizedMessage()); return mav; } }
Here, you need to use @ExceptionHandler annotation for the exception handler method, and specify the type of exception this method will handle. It returns a view similar to a regular web controller, which is the productNotFound view name in this example. And you can access the exception object by declaring a parameter in the method signature.
You can also return a String of view name instead of a ModelAndView object, like this:
@ExceptionHandler(ProductNotFoundException.class) public String handleProductNotFoundError(Exception ex) { // code that handles exception return "ProductNotFound"; }
If you want to access the request and response object, you can declare additional parameters in the method signature. Below is another example:
@ExceptionHandler(ProductNotFoundException.class) public String handleProductNotFoundError( HttpServletRequest request, HttpServletResponse response, Exception ex) { // code that handles exception // code that uses request // code that uses response return "ProductNotFound"; }
In case you want to handle more than one exception, you can specify an array of exception classes like this:
@ExceptionHandler({Exception1.class, Exception2.class, Exception3.class})
3. Exception Handler Examples in Spring REST Controller
Handle exception in a Spring REST controller is slightly different. In addition to @ExceptionHandler annotation, you may need to use @ResponseStatus and @ResponseBody annotations, to specify HTTP status code and what to be sent in the response, respectively.
Consider the following Spring REST controller class:
@RestController public class EmployeeController { @GetMapping("/employees/{id}") EntityModel<Employee> one(@PathVariable Long id) { // code that may throw EmployeeNotFoundException } @PutMapping("/employees/{id}") ResponseEntity<?> replaceEmployee(@RequestBody Employee newEmployee, Long id) { // code that may throw EmployeeNotFoundException } @DeleteMapping("/employees/{id}") ResponseEntity<?> deleteEmployee(@PathVariable Long id) { // code that may throw EmployeeNotFoundException } }
You see, all three handler methods may throw EmployeeNotFoundException, so we want to handle this exception right inside this class. For example, put the following method into the controller class:
@ResponseBody @ExceptionHandler(EmployeeNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public String employeeNotFoundHandler( HttpServletRequest request, HttpServletResponse response, Exception ex) { // code that handles exception return ex.getMessage(); }
Let me explain this code. If, somehow, an EmployeeNotFoundException is thrown by this controller, the employeeNotFoundHandler() method will get invoked. You can access the request, response and exception objects as arguments of the method. This exception handler returns HTTP status 404 (Not Found) with the exception message is the content of the response.
You can return a JSON document in the exception handler, as shown below:
@ExceptionHandler(OrderNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) @ResponseBody ErrorInfo orderNotFoundHandler(HttpServletRequest request, Exception ex) { // code that handles exception... return new ErrorInfo(request.getRequestURL().toString(), ex); }
Here, Spring will serialize the ErrorInfo object to a corresponding JSON string as the response. Code of the ErrorInfo class is as follows:
public class ErrorInfo { private final String url; private final String ex; public ErrorInfo(String url, Exception ex) { this.url = url; this.ex = ex.getLocalizedMessage(); } // getters and setters are not shown, for brevity }
The client will get the JSON response like this:
{ "url": "http://localhost:8080/orders/823", "ex": "Could not find order ID 823" }
So far I have shared some code examples about handling exception in Spring applications with controller-based exception handler, for both Spring Web and Spring REST controllers. To see the coding in action, I recommend you watch the following video:
Related Tutorials:
- Spring Boot Error Handling Guide
- Spring Boot Global Exception Handler Examples
- How to handle exceptions in Spring MVC
Other Spring Boot Tutorials:
- Spring Boot automatic restart using Spring Boot DevTools
- Spring Boot Form Handling Tutorial with Spring Form Tags and JSP
- How to create a Spring Boot Web Application (Spring MVC with JSP/ThymeLeaf)
- Spring Boot - Spring Data JPA - MySQL Example
- Spring Boot Hello World RESTful Web Services Tutorial
- How to use JDBC with Spring Boot
- Spring Boot CRUD Web Application with JDBC - Thymeleaf - Oracle
- Spring Boot RESTful CRUD API Examples with MySQL database
- How to package Spring Boot application to JAR and WAR
- Spring Boot Security Authentication with JPA, Hibernate and MySQL
- Spring Data JPA Paging and Sorting Examples
- All Spring Boot Tutorials
Comments