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 un 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<MyObject> 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 miObjeto 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<MyObject> myAction(
@RequestParam(value = "page", required = false) int page,
@RequestParam(value = "myObject", required = false) MyObject myObject,) { ... }
Es posible? ¿Cómo puedo hacer eso?
3 answers
Puede hacer eso, simplemente elimine la anotación @RequestParam
, Spring enlazará limpiamente sus parámetros de solicitud a su instancia de clase:
public @ResponseBody List<MyObject> myAction(
@RequestParam(value = "page", required = false) int page,
MyObject myObject)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-05 14:16:49
Voy a añadir un pequeño ejemplo de mí.
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);
}
}
Solicitud de asignación dentro de la clase del 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 c.g.g.r.f.w.ExampleController.handleRequest:59 - criteria: SearchDTO[id={353,234}]
Espero que ayude :)
UPDATE / KOTLIN
Porque actualmente estoy trabajando mucho con Kotlin si alguien quiere definir DTO similar la clase en Kotlin debería tener la siguiente forma:
class SearchDTO {
var id: Array<Long>? = arrayOf()
override fun toString(): String {
// to string implementation
}
}
Con la clase data
como esta:
data class SearchDTO(var id: Array<Long> = arrayOf())
La Primavera (tested in 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 data solo funcionará para el siguiente formulario de parámetros de solicitud:
http://localhost:8080/handle?id=353&id=234
Sea consciente de esto!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-18 09:00:51
Tengo un problema muy similar. En realidad el problema es más profundo como pensaba. Estoy usando jquery $.post
que usa Content-Type:application/x-www-form-urlencoded; charset=UTF-8
como predeterminado. Desafortunadamente, basé mi sistema en eso y cuando necesitaba un objeto complejo como @RequestParam
no podía simplemente hacerlo realidad.
En mi caso estoy tratando de enviar preferencias de usuario con algo como;
$.post("/updatePreferences",
{id: 'pr', preferences: p},
function (response) {
...
En el lado del cliente los datos sin procesar 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 is;
@RequestMapping(value = "/updatePreferences")
public
@ResponseBody
Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") UserPreferences preferences) {
...
return someService.call(preferences);
...
}
Probé @ModelAttribute
, añadí setter/getters, constructores con todas las posibilidades a UserPreferences
pero ninguna posibilidad ya que reconoció 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 constructor predeterminado y no rellena los datos.
Resolví el problema enviando una cadena JSon de las preferencias desde el lado del cliente y lo manejé 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, la razón por la que Spring no reconoce los datos enviados es el tipo de contenido.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-26 01:47:56