Spring MVC Interceptor HandlerInterceptorAdapter, Ejemplo HandlerInterceptor

Los Interceptors de Spring se utilizan para interceptar las solicitudes del cliente y procesarlas. A veces, queremos interceptar la solicitud HTTP y realizar algún procesamiento antes de pasarla a los métodos controladores del controlador. Ahí es donde resultan útiles los Interceptors de Spring MVC. `

Spring Interceptor

` Al igual que tenemos los Interceptors de Struts2, podemos crear nuestro propio interceptor de Spring ya sea implementando la interfaz `org.springframework.web.servlet.HandlerInterceptor` o mediante la anulación de la clase abstracta `org.springframework.web.servlet.handler.HandlerInterceptorAdapter` que proporciona la implementación base de la interfaz HandlerInterceptor. `

Spring Interceptor – HandlerInterceptor

` El `HandlerInterceptor` de Spring declara tres métodos según dónde queramos interceptar la solicitud HTTP.

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): Este método se utiliza para interceptar la solicitud antes de ser entregada al método del controlador. Este método debería devolver ‘true’ para que Spring sepa que debe procesar la solicitud a través de otro interceptor de Spring o enviarla al método del controlador si no hay más interceptores de Spring. Si este método devuelve ‘false’, el framework de Spring asume que la solicitud ha sido manejada por el interceptor de Spring mismo y no se necesita ningún procesamiento adicional. En este caso, debemos utilizar el objeto de respuesta para enviar la respuesta a la solicitud del cliente. El objeto handler es el objeto de controlador elegido para manejar la solicitud. Este método también puede lanzar una excepción, en cuyo caso podría ser útil Spring MVC Exception Handling para enviar una página de error como respuesta.
  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): Este método del interceptor HandlerInterceptor se llama cuando HandlerAdapter ha invocado al controlador pero DispatcherServlet aún no ha renderizado la vista. Se puede utilizar este método para agregar atributos adicionales al objeto ModelAndView que se utilizarán en las páginas de vista. Podemos utilizar este método del interceptor de Spring para determinar el tiempo que tarda el método del controlador en procesar la solicitud del cliente.
  3. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): Este es un método de devolución de llamada HandlerInterceptor que se llama una vez que se ejecuta el controlador y se renderiza la vista.

Si hay varios interceptores de Spring configurados, el método preHandle() se ejecuta en el orden de configuración, mientras que los métodos postHandle() y afterCompletion() se invocan en orden inverso. Creemos una aplicación Spring MVC simple donde configuraremos un Interceptor de Spring para registrar los tiempos de ejecución del método del controlador. Nuestro proyecto de ejemplo final de Interceptor de Spring se verá como la imagen a continuación, analizaremos los componentes en los que estamos interesados.

Interceptor de Spring – Clase de Controlador

package com.journaldev.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);
		// agregando algún retraso de tiempo para verificar la ejecución del interceptor
		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 just adding some processing time in the execution of the handler method to check our spring interceptor methods in action.

Implementación de HandlerInterceptorAdapter del Interceptor de Spring MVC

Para simplificar, estoy extendiendo la clase abstracta HandlerInterceptorAdapter. HandlerInterceptorAdapter es una clase adaptadora abstracta para la interfaz HandlerInterceptor, para la implementación simplificada de interceptores solo de pre/post.

package com.journaldev.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);
		//si devuelve falso, necesitamos asegurarnos de que se envíe 'response'
		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());
		//podemos agregar atributos en el modelAndView y usarlos en la página de vista
	}

	@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));
	}

}

La lógica es realmente simple, solo estoy registrando los tiempos de ejecución del método del controlador y el tiempo total tomado en el procesamiento de la solicitud, incluida la renderización de la página de vista.

Configuración del Interceptor Spring MVC

Debemos cablear el interceptor de Spring a las solicitudes, podemos usar el elemento mvc:interceptors para cablear todos los interceptores. También podemos proporcionar un patrón URI para que coincida antes de incluir el interceptor de Spring para la solicitud a través del elemento mapping. Nuestro archivo de configuración final del bean de Spring (spring.xml) se ve así.

<?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.journaldev.spring.RequestProcessingTimeInterceptor"></beans:bean>
		</interceptor>
	</interceptors>

	<context:component-scan base-package="com.journaldev.spring" />

</beans:beans>

I will not explain all other components of the web application, because we are not interested in them and they don’t have any specific spring interceptor related configuration.

Pruebas de Aplicación del Interceptor Spring MVC

Simplemente implementa la aplicación en un contenedor de servlet e invoca el controlador principal, verás que la salida del registro es algo así.

INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Start Time=1396906442086
INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is en_US.
INFO : com.journaldev.spring.HomeController - Before returning view page
Request URL::https://localhost:9090/SpringInterceptors/home Sent to Handler :: Current Time=1396906443098
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: End Time=1396906443171
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Time Taken=1085

El resultado confirma que los métodos del interceptor de Spring se ejecutan en el orden definido. Eso es todo para usar los interceptores de Spring, puedes descargar el proyecto de ejemplo del interceptor de Spring desde el siguiente enlace e intentar tener varios interceptores y verificar mediante diferentes órdenes de configuración.

Descargar Proyecto de Interceptores de Spring

Source:
https://www.digitalocean.com/community/tutorials/spring-mvc-interceptor-example-handlerinterceptor-handlerinterceptoradapter