In this article, we will see the Spring Boot interceptor example. Also, we will see how to configure interceptors using spring boot and what is the use of interceptors. These interceptors will get called before the request will reach to controller/endpoint classes.
Define custom interceptor in Spring Boot
Step 1 – Spring provides HandlerInterceptorAdapter class, we can define custom interceptors extending this class. HandlerInterceptorAdapter is an abstract class. We need to override the below methods in our interceptor.
boolean preHandle() – This method will get called by container while sending the request to controller classes. Typically used, if we want to send some data with the request or if we want to modify the request data.
void postHandle() – This method will get invoked while sending the response from the server. We can write some logic inside this method if want to modify response data.
afterCompletion() – This method is used for resource clean up task.
Step 2 – We need to define a class WebAppConfigAdapter.java which should implement the WebMvcConfigurer interface and need to override the addInterceptors() method. Using the addInterceptors() method we will add our custom interceptors.
@Override
public void addInterceptors (InterceptorRegistry interceptorRegistry) {
System.out.println("securityInterceptor --" +securityInterceptor);
interceptorRegistry.addInterceptor(securityInterceptor);
}
Note – There is another method afterConcurrentHandlingStarted() can be used instead postHandle() and afterCompletion() when handler is executed concurrently. This method is used for clean up thread-local variables.
Spring Boot interceptor example from scratch
Create a maven project, Don’t forget to check ‘Create a simple project (skip)’click on next. Fill all details(GroupId – springbootinterceptor, ArtifactId – springbootinterceptor, and name – springbootinterceptor) and click on finish. Keep packaging as the jar.
maven dependency – pom.xml
<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>springbootinterceptor</groupId> <artifactId>springbootinterceptor</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springbootinterceptor</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
Our directory structure should be as below.
Book.java
package com.javatute.entity; public class Book { int bookId; String bookName; String bookPrice; public int getBookId() { return bookId; } public void setBookId(int bookId) { this.bookId = bookId; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public String getBookPrice() { return bookPrice; } public void setBookPrice(String bookPrice) { this.bookPrice = bookPrice; } }
BooKController.java
package com.javatute.controller; import java.util.concurrent.Callable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.javatute.entity.Book; @RestController @RequestMapping("/book") public class BookController { @RequestMapping(value = "/getbook", method = RequestMethod.GET) @ResponseBody public Book getBook() { Book book = new Book(); book.setBookId(1); book.setBookName("rich dad poor dad"); book.setBookPrice("10"); return book; } @RequestMapping(value = "/getasync", method = RequestMethod.GET) public Callable<Book> handleTestRequest() { Callable<Book> callable = new Callable<Book>() { public Book call() throws Exception { Thread.sleep(100); Book book = new Book(); book.setBookId(1); book.setBookName("rich dad poor dad"); book.setBookPrice("10"); return book; } }; return callable; } }
SpringMainExample.java
package com.javatute.main; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan(basePackages = "com.javatute.*") public class SpringMain { public static void main(String[] args) { SpringApplication.run(SpringMain.class, args); } }
Now we need to define two classes for interceptor implementation.
RequestHandlerInterceptor.java
package com.javatute.interceptors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @Component public class RequestHandlerInterceptor extends HandlerInterceptorAdapter{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle() is invoked"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle() is invoked"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion() is invoked"); } @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("afterConcurrentHandlingStarted() is invoked"); } }
WebAppConfigAdapter.java
package com.javatute.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.javatute.interceptors.RequestHandlerInterceptor; @Component public class WebAppConfigAdapter implements WebMvcConfigurer { @Autowired RequestHandlerInterceptor interceptor; @Override public void addInterceptors(InterceptorRegistry interceptorRegistry) { System.out.println("this method will get invoked by container while deployment"); System.out.println("value of interceptor is " + interceptor); // adding custom interceptor interceptorRegistry.addInterceptor(interceptor); } }
We are done now. Let’s run SpringMainExample.java
We can see the addInterceptors() method has been called while deployment.
Let’s hit below URI from the postman.
http://localhost:9092/book/getbook
Observethe console. Now preHandle(), postHandle() and afterCompletion() will get called.
Did you notice! The afterConcurrentHandlingStarted() method has not been called? This method is used mainly for asynchronous processing. HandlerInterceptorAdapter class further implements AsyncHandlerInterceptor interface, this interface contains afterConcurrentHandlingStarted() method. We have created a new thread using callable in the controller.
@RequestMapping(value = "/getasync", method = RequestMethod.GET) public Callable<Book> handleTestRequest() { Callable<Book> callable = new Callable<Book>() { public Book call() throws Exception { Thread.sleep(100); Book book = new Book(); book.setBookId(1); book.setBookName("rich dad poor dad"); book.setBookPrice("10"); return book; } }; return callable; }
Let’s clear the console and hit the below URL from the postman.
localhost:9091/book/getasync
Spring Boot Interceptor example to Modify Request Body
Inside preHandle() method We can set the attribute name, value, and scope in request attributes. Further, this request attributes would be set to RequestContextHolder. The benefit is, we can access these data anywhere in whole application using RequestContextHolder.getRequestAttributes().
Observe the below code snippet.
@Component public class RequestHandlerInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); requestAttributes.setAttribute("some_name", "some_value", RequestAttributes.SCOPE_REQUEST); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // do-some stuff } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // do-some stuff } }
Now we are going to access request attributes value in our controller class. Let’s modify our controller class as below.
@RestController @RequestMapping("/book") public class BookController { @RequestMapping(value = "/getbook", method = RequestMethod.GET) @ResponseBody public Book getBook() { Book book = new Book(); book.setBookId(1); book.setBookName("rich dad poor dad"); book.setBookPrice("10"); System.out.println("accessing RequestContext Start"); RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); System.out.println(requestAttributes.getAttribute("some_name", RequestAttributes.SCOPE_REQUEST)); System.out.println("accessing RequestContext End"); return book; } }
Run the application and perform http://localhost:9091/book/getbook call.
In RequestHandlerInterceptor.java we added Request values at line number 7. We are able to access this in the controller. The same way you can access it anywhere in the application ServiceImpl layer or DaoImpl layer.
Spring Boot Logging Interceptor Example
We can also use the interceptors for logging purposes. We can log what request data and response data. Let’s see an example.
package com.javatute.interceptors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @Component public class LoggingInterceptor extends HandlerInterceptorAdapter { private static final Logger logger = LogManager.getLogger(LoggingInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); requestAttributes.setAttribute("some_name", "some_value", RequestAttributes.SCOPE_REQUEST); logger.info("" + request.getRequestURI()); logger.info("" + request.getMethod()); // some more information we can get here return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.info("postHanadle() method has been invoked"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.info("afterCompletion() has been invoked"); logger.info("Response status is " + response.getStatus()); } }
Call http://localhost:9091/book/getbook and observe the logger info.
INFO 11016 — [nio-9091-exec-4] c.n.interceptors.LoggingInterceptor : /book/getbook
INFO 11016 — [nio-9091-exec-4] c.n.interceptors.LoggingInterceptor : GET
INFO 11016 — [nio-9091-exec-4] c.n.interceptors.LoggingInterceptor : postHanadle() method has been invoked
INFO 11016 — [nio-9091-exec-4] c.n.interceptors.LoggingInterceptor :
INFO 11016 — [nio-9091-exec-4] c.n.interceptors.LoggingInterceptor : afterCompletion() has been invoked
INFO 11016 — [nio-9091-exec-4] c.n.interceptors.LoggingInterceptor : Response status is 200
In the above console output, we can see what URL we are passing, what Request Method is there. Also, we can see the Response status code for this request URL. This kind of information we can log using Interceptors.
Spring Boot Authentication Interceptor Example
Spring Interceptors can also be used for security-related stuff. Suppose you want to perform authentication operation then we can have logic inside preHandle() method.
Let’s consider a very simple use case. We have two rest end points.
http://localhost:9091/user/login
http://localhost:9091/user/getuser
For the first Rest API, we don’t want to be secured since anyone can access this API. But while accessing the second Rest API we want to perform some authentication using username and password. In this example, we are not using the database to perform authentication.
@Component public class AuthenthicationInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //Some - authentication related code goes here return true; } }
Let’s see an example.
Directory structure of exmple.
Define User.java class.
package com.javatute.entity;
public class User {
int id;
String username;
String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Define user define annotation NotSecuredApi.java
package com.javatute.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface NotSecuredApi {
}
Define AuthenticationInterceptor.java class.
package com.javatute.interceptors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.javatute.annotation.NotSecuredApi;
import com.javatute.constants.ApplicationConstant;
import com.javatute.error.UserNotAuthorizedException;
@Component
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HandlerMethod handlerMethod = null;
if (handler instanceof HandlerMethod) {
handlerMethod = (HandlerMethod) handler;
}
// Below implementation is for http://localhost:9091/user/login API
NotSecuredApi notSecuredApi = handlerMethod.getMethodAnnotation(NotSecuredApi.class);
if (notSecuredApi != null && notSecuredApi instanceof NotSecuredApi) {
return true;
}
// username and password that we are sending from postman
String username = request.getHeader("username");
String password = request.getHeader("password");
// Dummy logic for second API for authentication
// This should token based authentication so need to send username and
// password again and again
if (ApplicationConstant.USERNAME.equals(username) && ApplicationConstant.PASSWORD.equals(password)) {
return true;
}
// if username and password is not admin & admin then show error
if (!ApplicationConstant.USERNAME.equals(username) || !ApplicationConstant.PASSWORD.equals(password)) {
throw new UserNotAuthorizedException("Not a valid user");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// Some more logic if needed
System.out.println("postHandle() is invoked");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// Some more logic if needed
System.out.println("afterCompletion() is invoked");
}
}
Define WebAppConfigAdapter.java class where we will register AuthenthicationInterceptor.
package com.javatute.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.javatute.interceptors.AuthenthicationInterceptor;
@Component
public class WebAppConfigAdapter implements WebMvcConfigurer {
@Autowired
private AuthenticationInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
System.out.println("This method will get invoked by container while deployment");
System.out.println("Value of interceptor is " + interceptor);
// adding custom interceptor
interceptorRegistry.addInterceptor(interceptor);
}
}
Define ApplicationConstant.java class
package com.javatute.constants;
public class ApplicationConstant {
public static final String USERNAME = "admin";
public static final String PASSWORD = "admin";
}
Define User define exception i.e UserNotAuthorizedException.java
package com.javatute.error;
public class UserNotAuthorizedException extends RuntimeException {
private static final long serialVersionUID = 1L;
String message;
public UserNotAuthorizedException() {
super();
}
public UserNotAuthorizedException(String message) {
super(message);
this.message = message;
}
}
Define ResponseError class.
package com.javatute.error;
public class ResponseError {
private String errorMessage;
private int statusCode;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
}
Define global error handler class.
package com.javatute.error;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class GlobalErrorHandler {
@ExceptionHandler(UserNotAuthorizedException.class)
@ResponseBody
public ResponseError handleCustomException(UserNotAuthorizedException ex) {
ResponseError responseError = new ResponseError();
responseError.setErrorMessage(ex.getMessage());
responseError.setStatusCode(HttpStatus.UNAUTHORIZED.value());
return responseError;
}
}
We are almost done. Let’s define UserController class.
package com.javatute.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.javatute.annotation.NotSecuredApi;
import com.javatute.constants.ApplicationConstant;
import com.javatute.entity.User;
import com.javatute.error.UserNotAuthorizedException;
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/login")
@NotSecuredApi
public String getAuthenticated(@RequestHeader(value = "username") String username,
@RequestHeader(value = "password") String password) {
// if username and password is not admin & admin then show error
if (!ApplicationConstant.USERNAME.equals(username) || !ApplicationConstant.PASSWORD.equals(password)) {
throw new UserNotAuthorizedException("Not a valid user");
}
return "User successfully auntheticated";
}
@GetMapping("/getuser")
public User getUser() {
User user = new User();
user.setId(1);
user.setUsername("Tom");
user.setEmail("teste@gmail.com");
return user;
}
}
SpringMain.java would be same as above example.
Let’s run SpringMain.java class
Testing of Spring Authentication Interceptor Example using postman.
First we will test http://localhost:9091/user/login API and we will test http://localhost:9091/user/getuser API.
We will provide username and password as admin & admin.
Let’s provide some different username than admin.
we are getting the above response since we have implemented global error handling. See more about how to perform global error handling in Spring Boot application.
Let’s test another API.
Let’s try to access http://localhost:9091/user/getuser with different username than admin.
That’s all about Spring Authentication Interceptor Example.
Spring Boot Interceptor example which demonstrates Interceptor will get invoked after Filter.
Both filters and interceptors will get invoked before the request will reach to controller/endpoint classes. In this example, we will see how Filters getting invoked before Interceptors.
We will define a Filter called CustomFilter.java and we have already an interceptor i.e RequestHandlerInterceptor.java. Let’s see the directory structure of Filter.
CustomFilter.java
package com.javatute.filters; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.springframework.stereotype.Component; @Component public class CustomFilter implements Filter { // this method will be called by container when we send any request @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out .println("Hey i am Filter. I will get invoked before that Interceptors. doFilter() method is invoked"); chain.doFilter(request, response); } // this method will be called by container while deployment @Override public void init(FilterConfig config) throws ServletException { // do some stuff } @Override public void destroy() { // do some stuff like clearing the resources } }
RequestHandlerInterceptor.java
package com.javatute.interceptors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @Component public class RequestHandlerInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println( "Hey i am an Interceptor. I will get invoked after that filters. preHandle() method is invoked"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // Do some important stuff } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // do-some stuff } }
Run SpringMain.java, clear the console, and test using postman.
List of Some important Spring interceptors.
HandlerInterceptor – This is the to-level interceptor contains three methods preHandle(), postHandle() and afterCompletion(). All Spring interceptors(predefined or custom defined) should use this interceptors.
AsyncHandlerInterceptor – This interceptor extends HandlerInterceptor and contains afterConcurrentHandlingStarted() callback method. We have already seen when this method will get invoked.
HandlerInterceptorAdapter – This is an abstract class that implements the AsyncHandlerInterceptor interface.
UserRoleAuthorizationInterceptor – This interceptor extends HandlerInterceptorAdapter and used to check current user roles.
That’s all about the Spring Boot interceptor example.
You may like.
- Spring restful web services example using spring boot.
- Spring Data JPA example using spring boot.
- Spring batch basic.
- Spring batch task scheduling example using spring boot.
- Spring transaction management basic.
- Spring transaction management example using spring boot.
- Spring security default authorization example using spring boot.
- Spring security inMemoryAuthentication and authorization example using spring boot.
- @RestController and @Controller annotation example in Spring Boot.
- @RequestBody and @ResponseBody annotation example in Spring Boot.
- @PathVariable and @RequestParam annotations in Spring Boot.
- @RequestHeader annotation example by using Spring Boot.
- @SpringBootApplication annotation example in Spring Boot
- @Component, @Controller, @Service and @Repository annotations example using Spring Boot.
- @ComponentScan example in spring boot.
- Content negotiation example using Spring Boot.
- @Configuration annotation example using spring boot.
Spring interceptors docs.
Summary – We have seen about Spring Boot interceptor example. We covered how to add interceptors in Spring. We also covered Interceptor will get invoked after Filter.