Spring MVC HandlerInterceptorAdapter and HandlerInterceptor.
Spring Interceptors are utilized to intercept the requests made by clients and execute actions on them. Occasionally, we may want to intercept the HTTP Request and perform certain operations before passing it on to the handler methods of the controller. This is when Spring MVC Interceptors prove to be useful.
Interceptor for Spring framework.
Similar to Struts2 Interceptors, we can develop our own Spring interceptor by either implementing the org.springframework.web.servlet.HandlerInterceptor interface or by overriding the abstract class org.springframework.web.servlet.handler.HandlerInterceptorAdapter, which offers a fundamental implementation of the HandlerInterceptor interface.
Interceptor in Spring – HandlerInterceptor
The Spring HandlerInterceptor interface consists of three methods that determine the location at which we wish to intercept the HTTP request.
-
- The ‘preHandle’ method in Spring is used to intercept the request before it is handled by the designated method. If this method returns ‘true’, then the request can be processed further by other Spring interceptors or sent to the handler method. If it returns ‘false’, it means that the request has already been handled by the Spring interceptor and no further processing is necessary. In this case, the response object should be used to send a response to the client. The ‘handler’ object is the chosen object that will handle the request. If an exception is thrown in this method, Spring MVC Exception Handling can be used to send an error page as a response.
The ‘postHandle’ method is called by the HandlerInterceptor when the HandlerAdapter has invoked the handler, but the DispatcherServlet has not yet rendered the view. This method can be used to add additional attributes to the ModelAndView object, which can then be used in the view pages. Additionally, this Spring interceptor method can be used to determine the time taken by the handler method to process the client request.
The ‘afterCompletion’ method is a callback method in the HandlerInterceptor that is called once the handler has been executed and the view has been rendered.
If there are multiple spring interceptors set up, the preHandle() function is executed according to the order of configuration, while the postHandle() and afterCompletion() functions are called in the opposite order. We will now create a simple Spring MVC application where we configure a Spring Interceptor to record the timings of controller handler methods. The resulting example project will resemble the image below, focusing on the relevant components.
A class within the Spring framework that acts as an interceptor for the Controller component.
package com.scdev.spring;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
//adding some time lag to check interceptor execution
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
logger.info("Before returning view page");
return "home";
}
}
I am simply including some delay in the execution of the handler method to observe the functionality of our Spring interceptors.
Implementation of HandlerInterceptorAdapter in Spring MVC Interceptor.
To keep things simple, I am using the abstract class HandlerInterceptorAdapter. This class serves as an adapter for the HandlerInterceptor interface, making it easier to implement interceptors that only handle pre or post requests.
package com.scdev.spring;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class RequestProcessingTimeInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory
.getLogger(RequestProcessingTimeInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: Start Time=" + System.currentTimeMillis());
request.setAttribute("startTime", startTime);
//if returned false, we need to make sure 'response' is sent
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("Request URL::" + request.getRequestURL().toString()
+ " Sent to Handler :: Current Time=" + System.currentTimeMillis());
//we can add attributes in the modelAndView and use that in the view page
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
long startTime = (Long) request.getAttribute("startTime");
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: End Time=" + System.currentTimeMillis());
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: Time Taken=" + (System.currentTimeMillis() - startTime));
}
}
The concept is quite straightforward – I am merely recording the durations of the handler method’s execution and the overall time it takes to process the request, which includes rendering the view page.
Configure Spring MVC Interceptors
We need to connect the spring interceptor with the requests, and we can do this by using the mvc:interceptors element to connect all the interceptors. Additionally, we can specify a URI pattern to determine when to include the spring interceptor for a request using the mapping element. The configuration file for our spring bean (spring.xml) should look like the following.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- Configuring interceptors based on URI -->
<interceptors>
<interceptor>
<mapping path="/home" />
<beans:bean class="com.scdev.spring.RequestProcessingTimeInterceptor"></beans:bean>
</interceptor>
</interceptors>
<context:component-scan base-package="com.scdev.spring" />
</beans:beans>
Since we are not interested in and they do not have any specific spring interceptor related configuration, I will not provide an explanation for all the other components of the web application.
Testing the application with Spring MVC Interceptor.
Simply install the application in the servlet container and call upon the home controller. As a result, you will observe the logger generating an output similar to the one mentioned below.
INFO : com.scdev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Start Time=1396906442086
INFO : com.scdev.spring.HomeController - Welcome home! The client locale is en_US.
INFO : com.scdev.spring.HomeController - Before returning view page
Request URL::https://localhost:9090/SpringInterceptors/home Sent to Handler :: Current Time=1396906443098
INFO : com.scdev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: End Time=1396906443171
INFO : com.scdev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Time Taken=1085
The result affirms that the spring interceptor methods are executed in the specified sequence. That concludes the usage of spring interceptors. You can access the Spring Interceptor example project from the link below and experiment with multiple interceptors, testing different configuration orders.
Please obtain the Spring Interceptors Project by downloading it.
More Tutor
Tutorial on how to set up a Hibernate Tomcat JNDI DataSource.(Opens in a new browser tab)
BroadcastReceiver Example Tutorial on Android(Opens in a new browser tab)