Spring MVC Interceptor HandlerInterceptorAdapter, HandlerInterceptor Voorbeeld

Spring Interceptors worden gebruikt om clientverzoeken te onderscheppen en te verwerken. Soms willen we het HTTP-verzoek onderscheppen en enige verwerking uitvoeren voordat we het overdragen aan de controller-handlermethoden. Dat is waar Spring MVC Interceptors van pas komen.

Spring Interceptor

Net zoals we Struts2 Interceptors hebben, kunnen we onze eigen Spring-interceptor maken door ofwel de interface org.springframework.web.servlet.HandlerInterceptor te implementeren, of door de abstracte klasse org.springframework.web.servlet.handler.HandlerInterceptorAdapter te overschrijven, die de basisimplementatie van de HandlerInterceptor-interface biedt.

Spring Interceptor – HandlerInterceptor

Spring HandlerInterceptor declareert drie methoden op basis van waar we het HTTP-verzoek willen onderscheppen.

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): Deze methode wordt gebruikt om het verzoek te onderscheppen voordat het aan de handler-methode wordt doorgegeven. Deze methode moet ’true’ retourneren om Spring te laten weten het verzoek te verwerken via een andere Spring-interceptor of het naar de handler-methode te sturen als er geen verdere Spring-interceptors zijn. Als deze methode ‘false’ retourneert, gaat het Spring-framework ervan uit dat het verzoek is afgehandeld door de Spring-interceptor zelf en dat er geen verdere verwerking nodig is. In dit geval moeten we het response-object gebruiken om een antwoord naar het clientverzoek te sturen. Het object handler is het gekozen handler-object om het verzoek af te handelen. Deze methode kan ook een Exception gooien; in dat geval kan Spring MVC Exception Handling nuttig zijn om een foutpagina als antwoord te sturen.
  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): Deze HandlerInterceptor-methode wordt aangeroepen wanneer HandlerAdapter de handler heeft opgeroepen, maar DispatcherServlet de weergave nog moet renderen. Deze methode kan worden gebruikt om een extra attribuut toe te voegen aan het ModelAndView-object dat wordt gebruikt in de weergavepagina’s. We kunnen deze Spring-interceptormethode gebruiken om de tijd te bepalen die de handler-methode nodig heeft om het clientverzoek te verwerken.
  3. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): Dit is een callbackmethode van HandlerInterceptor die wordt aangeroepen zodra de handler is uitgevoerd en het weergave is gerenderd.

Als er meerdere Spring-interceptors zijn geconfigureerd, wordt de preHandle()-methode uitgevoerd in de volgorde van configuratie, terwijl de postHandle()– en afterCompletion()-methoden worden aangeroepen in omgekeerde volgorde. Laten we een eenvoudige Spring MVC-toepassing maken waarbij we een Spring Interceptor configureren om timings van de controllerhandlermethode te registreren. Ons uiteindelijke voorbeeldproject van Spring Interceptor zal eruitzien als de onderstaande afbeelding, we zullen de onderdelen bekijken waarin we geïnteresseerd zijn.

Spring Interceptor – Controllerklasse

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);
		// wat vertraging toevoegen om de uitvoering van de interceptor te controleren
		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.

Spring MVC Interceptor – HandlerInterceptorAdapter-implementatie

Voor eenvoud, breid ik de abstracte klasse HandlerInterceptorAdapter uit. HandlerInterceptorAdapter is een abstracte adapterklasse voor het HandlerInterceptor-interface, voor vereenvoudigde implementatie van alleen-vooraf/alleen-achteraf-interceptors.

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);
		// als false wordt geretourneerd, moeten we ervoor zorgen dat 'response' wordt verzonden
		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 kunnen attributen toevoegen in de modelAndView en die gebruiken in de weergavepagina
	}

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

}

De logica is echt eenvoudig, ik log gewoon de timing van de uitvoering van de handlermethode en de totale tijd die nodig is voor het verwerken van het verzoek, inclusief het renderen van de weergavepagina.

Spring MVC Interceptor-configuratie

We moeten de Spring-interceptor aan de verzoeken koppelen, we kunnen het mvc:interceptors-element gebruiken om alle interceptors te koppelen. We kunnen ook een URI-patroon opgeven om overeen te komen voordat we de Spring-interceptor voor het verzoek opnemen via het mapping-element. Ons uiteindelijke Spring-beanconfiguratiebestand (spring.xml) ziet er als volgt uit.

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

Spring MVC Interceptor-toepassingstesten

Implementeer gewoon de toepassing in een servletcontainer en roep de homecontroller aan, je zult logger-uitvoer zien zoals hieronder.

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

De output bevestigt dat de Spring-interceptor methoden worden uitgevoerd in de gedefinieerde volgorde. Dat is alles voor het gebruik van Spring-interceptors, je kunt het Spring Interceptor-voorbeeldproject downloaden van onderstaande link en proberen meerdere interceptors te hebben en te controleren door verschillende configuratievolgordes.

Download Spring Interceptors Project

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