2011-06-01 15 views
33

Estoy corriendo una aplicación web en la primavera de MVC Web 3.0 y tengo una serie de métodos de controlador cuyas firmas son aproximadamente como sigue:primavera Web MVC - validar la petición individual params

@RequestMapping(value = "/{level1}/{level2}/foo", method = RequestMethod.POST) 
public ModelAndView createFoo(@PathVariable long level1, 
     @PathVariable long level2, 
     @RequestParam("foo_name") String fooname, 
     @RequestParam(value = "description", required = false) String description); 

me gustaría añadir alguna validación, por ejemplo, description debe limitarse a una cierta longitud o fooname solo debe contener ciertos caracteres. Si esta validación falla, quiero devolver un mensaje al usuario en lugar de lanzar una excepción sin marcar (lo que sucedería de todos modos si dejo que los datos bajen a la capa DAO). Soy consciente de JSR303 pero no he trabajado con él y no entiendo cómo aplicarlo en un contexto de primavera.

Por lo que entiendo, otra opción sería vincular el @RequestBody a un objeto de dominio completo y agregar restricciones de validación allí, pero actualmente mi código está configurado para aceptar parámetros individuales como se muestra arriba.

¿Cuál es la forma más directa de aplicar la validación a los parámetros de entrada usando este enfoque?

+0

me gustaría probar usando javax.validation anotaciones allí y ver si funciona. No sé si lo hace :) – Bozho

+0

¿Puedes dar más detalles? ¿Usaría la anotación en la declaración del parámetro como lo hago con '@ RequestParam'? – Dan

+0

Además, esta no es una aplicación Java EE y no se ejecuta en un contenedor Java EE, es solo una aplicación web dinámica que se ejecuta en un contenedor de servlets. – Dan

Respuesta

23

No hay nada incorporado para hacer eso, notyet de todos modos. Con las versiones de lanzamiento actuales, necesitará usar WebDataBinder para vincular sus parámetros a un objeto si desea una validación automática. Vale la pena aprender a hacerlo si está utilizando SpringMVC, incluso si no es su primera opción para esta tarea.

Se ve algo como esto:

public ModelAndView createFoo(@PathVariable long level1, 
     @PathVariable long level2, 
     @Valid @ModelAttribute() FooWrapper fooWrapper, 
     BindingResult errors) { 
    if (errors.hasErrors() { 
    //handle errors, can just return if using Spring form:error tags. 
    } 
} 

public static class FooWrapper { 
    @NotNull 
    @Size(max=32) 
    private String fooName; 
    private String description; 
//getset 
} 

Si tiene Hibernate Validator 4 o posterior en la ruta de clases y utilizar la configuración por defecto debería despachador "Sólo el trabajo".

Edición ya que los comentarios estaban recibiendo especie de gran:

Cualquier objeto que está en su firma del método que no es uno de los 'espera' los primavera sabe cómo inyectar, como HttpRequest, ModelMap, etc, recibirá datos vinculados. Esto se logra para casos simples simplemente al hacer coincidir los nombres de param de solicitud con los nombres de propiedad de bean y los establecedores de llamadas. El @ModelAttribute es solo una cosa de estilo personal, en este caso no está haciendo nada. La integración JSR-303 con @Valid en un parámetro de método se conecta a través del WebDataBinder. Si usa @RequestBody, está utilizando un marcador de objetos basado en el tipo de contenido que spring determina para el cuerpo de la solicitud (generalmente solo desde el encabezado http). El servlet del operador (AnnotationMethodHandlerAdapter realmente) no tiene una forma de 'dar la vuelta a la validación cambiar 'por cualquier marcador arbitrario. Simplemente pasa el contenido de solicitud web junto con el convertidor de mensajes y recupera un Objeto. No se genera ningún objeto BindingResult, por lo que no hay lugar para establecer los errores de todos modos.

Todavía puede simplemente inyectar su validador en el controlador y ejecutarlo en el objeto que obtiene, simplemente no tiene la integración mágica con el @Valid en el parámetro de solicitud que puebla el BindingResult por usted.

+1

¿Cuál es la diferencia entre' @ ModelAttribute' y '@ RequestBody' para mapear mi bean de entrada? – Dan

+2

@ModelAttribute usa específicamente el enlazador de datos web para mapear los parámetros http en un POJO. @RequestBody se utiliza para serializar el contenido real de la solicitud en un objeto java utilizando una tecnología de mapeo/deserialización arbitraria definida en el despachador. El ejemplo más común para @RequestBody sería que tu cuerpo POST contiene una cadena JSON y usas Jackson para convertirlo en un POJO – Affe

+0

Ok, entonces, ¿cómo funciona @ModelAttribute entonces? Los parámetros individuales nombrados se asignan a los nombres de las propiedades en el POJO. Además, ¿por qué no puedo usar @RequestBody con validación? – Dan

13

Si tiene varios parámetros de la petición que necesitan ser validado (con HTTP GET o POSTAL). También puede crear una clase de modelo personalizada y usar @Válido junto con @Atributo de modelo para validar los parámetros. De esta forma puede usar Hibernate Validator o javax.validator api para validar los parámetros.Es algo parecido a esto:

Solicitud Método:

@RequestMapping(value="/doSomething", method=RequestMethod.GET) 
public Model dosomething(@Valid @ModelAttribute ModelRequest modelRequest, BindingResult result, Model model) { 

    if (result.hasErrors()) { 
     throw new SomeException("invalid request params"); 
    } 

    //to access the request params 
    modelRequest.getFirstParam(); 
    modelRequest.getSecondParam(); 

    ... 
} 

clase ModelRequest:

class ModelRequest { 

    @NotNull 
    private String firstParam; 

    @Size(min = 1, max = 10, message = "You messed up!") 
    private String secondParam; 

    //Setters and getters 

    public void setFirstParam (String firstParam) { 
     this.firstParam = firstParam; 
    } 

    public String getFirstParam() { 
     return firstParam; 
    } 

    ... 
} 

Espero que ayude.

+0

¿significa que tengo que crear muchas clases de modelo personalizado para diferentes solicitudes? – yuxh

25

Esto parece ser posible ahora (tratado con Spring 4.1.2), ver https://raymondhlee.wordpress.com/2015/08/29/validating-spring-mvc-request-mapping-method-parameters/

Extracto del anterior página:

  1. Añadir MethodValidationPostProcessor a clase primavera @Configuration:

    @Bean 
    public MethodValidationPostProcessor methodValidationPostProcessor() { 
        return new MethodValidationPostProcessor(); 
    } 
    
  2. Agregar @ Validado a la clase de controlador

  3. Uso @Size justo antes @RequestParam

    @RequestMapping("/hi") 
    public String sayHi(@Size(max = 10, message = "name should at most 10 characters long") @RequestParam("name") String name) { 
        return "Hi " + name; 
    

    }

  4. ConstraintViolationException manija en un método @ExceptionHandler

+0

Me gustaría agregar que la anotación '@ Size' se puede usar también para validar el tamaño de Colecciones, Arrays y Mapas. – naXa

+2

Uso Spring Boot y, de alguna manera, esta configuración no funciona para mí. Nunca se invocan las validaciones. –

+0

En 2017, estoy probando con Spring Boot 1.5.3 y simplemente funciona si tengo '@ Validated' en el controlador. No tuve que agregar la dependencia de hibernate-validators ni configuré el 'MethodValidationPostProcessor'. – adarshr

Cuestiones relacionadas