Inleiding tot Spring MVC HandlerInterceptor

1. Inleiding

In deze tutorial zullen we ons concentreren op het begrijpen van de Spring MVC HandlerInterceptor en hoe u het correct gebruikt.

2. Veer MVC Handler

Laten we, om de interceptor te begrijpen, een stap terug doen en naar het HandlerMapping. Dit wijst een methode toe aan een URL, zodat de DispatcherServlet zal er een beroep op kunnen doen bij het verwerken van een verzoek.

En de DispatcherServlet gebruikt de HandlerAdapter om de methode daadwerkelijk aan te roepen.

Nu we de algemene context begrijpen - dit is waar de handler interceptor binnenkomt. We gebruiken de HandlerInterceptor om acties uit te voeren vóór afhandeling, na afhandeling of na voltooiing (wanneer de weergave wordt weergegeven) van een verzoek.

De interceptor kan worden gebruikt voor transversale problemen en om repetitieve handlercodes zoals logboekregistratie, het wijzigen van wereldwijd gebruikte parameters in het Spring-model, enz. Te vermijden.

In de volgende secties is dat precies waar we naar gaan kijken - de verschillen tussen verschillende interceptorimplementaties.

3. Maven afhankelijkheden

Om te kunnen gebruiken Onderscheppers, moet u de volgende sectie opnemen in een afhankelijkheden sectie van uw pom.xml het dossier:

 org.springframework spring-web 5.2.8.RELEASE 

De laatste versie vind je hier.

4. Spring Handler Interceptor

Interceptors die werken met de HandlerMapping op het raamwerk moet de HandlerInterceptor koppel.

Deze interface bevat drie hoofdmethoden:

  • prehandle () - wordt aangeroepen voordat de daadwerkelijke handler wordt uitgevoerd, maar de weergave is nog niet gegenereerd
  • postHandle () - opgeroepen nadat de handler is uitgevoerd
  • na voltooiing() - wordt gebeld nadat het volledige verzoek is voltooid en de weergave is gegenereerd

Deze drie methoden bieden flexibiliteit om allerlei soorten voor- en nabewerking uit te voeren.

En een korte opmerking - het belangrijkste verschil tussen HandlerInterceptor en HandlerInterceptorAdapter is dat we in de eerste alle drie de methoden moeten negeren: preHandle (), postHandle () en na voltooiing(), terwijl we in de tweede alleen de vereiste methoden kunnen implementeren.

Een korte opmerking voordat we verder gaan - als je de theorie wilt overslaan en direct naar voorbeelden wilt springen, ga dan direct naar sectie 5.

Hier is wat een simpele preHandle () implementatie ziet er als volgt uit:

