2010-02-23 9 views
19

HttpServletRequest.getParameterValues() devuelve un String[] que contiene todos los valores de un parámetro de solicitud HTTP determinado. ¿Alguien sabe si el orden de los valores en esta matriz está garantizado por la especificación de por el mismo que el orden en el que se pasaron esos valores en la solicitud?El pedido de valores en HttpServletRequest.getParameterValues ​​()

Por ejemplo, si tengo la cadena de consulta GET x=1&x=2&x=3, soy yo garantizado para recibir el String[] {"1", "2", "3"} cuando llamo getParameterValues()? Parece funcionar en la práctica, pero no puedo encontrar nada que especifique que este debe ser el caso, por lo que soy reacio a confiar en ello.

+1

Como HttpServletRequest es una interfaz, depende de su implementación. Aunque me sorprendería si hay una implementación que no devuelve los valores en el orden recibido. – Fortega

+0

La documentación de la interfaz * puede * dictar el comportamiento si el diseñador así lo elige, pero en este caso no lo han hecho. – skaffman

Respuesta

13

El javadoc para ServletRequest (v2.5 javadoc) no menciona nada sobre el orden de los valores para ese método. Como tal, no confiaría en que el orden se preservara.


Actualización: También comprueba el documento de especificaciones de 2.5, contiene la siguiente información relacionada con getParameterValues ​​(). No menciona nada sobre ordenar con respecto a la cadena de consulta, por lo que creo que el comportamiento que está viendo es detalle de implementación, no definido como parte de la interfaz.

Los parámetros se almacenan como un conjunto de pares de nombre-valor. Pueden existir valores de parámetro múltiple para cualquier nombre de parámetro dado . Los siguientes métodos de la interfaz ServletRequest son a disposición de parámetros de acceso:

  • getParameter
  • getParameterNames
  • getParameterValues ​​
  • getParameterMap

El getParameterVa lues method devuelve una matriz de objetos String que contienen todos los los valores de los parámetros asociados con un nombre de parámetro . El valor devuelto del método getParameter debe ser el primer valor en la matriz de String objetos devueltos por getParameterValues. El método getParameterMap devuelve un java.util.Map del parámetro de la solicitud , que contiene nombres como claves y valores de parámetros como valores de mapa.

Para referencia futura, las especificaciones de Java Servlet se pueden descargar desde Sun, I mean Oracle's website. Puede verificar la versión específica del servlet que le interese allí.

7

De hecho, no es definied explícitamente en la especificación de servlets, pero al menos los formularios HTML espec definies explícitamente en la sección application/x-www-form-urlencoded:

2. Los nombres de los controles/valores se enumeran en el orden en que aparecen en el documento.

Por lo tanto, esa parte es segura.Ahora el servletcontainer, lógicamente una implementación decente y eficiente procesaría el flujo de entrada HTTP inmediatamente cuando entra, por lo que los parámetros se procesarían en el orden tal como aparecen en el URI de solicitud (GET) o cuerpo de solicitud (POST). Recopilarlos en un String[] es la elección más sencilla, ya que también se usa tal como está en la API de Servlet, así que realmente no veo ninguna razón para recopilarlo en una estructura similar a HashSet, o hacer un Collections#shuffle() o lo que sea y luego convertirlo a String[] después.

Al menos puedo decir por experiencia, Tomcat lo hace de la manera correcta, por lo que todos los principales contenedores/servidores de aplicaciones que se construyen sobre Tomcat/Catalina (IBM Websphere, JBoss AS, Sun Glassfish, etc.) también se comportarán . No tengo experiencia práctica con Weblogic, pero me sorprendería si lo procesa de manera diferente (léase: de manera menos eficiente).

Solo el pedido del parámetro nombres no está garantizado, lógicamente porque está respaldado por un HashMap.


Resumido: los parámetros se recogen en un HashMap<String, String[]>. Los nombres están codificados como no ordenados debido a la naturaleza del HashMap. Los valores (un nombre de parámetro puede tener varios valores, por ejemplo, foo=bar1&foo=bar2&foo=bar3) están a su vez ordenados debido a la naturaleza de String[], aunque esto no se especifica explícitamente en la API del servlet.

Para mayor seguridad, le gustaría usar un enfoque diferente, p.

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

con

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

Confiar en algo que no es obligatorio por las especificaciones de Servlet es en mi humilde opinión un error. Si lo hace, solo corra el riesgo de que su aplicación no sea portátil. Claro, uno puede argumentar que la implementación del contenedor no es eficiente, pero eso no cambia nada, es la expectativa de que estuvo mal al final (independientemente de cuántas implementaciones utilicen Tomcat). –

+0

Es un caso de esquina. – BalusC

+2

Las especificaciones de servlet realmente deberían hacer cumplir una orden. Esto haría que los parámetros con valores múltiples sean mucho más útiles porque podría correlacionar parámetros relacionados de una fila de tabla, por ejemplo. – Ryan

0

Depende de HttpServletRequest implementación de la interfaz.

+8

¿Por qué repites un comentario/respuesta ya dado? Agregue algo nuevo o simplemente modifique la respuesta con la que está de acuerdo y avance :) – BalusC

10

Sí, el orden de los valores devueltos por getParamterValues(String) y entradas en getParameterMap()es garantizado por la especificación Servlet. Aquí está el pasaje:

datos de la cadena de consulta y el cuerpo después se agregan en la solicitud conjunto de parámetros. Los datos de la cadena de consulta se presentan antes de los datos del cuerpo de publicación . Por ejemplo, si una solicitud es hecha con una cadena de consulta de a = hello y un cuerpo de publicación de a = adiós & a = world, el conjunto de parámetros resultante sería ordenado a = (hola, adiós, mundo).

(Esto es de la sección "Parámetros de protocolo HTTP" dentro "de la Solicitud" capítulo de las especificaciones Servlet (SRV.4.1 en la versión 2.4, SRV.3.1 en la versión 2.5).)

Hay no parece ser una forma limpia de obtener los nombres en orden (getParameterNames()no devolver nombres en el orden que dio el navegador). Podría, supongo, analizar la cadena GET en bruto desde getQueryString() o analizar la cadena de POST sin procesar desde getInputStream(), pero en su lugar creo que agregaré otro parámetro oculto y luego usaré getParameterValues(String) para obtener su orden.

Si tienes curiosidad por qué quiero los parámetros en orden, es porque tengo los controles que el usuario puede reordenar usando jQuery, y quiero saber el orden que el usuario ha elegido:

<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

Esto no dice (explícitamente) nada sobre el orden dentro de los datos de la cadena de consulta o los datos del cuerpo de la publicación, solo que 'datos del cuerpo de la publicación' debe aparecer después de ' datos de cadena de consulta'. Una garantía completa está implícita en el ejemplo, y la implementación de referencia respeta el orden original, pero ... – beetstra

2

Tengo un problema para extraer el mapa de valor param de HttpServletRequest de acuerdo con los elementos en el JSP. Escribí un OrderedRequestMap que analiza un cuerpo de solicitud POST de application/x-www-form-urlencoded.

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 = ""; 
} 

y llamarlo como esto

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

Esperanza, que ayuda.

Cuestiones relacionadas