Les intercepteurs Spring sont utilisés pour intercepter les demandes des clients et les traiter. Parfois, nous voulons intercepter la demande HTTP et effectuer un traitement avant de la remettre aux méthodes du gestionnaire de contrôleurs. C’est là que les intercepteurs Spring MVC sont utiles.
Intercepteur Spring
Tout comme nous avons des intercepteurs Struts2, nous pouvons créer notre propre intercepteur Spring en implémentant l’interface
org.springframework.web.servlet.HandlerInterceptor
ou en substituant la classe abstraite org.springframework.web.servlet.handler.HandlerInterceptorAdapter
qui fournit l’implémentation de base de l’interface HandlerInterceptor.
Intercepteur Spring – HandlerInterceptor
Spring HandlerInterceptor déclare trois méthodes en fonction de l’endroit où nous voulons intercepter la demande HTTP.
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): Cette méthode est utilisée pour intercepter la requête avant qu’elle ne soit transmise à la méthode de gestionnaire. Cette méthode doit renvoyer « true » pour permettre à Spring de savoir s’il faut traiter la requête par le biais d’un autre intercepteur Spring ou l’envoyer à la méthode de gestionnaire s’il n’y a pas d’autres intercepteurs Spring. Si cette méthode renvoie « false », le framework Spring suppose que la requête a été traitée par l’intercepteur Spring lui-même et aucun autre traitement n’est nécessaire. Nous devrions utiliser l’objet de réponse pour envoyer une réponse à la demande du client dans ce cas. L’objet handler est l’objet de gestionnaire choisi pour traiter la demande. Cette méthode peut également générer une Exception, auquel cas la Gestion des Exceptions de Spring MVC devrait être utile pour envoyer une page d’erreur en réponse.
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): Cette méthode d’intercepteur HandlerInterceptor est appelée lorsque HandlerAdapter a invoqué le gestionnaire mais que DispatcherServlet doit encore rendre la vue. Cette méthode peut être utilisée pour ajouter un attribut supplémentaire à l’objet ModelAndView à utiliser dans les pages de vue. Nous pouvons utiliser cette méthode d’intercepteur Spring pour déterminer le temps mis par la méthode de gestionnaire pour traiter la demande du client.
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): Il s’agit d’une méthode de rappel HandlerInterceptor qui est appelée une fois que le gestionnaire est exécuté et que la vue est rendue.
S’il existe plusieurs intercepteurs Spring configurés, la méthode preHandle() est exécutée dans l’ordre de configuration tandis que les méthodes postHandle() et afterCompletion() sont invoquées dans l’ordre inverse. Créons une application Spring MVC simple où nous configurerons un interceptor Spring pour enregistrer les durées des méthodes de gestionnaire de contrôleur. Notre projet d’exemple final avec l’intercepteur Spring ressemblera à l’image ci-dessous, nous examinerons les composants qui nous intéressent.
Intercepteur 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);
//ajoutons un délai pour vérifier l'exécution de l'intercepteur
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.
Intercepteur Spring MVC – Implémentation de HandlerInterceptorAdapter
Pour simplifier, je suis en train d’étendre la classe abstraite HandlerInterceptorAdapter
. HandlerInterceptorAdapter est une classe d’adaptateur abstrait pour l’interface HandlerInterceptor, pour une implémentation simplifiée des intercepteurs pré/post uniquement.
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 false est retourné, nous devons nous assurer que 'response' est envoyée
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());
//nous pouvons ajouter des attributs dans le modelAndView et les utiliser dans la page de vue
}
@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 logique est vraiment simple, je ne fais que consigner les temps d’exécution de la méthode de gestionnaire et le temps total pris dans le traitement de la requête, y compris le rendu de la page de vue.
Configuration de l’intercepteur Spring MVC
Nous devons câbler l’intercepteur Spring aux requêtes, nous pouvons utiliser l’élément mvc:interceptors pour câbler tous les intercepteurs. Nous pouvons également fournir un motif d’URI pour correspondre avant d’inclure l’intercepteur Spring pour la demande via l’élément mapping. Notre fichier de configuration de bean Spring final (spring.xml) ressemble à ce qui suit.
<?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 d’application de l’intercepteur Spring MVC
Il suffit de déployer l’application dans un conteneur de servlets et d’appeler le contrôleur principal, vous verrez une sortie de journalisation quelque chose comme ci-dessous.
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
La sortie confirme que les méthodes d’interception du ressort sont exécutées dans l’ordre défini. C’est tout pour l’utilisation des intercepteurs de Spring. Vous pouvez télécharger le projet exemple d’intercepteur Spring depuis le lien ci-dessous et essayer d’avoir plusieurs intercepteurs, puis vérifier par différents ordres de configuration.