2016-08-01 7 views
0

Ich habe ein Szenario, wo ich ein paar db-Checks zu Beginn jeder Web-Anfrage ausführen muss, und im Erfolgsfall muss ich Objekte für den Einsatz speichern später in der Anfrage durch den Controller oder im Falle eines Fehlers muss ich eine Fehlerseite rendern.Spring Boot - Laufprüfung auf jede Anfrage und Speichern von Objekten für den Lebenszyklus

Ein sehr ähnliches Beispiel aus der realen Welt wäre eine SaaS-App, die das Konto anhand einer Vanity-URL prüft und lädt und dann das Konto zur Verwendung durch Controller speichert, um mehrere Datenbankanforderungen zu vermeiden.

Was sind die besten Möglichkeiten, dies in einer Spring Boot App zu erreichen? Ich habe mit Filtern experimentiert, aber ich denke, dass ein Interceptor bei der Aufgabe besser sein könnte, was das Ausführen des Checks abdeckt, aber was ist mit dem Speichern der Objekte für den späteren Gebrauch? Gibt es einen Request-Lifecycle-Kontext irgendeiner Art, gegen den ich speichern kann?

Antwort

1

Nach meiner Erfahrung ist der beste Weg, ich habe ähnliche Sachen gemacht, durch HandlerMethodArgumentResolver.

Stellen Sie sich vor, Sie haben einen benutzerdefinierten Typ, nennen wir ihn UserContext, in dem Sie die Informationen speichern, die für die Anforderung benötigt werden. Und Sie haben eine UserContextService haben wir eine Methode getUserContext(HttServletRequest), die verwendet wird, um den Kontext basierend auf der Anfrage abrufen, aus denen Sie Ihre Datenbank basierend auf was Anfrage Parameter/Header/Pfad-Variable, usw. aufrufen können. Sie können das verfeinern wie du es brauchst. Aber auf der Grundlage dieser einfachen Annahmen, können Sie einen Controller haben, der wie folgt aussieht:

@RequestMapping("/some/url") 
public SomeResponse someMethod(UserContext userContext, ...) { 
    //do something here with UserContext 
} 

Die Art und Weise, dass der Frühling dieses Usercontext in Ihrem Controller injizieren würde HandlerMethodArgumentResolver wie diese mit einem benutzerdefinierten sein:

@Component 
public class UserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { 

    @Autowired 
    UserContextService 

    @Override 
    public boolean supportsParameter(MethodParameter parameter) { 
     return parameter.getParameterType().equals(UserContext.class); 
    } 

    @Override 
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 
     HttpServletRequest req = (HttpServletRequest)webRequest.getNativeRequest(); 
     UserContext userContext = userContextService.getUserContext(req); 
     if (userContext != null) { 
      return userContext; 
     } else { 
      return WebArgumentResolver.UNRESOLVED; 
      //Or throw exception 
     } 
    } 
} 

Das registrieren Sie, indem Sie die WebMvcConfigurer.addArgumentResolvers Methode in Ihrer WebMvcConfigurer Bean/Config-Klasse überschreiben.

Dieser Mechanismus ist die gleiche von @PathVariable verwendet, @RequestParam, etc ...

+0

den Vorschlag schätzen, ich bin ein wenig gegen Ich gebe jedoch zu, dass es letztendlich expressiver und testbarer sein kann. Die Methode, die ich gemacht habe, besteht darin, sie in einer Request-Bean zu speichern und Hilfsmethoden zu meinem Basis-Controller hinzuzufügen, von dem alle anderen Controller erben . – matthewrk

+0

Es wird nur passieren, wo es passieren muss (d. H. Wo Sie den Parameter deklarieren), genau wie jeder andere URL Param oder Pfadvariable, plus Spring ist bereits voll von Injektion und Reflexion. Ihre Lösung scheint in Ordnung zu sein, obwohl einige Kupplungs- und Kesselplatten durch diese Methode vermieden werden können. – Ulises