icono_twiter icono LinkedIn
Miguel Arlandy Rodríguez

Consultor tecnológico de desarrollo de proyectos informáticos.

Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación

Somos expertos en Java/JEE

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2011-05-30

Tutorial visitado 17.570 veces Descargar en PDF
Implementando nuestro propio formulario de validación con Spring MVC.

Implementando nuestro propio formulario de validación con Spring MVC


0. Índice de contenidos.


1. Introducción

En este tutorial vamos a ver cómo implementar nuestro propio validador para los datos de un formulario con Spring MVC.

Existen determinados casos en que las validaciones de los datos de un formulario son tan sencillas como validar que cierto campo sea obligatorio o que otro no pueda ser mayor de cierto valor. En este caso, podríamos solucionar el problema con anotaciones del tipo @NotNull o @Size en nuestro bean.
Sin embargo, existen otras ocasiones en que las validaciones de unos datos pueden estar condicionadas por otros. En este caso, una buena solución podría ser definir nuestro propio validador para el formulario.


2. Entorno.

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15' (2.2 Ghz Intel Core I7, 4GB DDR3).
  • Sistema Operativo: Mac OS Snow Leopard 10.6.7
  • Entorno de desarrollo: Eclipse 3.6.2.
  • Apache Tomcat 6.0.32 con jdk 1.6.
  • Spring 3.1.0.
  • Navegador: Mozilla Firefox 4.0.1

3. Diseñar los datos del formulario.

Lo primero que debemos hacer es definir el bean en el que llegarán los datos al controlador directamente desde el cliente. En nuestro caso, el bean tendrá información relativa a un coche, en concreto: matrícula, modelo, año y kilómetros.

public class DatosCoche {
	
	private String matricula;
	
	private String modelo;
	
	private int anho;
		
	private int kilometros;

	// getters y setters	
		
}

4. Implementar el validador concreto.

En este punto, estamos ya en disposición de poder implementar nuestro validador concreto. Las validaciones que realizaremos serán siguientes:

  • La matrícula es obligatoria.
  • La matrícula debe ser de la forma NNNN-LLL o L-NNNN-LL; donde L = letra y N = número.
  • El modelo es obligatorio.
  • El año no puede ser inferior a 1900 ni superior al año actual.
  • Si el año no es el actual, los kilómetros deben estar comprendidos entre 0 y 100.000.

No se si esto tiene mucho sentido en una aplicación empresarial, pero para nuestro ejemplo nos vale ;).

El validador quedaría de la siguiente manera:


import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;


public class ValidadorDatosCoche implements Validator {
	
	private static final int AÑO_ACTUAL = 
		Integer.valueOf(new SimpleDateFormat("yyyy").format(new Date()));	

	@Override
	public boolean supports(Class<?> clazz) {		
		return DatosCoche.class.equals(clazz); // clase del bean al que da soporte este validador
	}

	@Override
	public void validate(Object target, Errors errors) {
		
		DatosCoche datosCoche = (DatosCoche) target;
		
		// la matrícula es obligatoria
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "matricula", "field.matricula.required", 
				"La matrícula es obligatoria");
		
		// debe tener un formato correcto del tipo: 1111-BBB o B-2222-MM
		validarFormatoMatricula(datosCoche.getMatricula(), errors); // valida la matricula por expresión regular
		
