Binden einer Liste in @RequestParam

126

Ich sende einige Parameter aus einem Formular auf folgende Weise:

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

Ich weiß, dass ich alle Parameter in der Controller-Methode durch Hinzufügen eines Parameters wie erhalten kann

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

Ich möchte die Parameter myParam [] (nicht die anderen) an eine Liste oder ein Array binden (alles, was die Indexreihenfolge beibehält), also habe ich es mit einer Syntax wie der folgenden versucht:

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

und

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

aber keiner von ihnen bindet die myParams. Selbst wenn ich der Karte einen Wert hinzufüge, können die Parameter nicht gebunden werden:

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

Gibt es eine Syntax, um einige Parameter an eine Liste oder ein Array zu binden, ohne ein Objekt als @ModelAttribute mit einem Listenattribut erstellen zu müssen?

Vielen Dank

Javi
quelle
Ich denke nicht, dass das möglich ist. Der Code in HandlerMethodInvoker.resolveRequestParambekommt immer nur den ersten Wert
Skaffman
6
( Spring Boot ): Geht es um method = RequestMethod.GEToder method = RequestMethod.POST? Wenn erfolgreich .GET @RequestParam List<String> groupValerfüllt ?groupVal=kkk,ccc,mmm( Spring Boot )
Basilikum

Antworten:

76

Arrays in @RequestParamwerden zum Binden mehrerer gleichnamiger Parameter verwendet:

myparam=myValue1&myparam=myValue2&myparam=myValue3

Wenn Sie @ModelAttributeindizierte Parameter im Stil binden müssen, brauchen Sie diese wahrscheinlich @ModelAttributetrotzdem.

axtavt
quelle
1
Es kann Probleme mit der Reihenfolge geben (was in meinem Fall sehr wichtig ist), da ich die Parameter sende, indem ich ein Formular serialisiere und i mit Ajax sende. Ich werde den "traditionellen" @ ModelAttribute-Weg verwenden.
Javi
Würdest du zufällig wissen, wie man einen URI mit dieser Sortierzuordnung mit UriTemplate oder auf andere Weise erstellt? (für einen Kunden dieser Art von Ressource).
Chomeh
Wenn ich meine eigene Frage beantworte, scheint es, dass UriTemplate im Frühjahr RFC6570 nicht unterstützt. Verwenden Sie die verdammt gute Implementierung: stackoverflow.com/questions/14153036/…
Chomeh
110

Oder Sie könnten es einfach so machen:

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

Das funktioniert zum Beispiel bei solchen Formularen:

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

Dies ist die einfachste Lösung :)

Bernhard
quelle
4
Bewahrt das die Ordnung?
Andrew Cooke
7
Ich konnte also im Frühjahr 3.0 nur den Namen anstelle des [] verwenden: @RequestParam (value = "myParam") String [] myParams
M Smith
3
Ich teile die Ergebnisse von @MSmith jedoch nicht.
Droope
2
Ist es möglich, dadurch zu erhalten List<String>. Es ist auch möglich, eine Java-Bohne wieList<MyBean>
Juzer Ali
3
Ich denke, Sie können die Klammern aus dem Parameternamen entfernen.
Theblang
19

Als Ergänzung zu den Aussagen von Donal Fellows können Sie List mit @RequestParam verwenden

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

Ich hoffe es hilft!

Jorge Peres
quelle
12

Abonnieren Sie, was Basilikum in einem Kommentar zur Frage selbst gesagt hat, wenn method = RequestMethod.GETSie verwenden können@RequestParam List<String> groupVal .

Das Aufrufen des Dienstes mit der Liste der Parameter ist dann so einfach wie:

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

Eine Möglichkeit, dies (auf hackige Weise) zu erreichen, besteht darin, eine Wrapper-Klasse für die zu erstellen List. So was:

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

Dann würde Ihre Controller-Methodensignatur folgendermaßen aussehen:

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

Sie müssen die Annotation @RequestParamoder nicht verwenden, @ModelAttributewenn der Sammlungsname, den Sie in der Anforderung übergeben, mit dem Sammlungsfeldnamen der Wrapper-Klasse übereinstimmt. In meinem Beispiel sollten Ihre Anforderungsparameter folgendermaßen aussehen:

myList[0]     : 'myValue1'
myList[1]     : 'myValue2'
myList[2]     : 'myValue3'
otherParam    : 'otherValue'
anotherParam  : 'anotherValue'
Driangle
quelle
Dies entspricht fast der Verwendung von @ModelAttribute. Der einzige Unterschied besteht darin, dass der Parameter nicht mit Anmerkungen versehen ist. Ich wollte @ModelAttribute vermeiden, nur weil ich keinen Wrapper erstellen wollte. Ich habe irgendwo im Stackoverflow gelesen (ich kann mich nicht genau erinnern, wo), dass das Framework es behandelt, wenn Sie der Controller-Methode einen Parameter ohne @ ModelAttribute-Annotation hinzufügen (und es war kein spezielles Objekt wie HttpRequest, HttpResponse ...) wenn es mit @ModelAttribute kommentiert wäre. Wenn das wahr wäre, wäre dies genau so, als hätte man @ModelAttribute. Aber danke für deine Antwort.
Javi
4

Mir war nicht klar, dass Sie zwar eine Sammlung als Anforderungsparameter akzeptieren können, aber auf der Verbraucherseite die Sammlungselemente dennoch als durch Kommas getrennte Werte übergeben müssen .

Zum Beispiel, wenn die serverseitige API so aussieht:

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

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

Die direkte Übergabe einer Sammlung an das RestTemplate als RequestParam wie unten führt zu einer Beschädigung der Daten

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

Stattdessen können Sie verwenden

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

Das vollständige Beispiel finden Sie hier , hoffe, es erspart jemandem die Kopfschmerzen :)

Péter Veres
quelle
-7

Ändern Sie den Wert für versteckte Felder mit dem Kontrollkästchen wie unten umschalten ...

HTML:

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

Skript:

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

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

    } else {

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

    }

}
Khomeni
quelle