2010-02-23 16 views
19

HttpServletRequest.getParameterValues() gibt eine String[] zurück, die alle Werte eines bestimmten HTTP-Anforderungsparameters enthält. Weiß jemand, ob die Reihenfolge der Werte in diesem Array durch die Spezifikation garantiert wird, die der Reihenfolge entspricht, in der diese Werte in der Anforderung übergeben wurden?Reihenfolge der Werte in HttpServletRequest.getParameterValues ​​()

Zum Beispiel, wenn ich die GET-Abfrage-String x=1&x=2&x=3 haben, bin ich die String[] {"1", "2", "3"} erhalten garantiert, wenn ich getParameterValues() nennen? Es scheint in der Praxis zu funktionieren, aber ich kann nichts finden, was besagt, dass dies der Fall sein muss, daher zögere ich, mich darauf zu verlassen.

+1

Da HttpServletRequest eine Schnittstelle ist, hängt es von seiner Implementierung ab. Obwohl ich würde überrascht sein, wenn es eine Implementierung gibt, die die Werte in der Reihenfolge nicht zurückgibt. – Fortega

+0

Dokumentation der Schnittstelle * kann Verhalten diktieren, wenn der Designer dies wünscht, aber in diesem Fall nicht. – skaffman

Antwort

13

Das Javadoc für ServletRequest (v2.5 javadoc) erwähnt nichts über die Reihenfolge der Werte für diese Methode. Daher würde ich mich nicht darauf verlassen, dass die Reihenfolge erhalten bleibt.


Update: auch das spec Dokument für 2,5 geprüft, enthält die folgenden Informationen zu getParameterValues ​​beziehen(). Es wird nichts über die Reihenfolge in Bezug auf die Abfragezeichenfolge erwähnt. Daher denke ich, dass es sich bei dem angezeigten Verhalten um Implementierungsdetails handelt, die nicht als Teil der Schnittstelle definiert sind.

Die Parameter werden als Satz von Name-Wert-Paaren gespeichert. Mehrere Parameter Werte können für jeden gegebenen Parameternamen existieren. Die folgenden Methoden der ServletRequest Schnittstelle sind Verfügung Zugangsparameter:

  • getParameter
  • getParameterNames
  • getParameterValues ​​
  • getParameterMap

Die getParameterVa Lues-Methode gibt ein Array von String-Objekten zurück, das alle Parameterwerte enthält, die einem Parameternamen zugeordnet sind. Der von der getParameter-Methode zurückgegebene Wert muss der erste Wert im Array von String Objekte sein, die von getParameterValues ​​zurückgegeben werden. Die Methode getParameterMap gibt eine java.util.Map des Parameters der Anforderung zurück, die Namen als Schlüssel und Parameterwerte als Kartenwerte enthält.

Für zukünftige Referenz können die Java Servlet-Spezifikationen von Sun, I mean Oracle's website heruntergeladen werden. Sie können die spezifische Servlet-Version, an der Sie interessiert sind, dort überprüfen.

7

Es ist in der Tat nicht explizit in der Servlet-Spezifikation definiertem, aber die HTML-Formulare spec definies zumindest explizit im application/x-www-form-urlencoded Abschnitt:

2. Steuer Namen/Werte in der Reihenfolge, in sie erscheinen aufgeführt sind das Dokument.

Also, dieser Teil ist sicher.Nun würde der Servletcontainer, logisch eine vernünftige und effiziente Implementierung, den HTTP-Eingabestream sofort verarbeiten, so wie er hereinkommt, so dass die Parameter in der Reihenfolge verarbeitet würden, wie sie im Anfrage-URI (GET) oder Anfrage-Body (POST) erscheinen. Sammeln sie in einem String[] ist die einfachste Wahl, wie es auch ist wie in der Servlet-API verwendet, so sehe ich wirklich keinen Grund, es in einer HashSet Struktur wie zuerst zu sammeln, oder tun Sie eine Collections#shuffle() oder was auch immer und dann wandle es danach in String[] um.

Ich kann zumindest aus Erfahrung sagen, Tomcat tut es richtig, so dass auch alle großen Container/Anwendungen, die auf Tomcat/Catalina (IBM Websphere, JBoss AS, Sun Glassfish, etc.) gebaut werden . Ich habe keine Erfahrung mit Weblogic, aber ich würde mich wundern, wenn es anders verarbeitet wird (sprich: weniger effizient).

Nur die Bestellung des Parameters Namen ist nicht garantiert, logisch, weil es von einem HashMap unterstützt wird.


Zusammengefasst: Die Parameter in einem HashMap<String, String[]> gesammelt werden. Die Namen sind garantiert nicht wegen der Art der HashMap bestellt. Die Werte (ein Parametername kann mehrere Werte haben, z. B. foo=bar1&foo=bar2&foo=bar3) sind wiederum aufgrund der Natur von String[] geordnet, obwohl dies nicht explizit in der Servlet-API spezifiziert ist.

Um auf der sicheren Seite zu sein, möchten Sie einen anderen Ansatz verwenden, z.

foos=3&foo[0]=bar1&foo[1]=bar2&foo[2]=bar3 

mit

int foos = Integer.valueOf(request.getParameter("foos")); 
for (int i = 0; i < foos; i++) { 
    int foo = Integer.valueOf(request.getParameter("foo[" + i + "]")); 
} 
+2