		// la matrícula es obligatoria
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "modelo", "field.modelo.required", 
			"El modelo es obligatorio");
		
		// el año debe ser válido no puede ser mayor que el actual
		if ( datosCoche.getAnho() < 1900 || datosCoche.getAnho() > AÑO_ACTUAL ) {
			errors.rejectValue("anho", "field.anho.invalid", "El anho es incorrecto");
		}	
		
		// si no hay errores relacionados con el campo año
		if ( ! errors.hasFieldErrors("anho")) {
		
			// para los coches de año distinto al actual, validamos que no tengan más de 100.000 km
			if ( datosCoche.getAnho() < AÑO_ACTUAL ) {
				
				if ( datosCoche.getKilometros() < 0 ) {
					errors.rejectValue("kilometros", "field.kilometros.invalid", 
							"Los kilómetros son incorrectos");
				}
				
				if ( datosCoche.getKilometros() > 100000 ) {
					errors.rejectValue("kilometros", "field.kilometros.toomany", 
							"No se aceptan coches de más de 100000 km");
				}
			
			}		
		}		
		
	}
		
	private void validarFormatoMatricula (String matricula, Errors errors) {
		// valida la matrícula por expresión regular, si hay error lo añade a errors
	}

}

El método rejectIfEmptyOrWhitespace de la clase ValidationUtils, será el encargado de añadir el error. En nuestro ejemplo recibe 4 parámetros: los errores, el nombre del campo que no pasó la validación, la clave del mensaje (internacionalización, properties...) y el mensaje por defecto.

El método rejectValue de la clase Errors sirve para lo mismo.


5. El controlador.

A continuación, creamos el controlador.

El método manejarFormularioYaValidado será el que reciba nuestro formulario con el resultado del proceso de validación. Al principio preguntamos si hubo errores con los datos del formulario y, en ese caso, redirigimos a la vista del formulario (vistaFormularioCoche.jsp). En caso de que todo haya salido correctamente ya se pueden manejar los datos, sabiendo que son correctos. Podríamos llamar a un Service que los tratara y redirigir a donde fuese.

El método verFormulario únicamente nos redirecciona a la vista del formulario.

Con el método initBinder estamos registrando el validador concreto que acabamos de implementar.

El método populateForm nos suministra el objeto en el que se cargarán los datos del formulario, que posteriormente serán validados. En nuestro caso nos proporcionará un DatosCoche.

El código sería este:

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
@RequestMapping("/formularioCoche")
public class ControladorDatosCoche {

	@RequestMapping(method = RequestMethod.GET)
	public String verFormulario () {				
		return "vistaFormularioCoche"; // nos redirige a la vista del formulario
	}
	
	@InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new ValidadorDatosCoche()); // registramos el validador
    }
	
	@RequestMapping(value = "/manejar", method = RequestMethod.POST)
    public String manejarFormularioYaValidado(@Valid DatosCoche datosCoche, 
    		BindingResult result) {
		
		// si hay errores volvemos a la vista del formulario
		if ( result.hasErrors() ) {
			return "vistaFormularioCoche";
		}
		
		// si no hay errores, manejamos los datos validados...
		
		return "vistaQueSea";
		
	}
	
	@ModelAttribute("datosCoche")
	public DatosCoche populateForm() {
	     return new DatosCoche(); // creamos el bean para que se pueda popular
	}
	
}

6. Crear la vista.

Por último nos faltaría crear la jsp vistaFormularioCoche.jsp donde se define el formulario con el que interactuará el usuario. Debemos prestar especial atención a los siguientes elementos:

  • form:form define el formulario que vamos a popular y validar. El valor de su atributo commandName debe coincidir con el de la anotación @ModelAttribute del método populateForm de nuestro controlador.
  • form:input define cada uno de los campos que vamos a cargar en nuestro DatosCoche. El atributo path hace referencia a la propiedad a cargar.
  • form:errors será el componente (un span de HTML) donde aparecerá el error relacionado con el campo (path) que lleve definido. El atributo cssClass referencia al la regla de estilo css que le queramos dar.

La jsp vistaFormularioCoche.jsp quedaría de la siguiente forma:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
	<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
	<title>AUTENTIA - Prueba de Formulario de validación con Spring MVC 3.1</title>
	<style type="text/css">
		body {
			font-family: verdana, sans-serif;			
		}
		
		span.campoConError {
			color: red;
		}
		
	</style>	
</head>