@Override public boolean preHandle (HttpServletRequest-verzoek, HttpServletResponse-antwoord, Object-handler) genereert Uitzondering {// uw code retourneert true; }

Merk op dat de methode een boolean waarde - die Spring vertelt of het verzoek verder moet worden verwerkt door een handler (waar) of niet (false).

Vervolgens hebben we een implementatie van postHandle ():

@Override public void postHandle (HttpServletRequest-verzoek, HttpServletResponse-antwoord, Objecthandler, ModelAndView modelAndView) genereert Uitzondering {// uw code}

Deze methode wordt onmiddellijk aangeroepen nadat het verzoek is verwerkt door HandlerAdapter, maar voordat een weergave wordt gegenereerd.

En het kan natuurlijk op veel manieren worden gebruikt - we kunnen bijvoorbeeld een avatar van een ingelogde gebruiker aan een model toevoegen.

De laatste methode die we moeten implementeren in de custom HandlerInterceptor implementatie is na voltooiing():

@Override public void afterCompletion (HttpServletRequest-verzoek, HttpServletResponse-antwoord, Objecthandler, Exception ex) {// jouw code}

Als de weergave met succes is gegenereerd, kunnen we deze hook gebruiken om dingen te doen zoals het verzamelen van aanvullende statistieken met betrekking tot het verzoek.

Een laatste opmerking om te onthouden is dat a HandlerInterceptor is geregistreerd bij de DefaultAnnotationHandlerMapping bean, die verantwoordelijk is voor het toepassen van interceptors op elke klasse gemarkeerd met een @Controller annotatie. Bovendien kunt u in uw webapplicatie een willekeurig aantal interceptors specificeren.

5. Aangepaste Logger Interceptor

In dit voorbeeld zullen we ons concentreren op het inloggen in onze webapplicatie. Allereerst moet onze klas worden uitgebreid HandlerInterceptorAdapter:

openbare klasse LoggerInterceptor breidt HandlerInterceptorAdapter {...} uit

We moeten ook inloggen op onze interceptor inschakelen:

privé statisch logger-logboek = LoggerFactory.getLogger (LoggerInterceptor.class);

Dit stelt Log4J in staat om logs weer te geven, en om aan te geven welke klasse momenteel informatie registreert naar de opgegeven output.

Laten we ons vervolgens concentreren op implementaties van aangepaste interceptor:

5.1. Methode preHandle ()

Deze methode wordt aangeroepen voordat een verzoek wordt afgehandeld; het keert terug waar, om het raamwerk toe te staan ​​het verzoek verder te sturen naar de afhandelingsmethode (of naar de volgende interceptor). Als de methode terugkeert false, Gaat Spring ervan uit dat het verzoek is afgehandeld en dat er geen verdere verwerking nodig is.

We kunnen de hook gebruiken om informatie over de parameters van de verzoeken te loggen: waar het verzoek vandaan komt, enz.

In ons voorbeeld loggen we deze informatie met behulp van een eenvoudige Log4J-logger:

@Override public boolean preHandle (HttpServletRequest-verzoek, HttpServletResponse-antwoord, Objecthandler) genereert Uitzondering {log.info ("[preHandle] [" + request + "]" + "[" + request.getMethod () + "]" + verzoek .getRequestURI () + getParameters (verzoek)); terugkeer waar; } 

Zoals we kunnen zien, registreren we wat basisinformatie over het verzoek.

Als we hier een wachtwoord tegenkomen, moeten we ervoor zorgen dat we dat natuurlijk niet loggen.

Een eenvoudige optie is om wachtwoorden en elk ander gevoelig type gegevens te vervangen door sterren.

Hier is een snelle implementatie van hoe dat kan worden gedaan:

private String getParameters (verzoek HttpServletRequest) {StringBuffer gepost = nieuwe StringBuffer (); Opsomming 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 ("wachtwoord") || 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 (verzoek): ip; if (ipAddr! = null &&! ipAddr.equals ("")) {posted.append ("& _ psip =" + ipAddr); } return posted.toString (); }

Ten slotte proberen we het bron-IP-adres van het HTTP-verzoek te krijgen.

Hier is een eenvoudige implementatie:

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

5.2. Methode postHandle ()

Deze haak loopt wanneer de HandlerAdapter wordt aangeroepen de handler maar DispatcherServlet moet de weergave nog weergeven.

We kunnen deze methode gebruiken om extra attributen toe te voegen aan de ModelAndView of om de tijd te bepalen die de afhandelingsmethode nodig heeft om het verzoek van een cliënt te verwerken.

In ons geval loggen we gewoon een verzoek net daarvoor in DispatcherServlet gaat een weergave maken.

@Override public void postHandle (HttpServletRequest-verzoek, HttpServletResponse-antwoord, Objecthandler, ModelAndView modelAndView) genereert Uitzondering {log.info ("[postHandle] [" + request + "]"); }

5.3. Methode na voltooiing()

Wanneer een verzoek is voltooid en de weergave is weergegeven, kunnen we verzoek- en antwoordgegevens verkrijgen, evenals informatie over eventuele uitzonderingen:

@Override public void afterCompletion (HttpServletRequest-verzoek, HttpServletResponse-antwoord, Object-handler, Exception ex) genereert Uitzondering {if (ex! = Null) {ex.printStackTrace (); } log.info ("[afterCompletion] [" + request + "] [uitzondering:" + ex + "]"); }

6. Configuratie

Om onze interceptors toe te voegen aan de Spring-configuratie, moeten we overschrijven addInterceptors () methode binnen Webconfiguratie klasse die implementeert WebMvcConfigurer:

@Override public void addInterceptors (InterceptorRegistry-register) {registry.addInterceptor (nieuwe LoggerInterceptor ()); }

We kunnen dezelfde configuratie bereiken door ons XML Spring-configuratiebestand te bewerken:

Als deze configuratie actief is, is de interceptor actief en worden alle verzoeken in de applicatie correct gelogd.

Houd er rekening mee dat als er meerdere Spring-interceptors zijn geconfigureerd, de preHandle () methode wordt uitgevoerd in de volgorde van configuratie, terwijl postHandle () en na voltooiing() methoden worden in omgekeerde volgorde aangeroepen.

Als we Spring Boot gebruiken in plaats van vanilla Spring, moeten we in gedachten houden om onze configuratieklasse niet te annoteren met @EnableWebMvc, of we verliezen de automatische configuraties van Boot.

7. Conclusie

Deze tutorial is een korte inleiding tot het onderscheppen van HTTP-verzoeken met Spring MVC Handler Interceptor.

Alle voorbeelden en configuraties zijn hier beschikbaar op GitHub.