Wiązanie listy w @RequestParam

127

Przesyłam parametry z formularza w ten sposób:

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

Wiem, że mogę uzyskać wszystkie parametry w metodzie kontrolera, dodając parametr taki jak

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

Chcę powiązać parametry myParam [] (nie inne) z listą lub tablicą (cokolwiek, co zachowuje kolejność indeksów), więc próbowałem użyć składni takiej jak:

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

i

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

ale żaden z nich nie wiąże myParams. Nawet gdy dodam wartość do mapy, nie jest w stanie powiązać parametrów:

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

Czy istnieje jakakolwiek składnia do wiązania niektórych parametrów z listą lub tablicą bez konieczności tworzenia obiektu jako @ModelAttribute z atrybutem listy w nim?

Dzięki

Javi
źródło
Nie sądzę, żeby to było możliwe. Kod w HandlerMethodInvoker.resolveRequestParamtylko zawsze otrzymuje pierwszą wartość
skaffman
6
( Spring Boot ): Czy o method = RequestMethod.GETlub method = RequestMethod.POST? Jeśli .GET @RequestParam List<String> groupValspełniony z ?groupVal=kkk,ccc,mmmpowodzeniem ( Spring Boot )
bazylia

Odpowiedzi:

77

Tablice w programie @RequestParamsłużą do wiązania kilku parametrów o tej samej nazwie:

myparam=myValue1&myparam=myValue2&myparam=myValue3

Jeśli potrzebujesz powiązać @ModelAttributeparametry indeksowane w stylu, myślę, że i @ModelAttributetak potrzebujesz .

axtavt
źródło
1
mogą wystąpić problemy z zamówieniem (co jest bardzo ważne w moim przypadku), ponieważ wysyłam parametry poprzez serializowanie formularza i wysyłanie i za pomocą ajax. Użyję „tradycyjnego” sposobu @ModelAttribute.
Javi,
Czy wiesz, jak zbudować identyfikator URI z tym mapowaniem sortowania za pomocą UriTemplate lub w inny sposób? (dla klienta tego rodzaju zasobu).
Chomeh
Odpowiadając na moje własne pytanie, wydaje się, że wiosna UriTemplate nie obsługuje RFC6570, użyj cholernej implementacji: stackoverflow.com/questions/14153036/ ...
Chomeh
110

Lub możesz to zrobić w ten sposób:

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

Działa to na przykład w przypadku takich formularzy:

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

To najprostsze rozwiązanie :)

Bernhard
źródło
4
czy to zachowuje porządek?
andrew Cooke
7
Dzięki temu mogłem użyć tylko nazwy zamiast [] na wiosnę 3.0: @RequestParam (value = "myParam") String [] myParams
M Smith
3
Nie podzielam jednak ustaleń @MSmith.
opadanie
2
Czy można to uzyskać List<String>. Możliwe jest również zdobycie fasoli javaList<MyBean>
Juzer Ali
3
Myślę, że możesz usunąć nawiasy z nazwy parametru.
theblang
19

Uzupełniając tylko to, co powiedział Donal Fellows, możesz użyć List z @RequestParam

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

Mam nadzieję, że to pomoże!

Jorge Peres
źródło
12

Subskrybowanie tego, co powiedziała bazylia w komentarzu do samego pytania, jeśli method = RequestMethod.GETmożesz użyć @RequestParam List<String> groupVal.

Wtedy wywołanie serwisu z listą parametrów jest tak proste, jak:

API_URL?groupVal=kkk,ccc,mmm
Juangui Jordán
źródło
11

Jednym ze sposobów, w jaki można to osiągnąć (w hakerski sposób), jest utworzenie klasy opakowującej dla List. Lubię to:

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

Wtedy podpis metody kontrolera wyglądałby następująco:

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

Nie ma potrzeby używania adnotacji @RequestParamlub, @ModelAttributejeśli nazwa kolekcji, którą przekazujesz w żądaniu, jest zgodna z nazwą pola kolekcji klasy opakowania, w moim przykładzie parametry żądania powinny wyglądać następująco:

myList[0]     : 'myValue1'
myList[1]     : 'myValue2'
myList[2]     : 'myValue3'
otherParam    : 'otherValue'
anotherParam  : 'anotherValue'
trójkąt
źródło
Cóż, jest to prawie to samo, co użycie @ModelAttribute, jedyną różnicą jest to, że parametr nie jest opatrzony adnotacją. Chciałem uniknąć @ModelAttribute tylko dlatego, że nie chciałem tworzyć opakowania. Czytałem gdzieś w stackoverflow (nie pamiętam gdzie dokładnie), że jeśli dodasz parametr w metodzie kontrolera bez adnotacji @ModelAttribute (i nie był to specjalny obiekt jak HttpRequest, HttpResponse ...) framework traktuje to jako gdyby był opatrzony adnotacją @ModelAttribute. Więc jeśli to prawda, to dokładnie tak, jakby to było @ModelAttribute. Ale dzięki za odpowiedź.
Javi
4

Nie było dla mnie oczywiste, że chociaż możesz zaakceptować Collection jako parametr żądania, ale po stronie konsumenta nadal musisz przekazywać elementy kolekcji jako wartości oddzielone przecinkami .

Na przykład, jeśli interfejs API po stronie serwera wygląda następująco:

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

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

Bezpośrednie przekazanie kolekcji do RestTemplate jako RequestParam, jak poniżej, spowoduje uszkodzenie danych

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

Zamiast tego możesz użyć

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

Kompletny przykład można znaleźć tutaj , mam nadzieję, że oszczędza to komuś bólu głowy :)

Péter Veres
źródło
-7

Zmień wartość ukrytego pola za pomocą przełącznika pola wyboru, jak poniżej ...

HTML:

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

Scenariusz:

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

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

    } else {

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

    }

}
Khomeni
źródło