Vinculando uma lista em @RequestParam

126

Estou enviando alguns parâmetros de um formulário desta maneira:

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

Eu sei que posso obter todos os parâmetros no método do controlador adicionando um parâmetro como

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

Eu quero vincular os parâmetros myParam [] (não os outros) a uma lista ou matriz (qualquer coisa que mantenha a ordem do índice), então tentei com uma sintaxe como:

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

e

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

mas nenhum deles está vinculando os myParams. Mesmo quando adiciono um valor ao mapa, ele não pode vincular os parâmetros:

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

Existe alguma sintaxe para vincular alguns parâmetros a uma lista ou matriz sem precisar criar um objeto como @ModelAttribute com um atributo de lista?

obrigado

Javi
fonte
Eu não acho que isso seja possível. O código HandlerMethodInvoker.resolveRequestParamsó já recebe o primeiro valor
skaffman
6
( Spring Boot ): É sobre method = RequestMethod.GETou method = RequestMethod.POST? Se .GET @RequestParam List<String> groupValcumprido com ?groupVal=kkk,ccc,mmmêxito ( Spring Boot )
basil

Respostas:

76

Matrizes em @RequestParamsão usadas para vincular vários parâmetros com o mesmo nome:

myparam=myValue1&myparam=myValue2&myparam=myValue3

Se você precisar vincular @ModelAttributeparâmetros indexados no estilo, acho que precisa @ModelAttribute.

axtavt
fonte
1
pode haver problemas com o pedido (o que é muito importante manter no meu caso) porque eu envio os parâmetros serializando um formulário e enviando i com ajax. Usarei a maneira @ tradicional "@ModelAttribute.
Javi
Você saberia como construir um URI com esse mapeamento de classificação com o UriTemplate ou algum outro meio? (para um cliente desse tipo de recurso).
Chomeh 4/15
Respondendo à minha própria pergunta, parece que a primavera o UriTemplate não suporta RFC6570, use a implementação maldita: stackoverflow.com/questions/14153036/…
Chomeh
110

Ou você pode fazer dessa maneira:

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

Isso funciona, por exemplo, para formulários como este:

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

Esta é a solução mais simples :)

Bernhard
fonte
4
isso preserva a ordem?
andrew cooke
7
Eu era capaz de usar apenas o nome, e não o [] no Spring 3.0, da seguinte forma: @RequestParam (value = "myParam") String [] myParams
M Smith
3
Mas não compartilho as descobertas do @MSmith.
droope
2
É possível obter List<String>através disso. Também é possível obter um feijão java comoList<MyBean>
Juzer Ali
3
Eu acho que você pode remover os colchetes do nome do parâmetro.
theblang
19

Apenas complementando o que Donal Fellows disse, você pode usar a Lista com @RequestParam

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

Espero que ajude!

Jorge Peres
fonte
12

Inscrevendo o que o manjericão disse em um comentário à própria pergunta, se method = RequestMethod.GETvocê puder usar @RequestParam List<String> groupVal.

Em seguida, chamar o serviço com a lista de parâmetros é tão simples quanto:

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

Uma maneira de conseguir isso (de uma maneira imprudente) é criar uma classe de wrapper para o List. Como isso:

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

Em seguida, sua assinatura do método do controlador ficaria assim:

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

Não é necessário usar a anotação @RequestParamou @ModelAttributese o nome da coleção que você passar na solicitação corresponder ao nome do campo de coleção da classe wrapper, no meu exemplo, os parâmetros da sua solicitação devem ter a seguinte aparência:

myList[0]     : 'myValue1'
myList[1]     : 'myValue2'
myList[2]     : 'myValue3'
otherParam    : 'otherValue'
anotherParam  : 'anotherValue'
driangle
fonte
Bem, isso é quase o mesmo que usar @ModelAttribute, a única diferença é que o parâmetro não é anotado. Eu queria evitar o @ModelAttribute apenas porque não queria criar um wrapper. Eu li em algum lugar no stackoverflow (não me lembro exatamente) que se você adicionar um parâmetro no método controller sem a anotação @ModelAttribute (e não era um objeto especial como HttpRequest, HttpResponse ...), a estrutura o tratará como se tiver sido anotado com @ModelAttribute. Portanto, se isso fosse verdade, é exatamente como ter @ModelAttribute. Mas obrigado pela sua resposta.
Javi
4

Não era óbvio para mim que, embora você possa aceitar uma coleção como um parâmetro de solicitação, mas no lado do consumidor você ainda precisa passar os itens da coleção como valores separados por vírgula .

Por exemplo, se a API do lado do servidor estiver assim:

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

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

Passar diretamente uma coleção para o RestTemplate como um RequestParam como abaixo resultará em corrupção de dados

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

Em vez disso, você pode 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);
}

O exemplo completo pode ser encontrado aqui , espero que isso evite dores de cabeça para alguém :)

Péter Veres
fonte
-7

Altere o valor do campo oculto com a caixa de seleção, como abaixo ...

HTML:

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

Roteiro:

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

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

    } else {

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

    }

}
Khomeni
fonte