<body>
				
	<c:url value="/formularioCoche/manejar" var="destino"/>			
	<form:form method="post" action="${destino}" commandName="datosCoche"> 			  				
				
		

Formulario con datos del coche

Matrícula: <form:input path="matricula" /> <form:errors path="matricula" cssClass="campoConError"/>
Modelo: <form:input path="modelo" /> <form:errors path="modelo" cssClass="campoConError"/>
Año: <form:input path="anho" maxlength="4" /> <form:errors path="anho" cssClass="campoConError"/>
Kilómetros: <form:input path="kilometros" maxlength="6" /> <form:errors path="kilometros" cssClass="campoConError"/>
<input type="submit" value="Enviar" />
</form:form> </body> </html>

El formulario se vería de la siguiente forma:

Introduciendo datos incorrectos nos mostraría lo siguiente:


7. Referencias.


8. Conclusiones.

Hemos visto que es relativamente sencillo implementar nuestro propio validador utilizando Spring MVC.

El validador concreto nos aportará más control que otro sistema de validación a modo de anotaciones, sin embargo, con éste último no tendremos que implementar nada, por lo que puede que si las validaciones que vamos a realizar a los campos de nuestro formulario son constantes y sencillas, tengamos que pensar en esta segunda opción como más adecuada.

Espero que este tutorial os haya sido de ayuda. Un saludo.

Miguel Arlandy

marlandy@autentia.com

A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL:

Fecha publicación: 2012-04-16-11:51:31

Autor: Krusader

Muchas gracias por resolver las dudas que tenía.

En cuanto al tema de Hibernate, yo he sido entrenado en las artes oscuras del SQL :) y todo el tema de conexiones con bases de datos prefiero hacerlas yo mismo, aunque gracias por la idea de Hibernate.

Fecha publicación: 2012-04-14-10:58:50

Autor: marlandy

Hola Krusader,

- javax.validation.Valid pertenece a la especificación Bean Validator (JSR 303), para poder hacer uso de ella (http://jcp.org/en/jsr/detail?id=303), teniendo en cuenta que no vas a usar Maven, deberás añadir el jar a las dependencias de tu proyecto al igual que alguna implementación de dicha especificación como puede ser la de Hibernate (http://www.hibernate.org/subprojects/validator.html).

- Para especificar el fichero de donde sacar los mensajes de error basta con que crees un fichero ValidationMessages.properties en tu classpath y añadas ahí los mensajes.

Saludos

Fecha publicación: 2012-04-13-14:33:44

Autor: Krusader

Hola a todos,

Muy bueno el artículo. Tengo un par de dudas:

- javax.validation.Valid: ¿de donde la puedo obtener? ¿es de maven? En principio no estoy utilizando Maven
- La mas importante, ¿como y donde debo especificar el fichero de donde tomar los mensajes de error con anotaciones?, ya que mi idea es no utilizar xml de configuración, lo estoy haciendo todo por anotación.

Un saludo y muchas gracias

Fecha publicación: 2011-06-10-19:47:27

Autor: drarenas

Muy util, ¡gracias!

Fecha publicación: 2011-06-09-02:48:01

Autor: natxobau

Uno nunca deja de aprender gracias a tutoriales y profesionales cualificados... Antes struts, ahora spring (poco a poco)... Gracias por el tutorial, estaré atento a otros...

Un saludo!!!

Fecha publicación: 2011-06-01-17:50:01

Autor: marlandy

Hola amigo. Claro que se puede, necesitas dos etiquetas que nos proporciona el taglib form de Spring, en concreto form:select y form:option. Aquí te dejo un enlace por si te sirve de ayuda.

http://static.springsource.org/spring/docs/3.0.x/reference/view.html#view-jsp-formtaglib-selecttag

Un saludo.

Fecha publicación: 2011-06-01-11:41:44

Autor: iptaboada

Muy buen tutorial, me pregunto si seria posible validar de forma parecida los combobox? Seria algo bastante útil. Muchas gracias.Un saludo.