Sich auf etwas zu verlassen, das nicht von der Servlet-Spezifikation vorgeschrieben ist, ist IMHO ein Fehler. Wenn Sie dies tun, nehmen Sie einfach das Risiko, um Ihre Anwendung nicht tragbar zu machen. Sicher kann man darüber streiten, dass die Containerimplementierung nicht effizient ist, aber das ändert nichts, es ist die Erwartung, die am Ende falsch war (unabhängig davon, wie viele Implementierungen Tomcat verwenden). –

+0

Es ist ein Eckfall. – BalusC

+2

Die Servlet-Spezifikation sollte wirklich eine Bestellung erzwingen. Dies würde Parameter mit mehreren Werten viel nützlicher machen, weil Sie verwandte Parameter beispielsweise einer Tabellenzeile zuordnen könnten. – Ryan

0

Es hängt von HttpServletRequest Interface-Implementierung.

+8

Warum wiederholst du einen bereits gegebenen Kommentar/Antwort? Bitte fügen Sie etwas Neues hinzu oder aktualisieren Sie einfach die Antwort mit der Sie einverstanden sind und gehen Sie weiter :) – BalusC

10

Ja, die Reihenfolge der Werte von getParamterValues(String) und Einträge in getParameterMap()zurückgekehrt ist durch die Servlet-Spezifikation garantiert. Hier ist der Passus:

Daten aus der Abfrage-String und der Post Körper aggregiert in den Anfrage Parametersatz. Abfragezeichenfolge Daten werden vor dem Nachrichtentext Daten angezeigt. Zum Beispiel, wenn eine Anfrage ist gemacht mit einer Abfrage-String von a = Hallo und ein Post-Körper von a = Auf Wiedersehen & a = Welt, wäre der resultierende Parametersatz bestellt a = (Hallo, auf Wiedersehen, Welt).

(Dies ist aus dem "HTTP-Protokoll-Parameter" im Rahmen der "Request" Kapitel der Servlet-Spezifikationen (SRV.4.1 in Version 2.4, SRV.3.1 in Version 2.5).)

Es nicht scheint ein sauberer Weg, um die Namen in Reihenfolge zu bekommen (getParameterNames() tut nicht Namen in der Reihenfolge, die der Browser gab zurückgeben). Ich könnte, denke ich, die rohe GET-Zeichenfolge von getQueryString() analysieren oder die rohe POST-Zeichenfolge von getInputStream() analysieren, aber stattdessen denke ich, dass ich einen weiteren versteckten Parameter hinzufügen und dann getParameterValues(String) verwenden werde, um seine Reihenfolge zu erhalten.

Wenn Sie neugierig sind, warum ich auf die Parameter, um möchten, ist es, weil ich Steuerelemente haben, die der Benutzer neu anordnen können jQuery verwenden, und ich möchte, um die Reihenfolge wissen, dass der Benutzer gewählt hat:

<form> 
    <ul id=variables> 
    <li> 
     <input name=hello>hello 
     <input type=hidden name=variableOrder value=hello> 
    <li> 
     <input name=world>world 
     <input type=hidden name=variableOrder value=world> 
    </ul> 
</form> 
<script src="jquery.js"></script> 
<script src="jquery-ui.js"></script> 
<script> 
    jQuery('#variables').sortable().disableSelection(); 
</script> 
+5

Dies sagt nichts über die Reihenfolge in Query String Daten oder Post Body Daten, nur dass "post body data" nach 'erscheint Abfrage Zeichenfolge Daten. Im Beispiel ist eine vollständige Garantie enthalten, und die Referenzimplementierung respektiert die ursprüngliche Reihenfolge, aber ... – beetstra

2

Ich habe ein Problem, param-value map aus HttpServletRequest in der Reihenfolge in Übereinstimmung mit Elementen auf der JSP zu extrahieren. Ich schrieb eine OrderedRequestMap, die einen Anwendungs ​​/ x-www-form-urlencoded POST-Anfragetext parsiert.

import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.UnsupportedEncodingException; 
import java.net.URLDecoder; 
import java.util.Arrays; 
import java.util.LinkedHashMap; 
import java.util.Map; 


public class OrderedRequestMap extends LinkedHashMap<String,String[]> { 

private final String encoding; 

public OrderedRequestMap(InputStream httpBody, String encoding) throws IOException { 
    this.encoding = encoding; 
    fill(httpBody); 
} 

private void fill(InputStream is) throws IOException { 
    final InputStreamReader reader = new InputStreamReader(is, "ASCII"); 
    int c; 
    StringBuilder sb = new StringBuilder(1000); 
    while ((c = reader.read()) != -1) { 
     char ch = (char)c; 
     if (ch == '&') { 
      put(sb.toString()); 
      sb = new StringBuilder(1000); 
     } else { 
      sb.append(ch); 
     } 
    } 
    put(sb.toString()); 
} 

private void put(String parameter) throws UnsupportedEncodingException { 
    String[] pair = parameter.split("="); 
    if (pair.length == 0) 
     return; 
    String key = URLDecoder.decode(pair[0], encoding); 
    String val = EMPTY_STR; 
    if (pair.length > 1) 
     val = URLDecoder.decode(pair[1], encoding); 
    String[] values = get(key); 
    if (values == null) 
     values = new String[]{val}; 
    else { 
     values = Arrays.copyOf(values, values.length+1); 
     values[values.length - 1] = val; 
    } 
    put(key, values); 
} 


private static final String EMPTY_STR = ""; 
} 

Und nennen Sie es wie dieser

new OrderedRequestMap(request.getInputStream(), request.getCharacterEncoding()); 

Hoffnung, es hilft.

Verwandte Themen