Spring MVC Interceptor HandlerInterceptorAdapter, Esempio di HandlerInterceptor

Gli Interceptor di Spring vengono utilizzati per intercettare le richieste dei clienti e elaborarle. A volte vogliamo intercettare la richiesta HTTP e eseguire qualche elaborazione prima di passarla ai metodi del gestore del controller. È qui che entra in gioco l’Interceptor di Spring MVC.

Interceptor di Spring

Proprio come abbiamo gli Interceptor di Struts2, possiamo creare il nostro Interceptor di Spring implementando l’interfaccia org.springframework.web.servlet.HandlerInterceptor o sovrascrivendo la classe astratta org.springframework.web.servlet.handler.HandlerInterceptorAdapter che fornisce l’implementazione di base dell’interfaccia HandlerInterceptor.

Interceptor di Spring – HandlerInterceptor

L’Interceptor di Spring HandlerInterceptor dichiara tre metodi in base a dove vogliamo intercettare la richiesta HTTP.

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): Questo metodo viene utilizzato per intercettare la richiesta prima che venga passata al metodo gestore. Questo metodo dovrebbe restituire ‘true’ per permettere a Spring di elaborare la richiesta attraverso un altro interceptor di Spring o di inviarla al metodo gestore se non ci sono ulteriori interceptor di Spring. Se questo metodo restituisce ‘false’, il framework Spring assume che la richiesta sia stata gestita dall’interceptor di Spring stesso e non è necessario alcun ulteriore elaborazione. Dovremmo utilizzare l’oggetto di risposta per inviare la risposta alla richiesta del client in questo caso. L’oggetto handler è l’oggetto gestore scelto per gestire la richiesta. Questo metodo può anche lanciare un’eccezione, in tal caso Gestione delle eccezioni di Spring MVC dovrebbe essere utile per inviare la pagina di errore come risposta.
  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): Questo metodo interceptor di HandlerInterceptor viene chiamato quando HandlerAdapter ha invocato il gestore ma DispatcherServlet deve ancora rendere la vista. Questo metodo può essere utilizzato per aggiungere attributi aggiuntivi all’oggetto ModelAndView da utilizzare nelle pagine di visualizzazione. Possiamo utilizzare questo metodo interceptor di Spring per determinare il tempo impiegato dal metodo gestore per elaborare la richiesta del client.
  3. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): Questo è un metodo di callback HandlerInterceptor che viene chiamato una volta che il gestore è eseguito e la vista è renderizzata.

Se sono configurati più interceptors spring, il metodo preHandle() viene eseguito nell’ordine di configurazione mentre i metodi postHandle() e afterCompletion() vengono invocati nell’ordine inverso. Creiamo un’applicazione Spring MVC semplice dove configureremo un Interceptor Spring per registrare i tempi del metodo del gestore del controller. Il nostro progetto di esempio finale dell’Interceptor Spring apparirà come nell’immagine seguente, esamineremo i componenti di nostro interesse.

Interceptor Spring – Classe Controller

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);
		//aggiungendo un ritardo temporale per controllare l'esecuzione dell'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.

Interceptor Spring MVC – Implementazione di HandlerInterceptorAdapter

Per semplicità, sto estendendo la classe astratta HandlerInterceptorAdapter. HandlerInterceptorAdapter è una classe adattatore astratta per l’interfaccia HandlerInterceptor, per semplificare l’implementazione di intercettori solo 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);
		// se restituisce false, dobbiamo assicurarci che 'response' venga inviato
		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());
		// possiamo aggiungere attributi nel modelAndView e usarli nella pagina di visualizzazione
	}

	@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 logica è davvero semplice, sto semplicemente registrando i tempi di esecuzione del metodo del gestore e il tempo totale impiegato nel processare la richiesta inclusa la visualizzazione della pagina.

Configurazione dell’Interceptor di Spring MVC

Dobbiamo collegare l’intercettore Spring alle richieste, possiamo usare l’elemento mvc:interceptors per collegare tutti gli intercettori. Possiamo anche fornire un pattern URI da abbinare prima di includere l’intercettore Spring per la richiesta tramite l’elemento mapping. Il nostro file di configurazione finale del bean Spring (spring.xml) appare come segue.

<?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.

Test dell’applicazione con Interceptor di Spring MVC

Basta distribuire l’applicazione nel contenitore servlet e invocare il controller home, vedrai l’output del registro qualcosa di simile a quanto segue.

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

L’output conferma che i metodi interceptor della Spring vengono eseguiti nell’ordine definito. Questo è tutto per l’utilizzo degli interceptor della Spring, puoi scaricare il progetto di esempio degli interceptor della Spring dal link sottostante e provare ad avere più interceptor e controllare con diversi ordini di configurazione.

Scarica il Progetto degli Interceptor della Spring

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