Spring HandlerInterceptor Example

Spring provides two main ways to create interceptors: HandlerInterceptor and HandlerInterceptorAdapter. This spring tutorial discusses how to use these, and the difference between these two, and how they are related.

As we know the servlet filters can pre-handle and post-handle every web request they serve – before and after it is handled by the mapped servlet. Similarly, we can use the HandlerInterceptor interface in a Spring web application to pre-handle and post-handle web requests that are handled by MVC controllers.

The interceptor handlers are mostly used to manipulate the model attributes returned/submitted they are passed to the views/controllers. Also, it is possible to perform operations such as logging, authentication, authorization, and request validation before the actual request processing happens.

1. HandlerInterceptor Interface

Handler interceptors are configured in Spring’s web application context, so they can make use of the container features and refer to any beans declared in the container. A handler interceptor can be registered for particular URL mapping, so it only intercepts requests mapped to a certain URL.

Each handler interceptor must implement the HandlerInterceptor interface, which contains three callback methods for you to implement:

MethodDescription
preHandle()Executed before the actual handler is executed. This method returns a boolean value. If it returns true, the request proceeds to the next interceptor or handler. If it returns false, the request processing is interrupted.
postHandle()Executed after the handler is executed, but before the view is rendered. This method allows for modifying the ModelAndView object.
afterCompletion()Executed after the complete request has finished. This method is useful for resource cleanup, logging, etc.

2. How to Create a Handler Interceptor?

To create an interceptor, we implement the HandlerInterceptor interface and override its methods. Inside the method, we can write the logic to perform for each intercepted request and response.

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, 
      HttpServletResponse response, Object handler) throws Exception {

        System.out.println("Pre Handle method is Calling");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, 
      HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("Post Handle method is Calling");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, 
      HttpServletResponse response, Object handler, Exception exception) throws Exception {

        System.out.println("Request and Response is completed");
    }
}

Next, we register it in the Spring Boot application by implementing the WebMvcConfigurer interface and add its instance to the list of interceptors.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor);
    }
}

3. Applying HandlerInterceptor to Certain URLs Only

Well, using the above approach, the handler will be applied on all controllers in the application irrespective of what URLs they are mapped to. If you want to map your handler to a certain URL only then you will have to use the addPathPatterns() and excludePathPatterns() methods.

For example, with the following configuration:

  • The interceptor will be applied to requests with URLs matching /demo/** and /api/**.
  • The interceptor will NOT be applied to requests with URLs matching /public/**.
//...
public class WebConfig implements WebMvcConfigurer {

  @Autowired
  private CustomRequestHandler customRequestHandler;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // Register the interceptor and apply it to specific URL patterns
    registry.addInterceptor(customRequestHandler)
      .addPathPatterns("/demo/**", "/api/**")  // Add specific URL patterns
      .excludePathPatterns("/public/**");     // Exclude specific URL patterns
  }

  //...
}

4. What is HandlerInterceptorAdapter Class?

This class was deprecated as of 5.3 in favor of implementing HandlerInterceptor and/or AsyncHandlerInterceptor directly. Later, it was removed and it is not available in Spring 6.

The problem with HandlerInterceptor interface is that the new class has to implement all three methods irrespective of whether they are needed or not. The HandlerInterceptorAdapter is an abstract class that implements the HandlerInterceptor interface and provides default implementations for the three methods.

So whatever methods we want to override in the request handler, we can extend it from HandlerInterceptorAdapter.

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class MyInterceptorAdapter extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, 
      HttpServletResponse response, Object handler) throws Exception {

        System.out.println("Pre Handle method is Calling");
        return true;
    }

    // Override other methods only if needed
}

5. Demo

For demo purposes, we are reusing the code created for Spring MVC hello world application. We are creating a CustomRequestHandler class. Methods of this class will be called as per the above discussion.

@Component
public class CustomRequestHandler implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long startTime = (Long) request.getAttribute("startTime");
        request.removeAttribute("startTime");

        long endTime = System.currentTimeMillis();
        if (modelAndView != null) {
            modelAndView.addObject("totalTime", endTime - startTime);
        }

        System.out.println("Request Processing Time :: " + (endTime - startTime));
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("View Rendered!!");
    }
}

Now when we have created the request handler, it must be declared into Spring configuration so that spring can pass requests to it at the appropriate time.

Next, we register the interceptor in the Spring configuration.

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private CustomRequestHandler customRequestHandler;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(customRequestHandler);
    }
}

Now when we run the hello-world application again, it will print the below output.

Request Precessing Time :: 15
View Rendered !!

That’s all for this quick tip.

Happy Learning !!

Comments

Subscribe
Notify of
guest
2 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.