Einführung in Spring MVC HandlerInterceptor

Einführung in Spring MVC HandlerInterceptor

1. Einführung

In diesem Tutorial konzentrieren wir uns darauf, die Spring MVCHandlerInterceptorzu verstehen und wie man sie richtig verwendet. __

2. Spring MVC Handler

Um den Interceptor zu verstehen, treten wir einen Schritt zurück und schauen uns dieHandlerMappingan. Dadurch wird eine Methode einer URL zugeordnet, sodassDispatcherServlet sie bei der Verarbeitung einer Anforderung aufrufen kann.

UndDispatcherServlet verwendetHandlerAdapter, um die Methode tatsächlich aufzurufen.

Nachdem wir den Gesamtkontext verstanden haben -this is where the handler interceptor comes in. Wir verwenden dieHandlerInterceptor, um Aktionen vor der Verarbeitung, nach der Verarbeitung oder nach Abschluss (wenn die Ansicht gerendert wird) einer Anforderung auszuführen.

Der Interceptor kann für übergreifende Probleme verwendet werden und um sich wiederholende Handler-Codes wie Protokollierung, Ändern global verwendeter Parameter im Spring-Modell usw. zu vermeiden.

In den nächsten Abschnitten werden wir uns genau damit befassen - die Unterschiede zwischen verschiedenen Interceptor-Implementierungen.

3. Maven-Abhängigkeiten

UmInterceptors verwenden zu können, müssen Sie den folgenden Abschnitt in einendependencies-Abschnitt Ihrerpom.xml-Datei aufnehmen:


    org.springframework
    spring-web
    5.0.6.RELEASE

Die neueste Version finden Sie inhere.

4. Spring Handler Interceptor

Interceptors, die mitHandlerMapping im Framework arbeiten, müssen dieHandlerInterceptor-Schnittstelle implementieren.

Diese Schnittstelle enthält drei Hauptmethoden:

  • prehandle() - wird aufgerufen, bevor der eigentliche Handler ausgeführt wird, aber die Ansicht wird noch nicht generiert

  • postHandle() -after genannt, wird der Handler ausgeführt

  • afterCompletion() – heißtafter the complete request has finished and view was generated

Diese drei Methoden bieten Flexibilität für alle Arten der Vor- und Nachbearbeitung.

Und eine kurze Anmerkung - der Hauptunterschied zwischenHandlerInterceptor undHandlerInterceptorAdapter besteht darin, dass wir in der ersten alle drei Methoden überschreiben müssen:preHandle(),postHandle() undafterCompletion(), während wir im zweiten möglicherweise nur die erforderlichen Methoden implementieren.

Eine kurze Anmerkung, bevor wir weiter gehen - wenn Sie die Theorie überspringen und direkt zu Beispielen springen möchten, springen Sie direkt in Abschnitt 5.

So sieht eine einfache Implementierung vonpreHandle()aus:

@Override
public boolean preHandle(
  HttpServletRequest request,
  HttpServletResponse response,
  Object handler) throws Exception {
    // your code
    return true;
}

Beachten Sie, dass die Methode einen Wert vonbooleanzurückgibt. Dies teilt Spring mit, ob die Anforderung von einem Handler weiterverarbeitet werden soll (true) oder nicht (false).

Als nächstes haben wir eine Implementierung vonpostHandle():

@Override
public void postHandle(
  HttpServletRequest request,
  HttpServletResponse response,
  Object handler,
  ModelAndView modelAndView) throws Exception {
    // your code
}

Diese Methode wird unmittelbar nach der Verarbeitung der Anforderung durchHandlerAdapter, jedoch vor dem Generieren einer Ansicht aufgerufen.

Und es kann natürlich auf viele Arten verwendet werden - zum Beispiel können wir einem Modell einen Avatar eines angemeldeten Benutzers hinzufügen.

Die letzte Methode, die wir in der benutzerdefinierten Implementierung vonHandlerInterceptorimplementieren müssen, istafterCompletion():

@Override
public void afterCompletion(
  HttpServletRequest request,
  HttpServletResponse response,
  Object handler, Exception ex) {
    // your code
}

Wenn die Ansicht erfolgreich generiert wurde, können wir diesen Hook verwenden, um zusätzliche Statistiken im Zusammenhang mit der Anforderung zu erfassen.

Ein letzter Hinweis ist, dass einHandlerInterceptor in derDefaultAnnotationHandlerMapping-Bean registriert ist, die für das Anwenden von Interceptors auf jede Klasse verantwortlich ist, die mit einer@Controller-Annotation gekennzeichnet ist. Darüber hinaus können Sie in Ihrer Webanwendung eine beliebige Anzahl von Interceptors angeben.

5. Benutzerdefinierter Logger Interceptor

In diesem Beispiel konzentrieren wir uns auf die Anmeldung in unserer Webanwendung. Zunächst muss unsere KlasseHandlerInterceptorAdapter verlängern:

public class LoggerInterceptor extends HandlerInterceptorAdapter {
    ...
}

Wir müssen auch die Protokollierung in unserem Abfangjäger aktivieren:

private static Logger log = LoggerFactory.getLogger(LoggerInterceptor.class);

Auf diese Weise kann Log4J Protokolle anzeigen und angeben, welche Klasse derzeit Informationen für die angegebene Ausgabe protokolliert.

