Enlazar una lista en @RequestParam

126

Estoy enviando algunos parámetros desde un formulario de esta manera:

myparam[0]     : 'myValue1'
myparam[1]     : 'myValue2'
myparam[2]     : 'myValue3'
otherParam     : 'otherValue'
anotherParam   : 'anotherValue' 
...

Sé que puedo obtener todos los parámetros en el método del controlador agregando un parámetro como

public String controllerMethod(@RequestParam Map<String, String> params){
    ....
}

Quiero vincular los parámetros myParam [] (no los otros) a una lista o matriz (cualquier cosa que mantenga el orden del índice), así que he intentado con una sintaxis como:

public String controllerMethod(@RequestParam(value="myParam") List<String> myParams){
    ....
}

y

public String controllerMethod(@RequestParam(value="myParam") String[] myParams){
    ....
}

pero ninguno de ellos vincula los myParams. Incluso cuando agrego un valor al mapa, no puede vincular los parámetros:

public String controllerMethod(@RequestParam(value="myParam") Map<String, String> params){
    ....
}

¿Existe alguna sintaxis para vincular algunos parámetros a una lista o matriz sin tener que crear un objeto como @ModelAttribute con un atributo de lista?

Gracias

Javi
fuente
No creo que esto sea posible. El código HandlerMethodInvoker.resolveRequestParamsolo obtiene el primer valor
skaffman
66
( Spring Boot ): ¿Se trata de method = RequestMethod.GETo method = RequestMethod.POST? Si se .GET @RequestParam List<String> groupValcumple con ?groupVal=kkk,ccc,mmméxito ( Spring Boot )
albahaca el

Respuestas:

76

Las matrices en @RequestParamse utilizan para vincular varios parámetros del mismo nombre:

myparam=myValue1&myparam=myValue2&myparam=myValue3

Si necesita vincular @ModelAttributeparámetros indexados al estilo, supongo que lo necesita de @ModelAttributetodos modos.

axtavt
fuente
1
Puede haber problemas con el pedido (que es muy importante mantener en mi caso) porque envío los parámetros serializando un formulario y enviando i con ajax. Usaré la forma "tradicional" @ModelAttribute.
Javi
¿Sabrías cómo construir un URI con este tipo de mapeo con UriTemplate, o algún otro medio? (para un cliente de este tipo de recurso).
Chomeh
Respondiendo a mi propia pregunta, parece que la primavera UriTemplate no es compatible con RFC6570, usa la implementación maldita: stackoverflow.com/questions/14153036/…
Chomeh
110

O simplemente podría hacerlo de esa manera:

public String controllerMethod(@RequestParam(value="myParam[]") String[] myParams){
    ....
}

Eso funciona, por ejemplo, para formas como esta:

<input type="checkbox" name="myParam[]" value="myVal1" />
<input type="checkbox" name="myParam[]" value="myVal2" />

Esta es la solución más simple :)

Bernhard
fuente
44
¿eso preserva el orden?
Andrew Cooke
77
Pude usar solo el nombre en lugar del [] en Spring 3.0, por lo tanto: @RequestParam (value = "myParam") String [] myParams
M Smith
3
Sin embargo, no comparto los hallazgos de @MSmith.
droope
2
¿Es posible obtener a List<String>través de esto? También es posible obtener un frijol java comoList<MyBean>
Juzer Ali
3
Creo que puedes quitar los corchetes del nombre del parámetro.
theblang
19

Simplemente complementando lo que dijo Donal Fellows, puede usar List con @RequestParam

public String controllerMethod(@RequestParam(value="myParam") List<ObjectToParse> myParam){
....
}

¡Espero eso ayude!

Jorge Peres
fuente
12

Suscribiendo lo que dijo albahaca en un comentario a la pregunta en sí, si method = RequestMethod.GETpuede usarlo @RequestParam List<String> groupVal.

Entonces llamar al servicio con la lista de parámetros es tan simple como:

API_URL?groupVal=kkk,ccc,mmm
Juangui Jordán
fuente
11

Una forma de lograr esto (de una manera hack) es crear una clase de contenedor para el List. Me gusta esto:

class ListWrapper {
     List<String> myList; 
     // getters and setters
}

Entonces la firma de su método de controlador se vería así:

public String controllerMethod(ListWrapper wrapper) {
    ....
}

No es necesario usar la anotación @RequestParamo @ModelAttributesi el nombre de la colección que pasa en la solicitud coincide con el nombre del campo de la colección de la clase wrapper, en mi ejemplo, los parámetros de su solicitud deberían verse así:

myList[0]     : 'myValue1'
myList[1]     : 'myValue2'
myList[2]     : 'myValue3'
otherParam    : 'otherValue'
anotherParam  : 'anotherValue'
driangle
fuente
Bueno, esto es casi lo mismo que usar @ModelAttribute, la única diferencia es que el parámetro no está anotado. Quería evitar @ModelAttribute solo porque no quería crear un contenedor. Leí en algún lugar de stackoverflow (no recuerdo exactamente dónde) que si agrega un parámetro en el método del controlador sin la anotación @ModelAttribute (y no era un objeto especial como HttpRequest, HttpResponse ...) el marco lo trata como si estuviera anotado con @ModelAttribute. Entonces, si eso fuera cierto, esto es exactamente como tener @ModelAttribute. Pero gracias por tu respuesta.
Javi
4

No era obvio para mí que, aunque puede aceptar una Colección como parámetro de solicitud, pero en el lado del consumidor , todavía tiene que pasar los elementos de la colección como valores separados por comas .

Por ejemplo, si la API del lado del servidor se ve así:

@PostMapping("/post-topics")
public void handleSubscriptions(@RequestParam("topics") Collection<String> topicStrings) {

    topicStrings.forEach(topic -> System.out.println(topic));
}

Pasar directamente una colección al RestTemplate como RequestParam como se muestra a continuación provocará la corrupción de datos

public void subscribeToTopics() {

    List<String> topics = Arrays.asList("first-topic", "second-topic", "third-topic");

    RestTemplate restTemplate = new RestTemplate();
    restTemplate.postForEntity(
            "http://localhost:8088/post-topics?topics={topics}",
            null,
            ResponseEntity.class,
            topics);
}

En cambio, puedes usar

public void subscribeToTopics() {

    List<String> topicStrings = Arrays.asList("first-topic", "second-topic", "third-topic");
    String topics = String.join(",",topicStrings);

    RestTemplate restTemplate = new RestTemplate();
    restTemplate.postForEntity(
            "http://localhost:8088/post-topics?topics={topics}",
            null,
            ResponseEntity.class,
            topics);
}

El ejemplo completo se puede encontrar aquí , espero que le ahorre a alguien el dolor de cabeza :)

Péter Veres
fuente
-7

Cambie el valor del campo oculto con la casilla de verificación como se muestra a continuación ...

HTML:

<input type='hidden' value='Unchecked' id="deleteAll" name='anyName'>
<input type="checkbox"  onclick="toggle(this)"/> Delete All

Guión:

function toggle(obj) {`var $input = $(obj);
    if ($input.prop('checked')) {

    $('#deleteAll').attr( 'value','Checked');

    } else {

    $('#deleteAll').attr( 'value','Unchecked');

    }

}
Khomeni
fuente