2016-01-15 10 views
8

Ich versuche, einige bestimmte Parameter von RequestMapping Methoden zu lösen, um Werte aus dem Anfragetext zu extrahieren und validiert sie und injizieren sie in bestimmte annotierte Parameter.Wie kann ich im Frühling 'HandlerMethodArgumentResolver' den Anfragetext mehrmals lesen?

@Override 
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, 
           NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 
    // 1, get corresponding input parameter from NativeWebRequest 
    // 2, validate 
    // 3, type convertion and assemble value to return 
    return null; 
} 

Das größte Problem ist, dass ich herausfinden, dass HttpServletRequest (erhalten von NativeWebRequest) Eingangsstrom nicht (einige Parameter in der Anfrage Körper) lesen kann mehr als einmal. Also, wie kann ich Inputstream/Reader oder die Anfrage Körper mehr als einmal abrufen?

+0

Eine Lösung könnte sein, ein ThreadLocal zu verwenden, um Parameter innerhalb eines Filters aus einer Anfrage zu speichern und sie dann beliebig oft in Ihrem Code zu verwenden. –

+0

@SandeepPoonia Dies kann helfen. Aber ein Problem ist, wenn ich den Körper in den Threadlocal (durch Aufruf von HttpServletRequest.getReader/getInputStream) speichern, wird dies nie wieder aufgerufen werden. Event in der Controller-Ebene kann ich nicht "@RequestBody String body" deklarieren (was eine Ausnahme durch Spring auslösen kann), weil Spring den Input-Stream nicht mehr lesen kann. – Kim

Antwort

16

Sie können einen Filter hinzufügen, den aktuellen HttpServletRequest abfangen und in eine benutzerdefinierte HttpServletRequestWrapper umbrechen. In Ihrer benutzerdefinierten HttpServletRequestWrapper, lesen Sie den Anfragetext und Cache und implementieren Sie dann getInputStream und getReader aus dem zwischengespeicherten Wert zu lesen. Da nach der Anforderung Einwickeln, die im Cache gespeicherte Wert immer vorhanden ist, können Sie die Anfrage Körper mehrmals lesen:

@Component 
public class CachingRequestBodyFilter extends GenericFilterBean { 
    @Override 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) 
      throws IOException, ServletException { 
     HttpServletRequest currentRequest = (HttpServletRequest) servletRequest; 
     MultipleReadHttpRequest wrappedRequest = new MultipleReadHttpRequest(currentRequest); 
     chain.doFilter(wrappedRequest, servletResponse); 
    } 
} 

Nach diesem Filter wird jeder die wrappedRequest sehen, welche die Fähigkeit zu lesenden mehrfach hat:

Für die Implementierung MultipleReadHttpRequest, können Sie einen Blick auf ContentCachingRequestWrapper von Feder-Framework, die im Grunde die gleiche Sache ist.

Dieser Ansatz hat seine eigenen Nachteile. Zunächst ist es etwas ineffizient, da der Anfragetext für jede Anfrage mindestens zweimal gelesen wird. Der andere wichtige Nachteil ist, wenn Ihr Anfragekörper 10 GB Wert des Stromes enthält, lesen Sie, dass 10 GB Daten und sogar schlechter dieses in Gedächtnis für weitere Prüfung holen.

+1

Ja, das ist die beste Lösung bisher. Aber die Effizienz ist wirklich ein großes Problem. Ich denke, dass ich einen Weg finden muss, die Eingabestromgröße einzuschränken, falls jemand Sabotage oder etwas Ähnliches anwendet. Da der Anfragetext zumindest zweimal gelesen wird, halte ich das für akzeptabel, da ich nur json-formatierte Eingabezeichenfolgen aus dem Anfragetext akzeptiere, die normalerweise weniger als 1kb/pr. – Kim

+1

Das vollständige Beispiel finden Sie in dieser Antwort: https://StackOverflow.com/a/17129256/364401 – Stim

Verwandte Themen