Spring Web MVC: valide los parámetros de solicitud individuales

Estoy ejecutando una aplicación web en Spring Web MVC 3.0 y tengo varios métodos de control cuyas firmas son más o menos las siguientes:

@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 agregar algo de validación, por ejemplo, la description debe limitarse a 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 spring.

Por lo que entiendo, otra opción sería vincular @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?

No hay nada incorporado para hacer eso, todavía no 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 su ruta de clases y usa la configuración predeterminada del asignador, debería “Simplemente funcionar”.

Editando ya que los comentarios se estaban volviendo algo grandes:

Cualquier objeto que esté en la firma de su método que no sea uno de los ‘esperados’ que Spring sepa cómo inyectar, como HttpRequest , ModelMap , etc., obtendrá datos enlazados. 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 un 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 de WebDataBinder . Si usa @RequestBody , está usando un marcador de objeto basado en el tipo de contenido que spring determina para el cuerpo de la solicitud (generalmente solo desde el encabezado http). El servlet del despachador ( AnnotationMethodHandlerAdapter realmente) no tiene una forma de ‘voltear el interruptor de validación ‘para 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 @Valid en el parámetro de solicitud que BindingResult el BindingResult por usted.

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

Extracto de la página anterior:

  1. Agregue MethodValidationPostProcessor a la clase Spring @Configuration:

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

  3. Use @Size justo antes de @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. Manejar ConstraintViolationException en un método @ExceptionHandler

Si tiene múltiples parámetros de solicitud que deben validarse (con Http GET o POST ). También podría crear una clase de modelo personalizada y usar @ Válido junto con @ ModelAttribute para validar los parámetros. De esta forma puede usar Hibernate Validator o javax.validator api para validar los params. Es algo parecido a esto:

Método de solicitud:

 @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.