Spring MVC: objeto complejo como GET @RequestParam

Resuelto renanleandrof asked hace 11 años • 7 respuestas

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 GET Ajax a una URL como esta: 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 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<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    @RequestParam(value = "myObject", required = false) MyObject myObject,) { ... }

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

renanleandrof avatar Jun 05 '13 21:06 renanleandrof
Aceptado

Absolutamente puedes hacer eso, simplemente elimina la @RequestParamanotación, Spring vinculará limpiamente los parámetros de tu solicitud a tu instancia de clase:

public @ResponseBody List<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    MyObject myObject)
Biju Kunjummen avatar Jun 05 '2013 14:06 Biju Kunjummen

Agregaré un breve ejemplo mío.

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

Solicitar mapeo 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  c.g.g.r.f.w.ExampleController.handleRequest:59 - criteria: SearchDTO[id={353,234}]

Espero que ayude :)

ACTUALIZACIÓN / KOTLIN

Debido a que actualmente estoy trabajando mucho con Kotlin, si alguien quiere definir un 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 dataclase como esta:

data class SearchDTO(var id: Array<Long> = arrayOf())

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 funcionará solo para el siguiente formulario de parámetros de solicitud:

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

¡Ten en cuenta esto!

Przemek Nowak avatar Sep 10 '2014 14:09 Przemek Nowak

Dado que la pregunta sobre cómo configurar los campos como obligatorios aparece debajo de cada publicación, escribí un pequeño ejemplo sobre cómo configurar los campos como obligatorios:

public class ExampleDTO {
    @NotNull
    private String mandatoryParam;

    private String optionalParam;
    
    @DateTimeFormat(iso = ISO.DATE) //accept Dates only in YYYY-MM-DD
    @NotNull
    private LocalDate testDate;

    public String getMandatoryParam() {
        return mandatoryParam;
    }
    public void setMandatoryParam(String mandatoryParam) {
        this.mandatoryParam = mandatoryParam;
    }
    public String getOptionalParam() {
        return optionalParam;
    }
    public void setOptionalParam(String optionalParam) {
        this.optionalParam = optionalParam;
    }
    public LocalDate getTestDate() {
        return testDate;
    }
    public void setTestDate(LocalDate testDate) {
        this.testDate = testDate;
    }
}

//Add this to your rest controller class
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String testComplexObject (@Valid ExampleDTO e){
    System.out.println(e.getMandatoryParam() + " " + e.getTestDate());
    return "Does this work?";
}
FluffyDestroyerOfCode avatar Feb 08 '2019 13:02 FluffyDestroyerOfCode