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.

    1. 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)

Leave a Reply 0

Your email address will not be published. Required fields are marked *


广告
Closing in 10 seconds
bannerAds