Spring MVC Interceptor – HandlerInterceptorAdapter Beispiel
Spring Interceptor werden verwendet, um Clientanfragen abzufangen und zu verarbeiten. Manchmal wollen wir die HTTP Request abfangen und einige Verarbeitungen durchführen, bevor wir sie an die Controller-Handler-Methoden übergeben. Hier kommen Spring MVC Interceptor zum Einsatz.
Spring Interceptor
Genau wie wir Struts2 Interceptors haben, können wir unseren eigenen Spring Interceptor erstellen, indem wir entweder das Interface org.springframework.web.servlet.HandlerInterceptor implementieren oder die abstrakte Klasse org.springframework.web.servlet.handler.HandlerInterceptorAdapter überschreiben, die die Basisimplementierung des HandlerInterceptor-Interfaces bereitstellt.
Spring Interceptor – HandlerInterceptor
Spring HandlerInterceptor deklariert drei Methoden, basierend darauf, wo wir die HTTP-Anfrage abfangen wollen.
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): Diese Methode wird verwendet, um die Anfrage abzufangen, bevor sie an die Handler-Methode übergeben wird. Diese Methode sollte ‚true‘ zurückgeben, um Spring zu signalisieren, die Anfrage durch einen weiteren Spring Interceptor zu verarbeiten oder sie an die Handler-Methode zu senden, wenn keine weiteren Spring Interceptor vorhanden sind. Wenn diese Methode ‚false‘ zurückgibt, geht das Spring Framework davon aus, dass die Anfrage bereits durch den Spring Interceptor selbst behandelt wurde und keine weitere Verarbeitung notwendig ist. In diesem Fall sollten wir das Response-Objekt verwenden, um eine Antwort auf die Clientanfrage zu senden. Object handler ist das ausgewählte Handler-Objekt, um die Anfrage zu bearbeiten. Diese Methode kann auch eine Exception auslösen, in diesem Fall sollte die Spring MVC Exception Handling nützlich sein, um eine Fehlerseite als Antwort zu senden.
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): Diese HandlerInterceptor-Interceptor-Methode wird aufgerufen, wenn HandlerAdapter den Handler aufgerufen hat, aber DispatcherServlet die Ansicht noch nicht gerendert hat. Diese Methode kann verwendet werden, um zusätzliche Attribute zum ModelAndView-Objekt hinzuzufügen, die auf den Ansichtsseiten verwendet werden können. Wir können diese Spring Interceptor-Methode verwenden, um die Zeit zu bestimmen, die die Handler-Methode benötigt, um die Clientanfrage zu verarbeiten.
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): Dies ist eine HandlerInterceptor-Rückrufmethode, die aufgerufen wird, sobald der Handler ausgeführt und die Ansicht gerendert wurde.
Wenn mehrere Spring Interceptors konfiguriert sind, wird die preHandle()-Methode in der Reihenfolge der Konfiguration ausgeführt, während die postHandle()- und afterCompletion()-Methoden in umgekehrter Reihenfolge aufgerufen werden. Lassen Sie uns eine einfache Spring MVC-Anwendung erstellen, in der wir einen Spring Interceptor konfigurieren, um die Timings der Controller-Handler-Methode zu protokollieren. Unser finales Spring Interceptor-Beispielprojekt wird wie das folgende Bild aussehen, wir werden uns die Komponenten ansehen, die uns interessieren.
Spring Interceptor – Controller-Klasse
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);
//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";
}
}
Ich füge lediglich etwas Verarbeitungszeit bei der Ausführung der Handler-Methode hinzu, um unsere Spring Interceptor-Methoden in Aktion zu sehen.
Spring MVC Interceptor – HandlerInterceptorAdapter Implementierung
Zur Vereinfachung erweitere ich die abstrakte Klasse HandlerInterceptorAdapter. HandlerInterceptorAdapter ist eine abstrakte Adapterklasse für das HandlerInterceptor-Interface und dient der vereinfachten Implementierung von ausschließlich Pre- oder Post-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);
//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));
}
Die Logik ist wirklich einfach, ich protokolliere nur die Zeiten der Ausführung der Handler-Methode und die Gesamtzeit, die für die Verarbeitung der Anfrage einschließlich des Renderings der Ansichtsseite benötigt wird.
Spring MVC Interceptor-Konfiguration
Wir müssen den Spring Interceptor mit den Anfragen verbinden, dazu können wir das Element mvc:interceptors verwenden, um alle Interceptors zu verdrahten. Wir können auch ein URI-Muster angeben, das vor dem Einbeziehen des Spring Interceptors für die Anfrage durch das Mapping-Element abgeglichen werden muss. Unsere finale Spring Bean-Konfigurationsdatei (spring.xml) sieht wie unten aus.
<?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>
Ich werde nicht alle anderen Komponenten der Webanwendung erklären, da wir uns nicht dafür interessieren und sie keine spezifischen Konfigurationen im Zusammenhang mit Spring Interceptor haben.
Spring MVC Interceptor Anwendungstests
Stellen Sie einfach die Anwendung im Servlet-Container bereit und rufen Sie den Home-Controller auf, dann werden Sie eine Logger-Ausgabe ähnlich wie unten sehen.
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
Die Ausgabe bestätigt, dass die Spring Interceptor-Methoden in der definierten Reihenfolge ausgeführt werden. Das ist alles zur Verwendung von Spring Interceptors.