Als nächstes konzentrieren wir uns auf benutzerdefinierte Interceptor-Implementierungen:

5.1. MethodepreHandle()

Diese Methode wird aufgerufen, bevor eine Anforderung verarbeitet wird. Es gibttrue, zurück, damit das Framework die Anforderung weiter an die Handler-Methode (oder an den nächsten Interceptor) senden kann. Wenn die Methodefalse zurückgibt, geht Spring davon aus, dass die Anforderung verarbeitet wurde und keine weitere Verarbeitung erforderlich ist.

Wir können den Hook verwenden, um Informationen über die Parameter der Anforderungen zu protokollieren: Woher kommt die Anforderung usw.

In unserem Beispiel protokollieren wir diese Informationen mit einem einfachen Log4J-Logger:

@Override
public boolean preHandle(
  HttpServletRequest request,
  HttpServletResponse response,
  Object handler) throws Exception {

    log.info("[preHandle][" + request + "]" + "[" + request.getMethod()
      + "]" + request.getRequestURI() + getParameters(request));

    return true;
}

Wie wir sehen können, protokollieren wir einige grundlegende Informationen zu der Anfrage.

Falls wir hier auf ein Passwort stoßen, müssen wir natürlich sicherstellen, dass wir das nicht protokollieren.

Eine einfache Möglichkeit besteht darin, Kennwörter und andere sensible Datentypen durch Sterne zu ersetzen.

Hier ist eine schnelle Implementierung, wie dies getan werden kann:

private String getParameters(HttpServletRequest request) {
    StringBuffer posted = new StringBuffer();
    Enumeration e = request.getParameterNames();
    if (e != null) {
        posted.append("?");
    }
    while (e.hasMoreElements()) {
        if (posted.length() > 1) {
            posted.append("&");
        }
        String curr = (String) e.nextElement();
        posted.append(curr + "=");
        if (curr.contains("password")
          || curr.contains("pass")
          || curr.contains("pwd")) {
            posted.append("*****");
        } else {
            posted.append(request.getParameter(curr));
        }
    }
    String ip = request.getHeader("X-FORWARDED-FOR");
    String ipAddr = (ip == null) ? getRemoteAddr(request) : ip;
    if (ipAddr!=null && !ipAddr.equals("")) {
        posted.append("&_psip=" + ipAddr);
    }
    return posted.toString();
}

Schließlich möchten wir die Quell-IP-Adresse der HTTP-Anforderung ermitteln.

Hier ist eine einfache Implementierung:

private String getRemoteAddr(HttpServletRequest request) {
    String ipFromHeader = request.getHeader("X-FORWARDED-FOR");
    if (ipFromHeader != null && ipFromHeader.length() > 0) {
        log.debug("ip from proxy - X-FORWARDED-FOR : " + ipFromHeader);
        return ipFromHeader;
    }
    return request.getRemoteAddr();
}

5.2. MethodepostHandle()

Dieser Hook wird ausgeführt, wennHandlerAdapter vom Handler aufgerufen wird,DispatcherServlet die Ansicht jedoch noch nicht gerendert hat.

Mit dieser Methode können wir denModelAndView zusätzliche Attribute hinzufügen oder die Zeit bestimmen, die die Handler-Methode benötigt, um die Anforderung eines Clients zu verarbeiten.

In unserem Fall protokollieren wir einfach eine Anforderung, kurz bevorDispatcherServlet eine Ansicht rendert.

@Override
public void postHandle(
  HttpServletRequest request,
  HttpServletResponse response,
  Object handler,
  ModelAndView modelAndView) throws Exception {

    log.info("[postHandle][" + request + "]");
}

5.3. MethodeafterCompletion()

Wenn eine Anforderung abgeschlossen und die Ansicht gerendert ist, erhalten wir möglicherweise Anforderungs- und Antwortdaten sowie Informationen zu Ausnahmen, falls eine aufgetreten ist:

@Override
public void afterCompletion(
  HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex)
  throws Exception {
    if (ex != null){
        ex.printStackTrace();
    }
    log.info("[afterCompletion][" + request + "][exception: " + ex + "]");
}

6. Aufbau

Um unsere Interceptors zur Spring-Konfiguration hinzuzufügen, müssen wir die MethodeaddInterceptors()innerhalb der KlasseWebConfigüberschreiben, dieWebMvcConfigurer: implementiert

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoggerInterceptor());
}

Wir können dieselbe Konfiguration erreichen, indem wir unsere XML Spring-Konfigurationsdatei bearbeiten:


    

Wenn diese Konfiguration aktiviert ist, ist der Interceptor aktiv und alle Anforderungen in der Anwendung werden ordnungsgemäß protokolliert.

Bitte beachten Sie, dass bei Konfiguration mehrerer Spring Interceptors die MethodepreHandle() in der Reihenfolge der Konfiguration ausgeführt wird, während die MethodenpostHandle() undafterCompletion()in umgekehrter Reihenfolge aufgerufen werden.

7. Fazit

Dieses Tutorial bietet eine kurze Einführung in das Abfangen von HTTP-Anforderungen mit Spring MVC Handler Interceptor.

Alle Beispiele und Konfigurationen finden Sie hier aufGitHub.