Lier une liste dans @RequestParam


127

J'envoie quelques paramètres à partir d'un formulaire de cette manière:

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

Je sais que je peux obtenir tous les paramètres de la méthode du contrôleur en ajoutant un paramètre comme

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

Je veux lier les paramètres myParam [] (pas les autres) à une liste ou un tableau (tout ce qui garde l'ordre d'index), j'ai donc essayé avec une syntaxe comme:

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

et

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

mais aucun d'entre eux ne lie les myParams. Même lorsque j'ajoute une valeur à la carte, il n'est pas possible de lier les paramètres:

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

Existe-t-il une syntaxe pour lier certains paramètres à une liste ou à un tableau sans avoir à créer un objet en tant que @ModelAttribute avec un attribut de liste?

Merci


Je ne pense pas que ce soit possible. Le code HandlerMethodInvoker.resolveRequestParamn'obtient que la première valeur
skaffman

6
( Spring Boot ): Est-ce à propos method = RequestMethod.GETou method = RequestMethod.POST? Si .GET @RequestParam List<String> groupValrempli avec ?groupVal=kkk,ccc,mmmsuccès ( Spring Boot )
basilic

Réponses:


77

Les tableaux dans @RequestParamsont utilisés pour lier plusieurs paramètres du même nom:

myparam=myValue1&myparam=myValue2&myparam=myValue3

Si vous avez besoin de lier @ModelAttributedes paramètres indexés de style, je suppose que vous en avez besoin de @ModelAttributetoute façon.


1
il peut y avoir des problèmes avec la commande (ce qui est très important à garder dans mon cas) car j'envoie les paramètres en sérialisant un formulaire et en envoyant i avec ajax. J'utiliserai la méthode @ModelAttribute "traditionnelle".
Javi

Savez-vous comment construire un URI avec ce mappage de tri avec UriTemplate, ou d'autres moyens? (pour un client de ce type de ressource).
Chomeh

En réponse à ma propre question, il apparaît que le printemps UriTemplate ne prend pas en charge RFC6570, utilisez l'implémentation damnhandy: stackoverflow.com/questions/14153036/…
Chomeh

110

Ou vous pouvez simplement le faire de cette façon:

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

Cela fonctionne par exemple pour des formulaires comme celui-ci:

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

C'est la solution la plus simple :)


4
cela préserve-t-il l'ordre?
andrew cooke

7
J'ai pu utiliser uniquement le nom plutôt que le [] au printemps 3.0 ainsi: @RequestParam (value = "myParam") String [] myParams
M Smith

3
Cependant, je ne partage pas les conclusions de @MSmith.
statisme du

2
Est-il possible d'obtenir List<String>grâce à cela. Il est également possible d'obtenir un java bean commeList<MyBean>
Juzer Ali

3
Je pense que vous pouvez supprimer les crochets du nom du paramètre.
theblang

19

En complément de ce que Donal Fellows a dit, vous pouvez utiliser List avec @RequestParam

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

J'espère que ça aide!


12

Abonnez-vous à ce que Basil a dit dans un commentaire à la question elle-même, si method = RequestMethod.GETvous pouvez l'utiliser @RequestParam List<String> groupVal.

Ensuite, appeler le service avec la liste des paramètres est aussi simple que:

API_URL?groupVal=kkk,ccc,mmm

10

Une façon d'accomplir cela (de manière hackish) est de créer une classe wrapper pour le List. Comme ça:

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

Ensuite, la signature de votre méthode de contrôleur ressemblerait à ceci:

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

Pas besoin d'utiliser l' annotation @RequestParamou @ModelAttributesi le nom de collection que vous passez dans la requête correspond au nom du champ de collection de la classe wrapper, dans mon exemple, vos paramètres de requête devraient ressembler à ceci:

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

Eh bien, c'est presque la même chose que d'utiliser @ModelAttribute, la seule différence est que le paramètre n'est pas annoté. Je voulais éviter @ModelAttribute simplement parce que je ne voulais pas créer de wrapper. J'ai lu quelque part dans stackoverflow (je ne me souviens pas où exactement) que si vous ajoutez un paramètre dans la méthode du contrôleur sans l'annotation @ModelAttribute (et ce n'était pas un objet spécial comme HttpRequest, HttpResponse ...), le framework le traitera comme s'il était annoté avec @ModelAttribute. Donc, si c'était vrai, c'est exactement comme avoir @ModelAttribute. Mais merci pour ta réponse.
Javi

4

Il n'était pas évident pour moi que bien que vous puissiez accepter une collection en tant que paramètre de demande, mais du côté du consommateur, vous devez toujours transmettre les éléments de la collection sous forme de valeurs séparées par des virgules .

Par exemple, si l'API côté serveur ressemble à ceci:

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

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

Passer directement une collection au RestTemplate en tant que RequestParam comme ci-dessous entraînera une corruption des données

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);
}

Au lieu de cela, vous pouvez utiliser

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);
}

L'exemple complet peut être trouvé ici , j'espère que cela évitera à quelqu'un le mal de tête :)


-7

Modifiez la valeur du champ masqué avec la case à cocher comme ci-dessous ...

HTML:

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

Scénario:

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

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

    } else {

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

    }

}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.