Spring MVC: objeto complejo como GET @RequestParam

Supongamos que tengo una página que enumera los objetos en una tabla y necesito poner un formulario para filtrar la tabla. El filtro se envía como Ajax GET a una URL como esa: http://foo.com/system/controller/action?page=1&prop1=x&prop2=y&prop3=z

Y en lugar de tener muchos parámetros en mi 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) { ... } 

Y suponiendo que tengo MyObject como:

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

Quiero hacer algo como:

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

¿Es posible? ¿Cómo puedo hacer eso?

Puede hacerlo, solo elimine la anotación @RequestParam , Spring enlazará limpiamente sus parámetros de solicitud a su instancia de clase:

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

Agregaré un breve ejemplo de mi parte.

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

Asignación de solicitud dentro de la clase de controlador:

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

Consulta:

 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 ayude 🙂

ACTUALIZACIÓN / KOTLIN

Porque actualmente estoy trabajando mucho con Kotlin si alguien quiere definir DTO similar, la clase en Kotlin debe tener la siguiente forma:

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

Con la clase de data como esta:

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

The Spring (probado en Boot) devuelve el siguiente error para la solicitud mencionada en la respuesta:

“Error al convertir el valor del tipo ‘java.lang.String []’ al tipo requerido ‘java.lang.Long []’; la excepción anidada es java.lang.NumberFormatException: para la cadena de entrada: \” 353,234 \ “”

La clase de datos solo funcionará para el siguiente formulario de solicitud de parámetros:

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

¡Ten en cuenta esto!

Tengo un problema muy similar. En realidad, el problema es más profundo, como yo pensaba. Estoy 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 predeterminado. Desafortunadamente basé mi sistema en eso y cuando necesité un objeto complejo como @RequestParam no pude hacerlo.

En mi caso, estoy tratando de enviar preferencias de usuario con algo así como;

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

Del lado del cliente, los datos brutos reales enviados al servidor son;

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

analizado como;

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

y el lado del servidor es;

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

Intenté @ModelAttribute , agregué setter / getters, constructores con todas las posibilidades a UserPreferences pero no tuve la oportunidad, ya que reconocía los datos enviados como 5 parámetros, pero de hecho el método mapeado tiene solo 2 parámetros. También probé la solución de Biju; sin embargo, lo que sucede es que Spring crea un objeto UserPreferences con el constructor predeterminado y no completa los datos.

Resolví el problema enviando cadena JSon de las preferencias desde el lado del cliente y lo manejo como si fuera una Cadena en el lado del 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 resumir, hice la conversión manualmente dentro del método REST. En mi opinión, el motivo por el cual Spring no reconoce los datos enviados es el tipo de contenido.