Monolith Spring Boot Exception Handling
1. Overview
This article is a build up on the first article that explores the basics of Spring Boot exception handling and explains the different techniques used. The first article used an API server that returns JSON format for example throughout.
In this follow-up article, however, we will be working with HTML response and be returning web pages instead of JSON. We will be using the same technique and so it’s highly recommended that you read the first article before continuing with this.
2. Application Setup
The application we will be working with contains spring-boot-starter-web and spring-boot-starter-freemarker as main dependencies. We can generate the bare scaffolding using this Spring Initializr link.
3. Basic Exception Handling
By default, Spring Boot will bootstrap the BasicErrorController
to handle all calls to the /error
endpoint.
Whenever there’s an error while accessing the application from a web browser the errorHtml
function of the BasicErrorController
will be called since the Accept
content-type is text/html
.
Furthermore, the errorHtml
method will use available error view resolvers to get the right error page.
The DefaultErrorViewResolver
will look for suitable view files in the resources/templates/error
, resources/static/error
and
resources/error
directories and display the first match to the end-user.
This simplifies things for us a lot! All we have to do to handle a 404
error is to provide a 404.ftlh
file in the
resources/templates/error
directory and it will be served whenever there’s a 404
error.
Listing 3.1 resources/templates/error/404.ftlh
|
|
We can repeat this technique for all other error status codes like 403
, 500
and 503
.
The reason we’re using the .ftlh
extension is that we’re using the Freemarker template engine and that’s the default file extension.
If we’re using other template engines the view files will have a different extension.
For example, the Thymeleaf template engine uses the .html
extension by default.
In addition to individual error view files, we can also create a catch-all error file in resources/templates/error.ftlh
.
This will be the fallback if no other specific error views are found.
Let’s create the resource file and an endpoint that will intentionally throw a runtime exception, so we can see it work.
Listing 3.2 resources/templates/error.ftlh
|
|
Listing 3.3 IndexController.java
|
|
If we visit the /ex/runtime
endpoint, we will see the content of resources/templates/error.ftlh
, because we did not define a specific
resources/templates/error/500.ftlh
error page.
4. Custom Error Controller
There are times that we want to do something more than just return a view when an exception occurred. For this purpose, we can define our own error handler that will be called instead of the default basic error controller.
Our custom error handler is a controller class, i.e. annotated with @Controller
, that has a request mapping for the /error
endpoint.
The class must also implement the ErrorController
interface so that it will replace the default BasicErrorController
component.
Listing 4.1 GlobalExceptionHandler.java
|
|
Our implementation is also similar to the default one, it’s just that we can now execute custom logic and add custom attributes to be used in the view template.
Listing 4.2 resources/templates/error/custom-error.ftlh
|
|
This is one of the sweet points of Spring Boot. In as much as there are sensible defaults, we can easily use custom implementations and everything will still work seamlessly.
Always remember to exclude your /error
endpoint from Spring Security to avoid access denied error when Spring Boot is
redirecting to the /error
endpoint. Ensure you set the permission level to permit all.
5. Handling Specific Exception Classes
In part one of this series, we learnt that it’s possible to create a specific exception class that we can throw from any part of the application and it will be handled by a designated method.
We can apply the same technique here as well, although we will be returning a specific error page instead of a JSON.
To achieve this, we will annotate our existing GlobalExceptionHandler
.java with @ControllerAdvice
and add a new method
to handle the CustomApplicationException
class.
Listing 5.1 CustomApplicationException.java
|
|
Let’s create a separate error page to demonstrate this and a new endpoint to test it.
Listing 5.2 resources/templates/errors/custom-app-error.ftlh
|
|
Listing 5.3 IndexController.java
|
|
This technique can also be applied to any specific exception classes that we desire to treat specially.
Also, it’s important to note that once an exception has been handled by a specific method,
it will not be handled by other handlers like the /error
endpoint.
6. Conclusion
In this article, we’ve looked extensively at how to handle exceptions in Spring Boot and return corresponding error pages. The complete source code is available on GitHub.
Love this concise and interesting article about exception handling? You should totally check out my book on Spring Cloud OpenFeign. You’ll never call external APIs the same way again.