Spring MVC: object complexo como GET @RequestParam

Suponha que eu tenha uma página que lista os objects em uma tabela e preciso colocar um formulário para filtrar a tabela. O filtro é enviado como um Ajax GET para um URL como este: http://foo.com/system/controller/action?page=1&prop1=x&prop2=y&prop3=z

E em vez de ter muitos parâmetros no meu controlador como:

@RequestMapping(value = "/action") public @ResponseBody List myAction( @RequestParam(value = "page", required = false) int page, @RequestParam(value = "prop1", required = false) String prop1, @RequestParam(value = "prop2", required = false) String prop2, @RequestParam(value = "prop3", required = false) String prop3) { ... } 

E supondo que eu tenho MyObject como:

 public class MyObject { private String prop1; private String prop2; private String prop3; //Getters and setters ... } 

Eu quero fazer algo como:

 @RequestMapping(value = "/action") public @ResponseBody List myAction( @RequestParam(value = "page", required = false) int page, @RequestParam(value = "myObject", required = false) MyObject myObject,) { ... } 

É possível? Como eu posso fazer isso?

Você pode absolutamente fazer isso, basta remover a anotação @RequestParam , o Spring ligará seus parâmetros de solicitação à sua instância de class:

 public @ResponseBody List myAction( @RequestParam(value = "page", required = false) int page, MyObject myObject) 

Vou adicionar um pequeno exemplo de mim.

A class DTO:

 public class SearchDTO { private Long id[]; public Long[] getId() { return id; } public void setId(Long[] id) { this.id = id; } // reflection toString from apache commons @Override public String toString() { return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE); } } 

Solicitar mapeamento dentro da class do controlador:

 @RequestMapping(value="/handle", method=RequestMethod.GET) @ResponseBody public String handleRequest(SearchDTO search) { LOG.info("criteria: {}", search); return "OK"; } 

Inquerir:

 http://localhost:8080/app/handle?id=353,234 

Resultado:

 [http-apr-8080-exec-7] INFO cggrfwExampleController.handleRequest:59 - criteria: SearchDTO[id={353,234}] 

Espero que ajude 🙂

UPDATE / KOTLIN

Porque atualmente eu estou trabalhando muito com o Kotlin se alguém quiser definir um DTO similar a class no Kotlin deve ter o seguinte formato:

 class SearchDTO { var id: Array? = arrayOf() override fun toString(): String { // to string implementation } } 

Com a class de data como esta:

 data class SearchDTO(var id: Array = arrayOf()) 

O Spring (testado no Boot) retorna o seguinte erro para o pedido mencionado na resposta:

“Falha ao converter o valor do tipo ‘java.lang.String []’ para o tipo requerido ‘java.lang.Long []’; a exceção aninhada é java.lang.NumberFormatException: Para a cadeia de input: \” 353.234 \ “”

A class de dados funcionará apenas para o seguinte formulário de parâmetros de solicitação:

 http://localhost:8080/handle?id=353&id=234 

Esteja ciente disso!

Eu tenho um problema muito similar. Na verdade, o problema é mais profundo, como eu pensava. Eu estou usando jquery $.post que usa Content-Type:application/x-www-form-urlencoded; charset=UTF-8 Content-Type:application/x-www-form-urlencoded; charset=UTF-8 como padrão. Infelizmente eu @RequestParam meu sistema nisso e quando eu precisei de um object complexo como @RequestParam eu não poderia simplesmente fazer acontecer.

No meu caso, estou tentando enviar preferências de usuário com algo parecido;

  $.post("/updatePreferences", {id: 'pr', preferences: p}, function (response) { ... 

No lado do cliente, os dados brutos reais enviados para o servidor são;

 ... id=pr&preferences%5BuserId%5D=1005012365&preferences%5Baudio%5D=false&preferences%5Btooltip%5D=true&preferences%5Blanguage%5D=en ... 

analisado como;

 id:pr preferences[userId]:1005012365 preferences[audio]:false preferences[tooltip]:true preferences[language]:en 

e o lado do servidor é;

 @RequestMapping(value = "/updatePreferences") public @ResponseBody Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") UserPreferences preferences) { ... return someService.call(preferences); ... } 

Eu tentei @ModelAttribute , adicionado setter / getters, construtores com todas as possibilidades para UserPreferences mas nenhuma chance, uma vez que reconheceu os dados enviados como 5 parâmetros, mas na verdade o método mapeado tem apenas 2 parâmetros. Eu também tentei a solução da Biju, mas o que acontece é que, a primavera cria um object UserPreferences com o construtor padrão e não preenche os dados.

Eu resolvi o problema enviando JSon string das preferências do lado do cliente e lidava com isso como se fosse uma String no lado do servidor;

cliente:

  $.post("/updatePreferences", {id: 'pr', preferences: JSON.stringify(p)}, function (response) { ... 

servidor:

 @RequestMapping(value = "/updatePreferences") public @ResponseBody Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") String preferencesJSon) { String ret = null; ObjectMapper mapper = new ObjectMapper(); try { UserPreferences userPreferences = mapper.readValue(preferencesJSon, UserPreferences.class); return someService.call(userPreferences); } catch (IOException e) { e.printStackTrace(); } } 

para breve, eu fiz a conversão manualmente dentro do método REST. Na minha opinião, a razão pela qual a primavera não reconhece os dados enviados é o tipo de conteúdo.