Cuando aceptamos entradas de usuario en cualquier aplicación web, se vuelve necesario validarlas. Podemos validar la entrada del usuario en el lado del cliente utilizando JavaScript, pero también es necesario validarlas en el lado del servidor para asegurarnos de que estemos procesando datos válidos en caso de que el usuario tenga JavaScript desactivado.
Validación de Spring
El marco de trabajo Spring MVC admite las especificaciones JSR-303 de forma predeterminada y todo lo que necesitamos es agregar las dependencias de JSR-303 y su implementación en la aplicación Spring MVC. Spring también proporciona la anotación @Validator
y la clase BindingResult
a través de las cuales podemos obtener los errores generados por la implementación del validador en el método manejador de solicitud del controlador. Podemos crear nuestras implementaciones de validadores personalizados de dos maneras: la primera es crear una anotación que cumpla con las especificaciones JSR-303 e implementar su clase Validator. El segundo enfoque es implementar la interfaz org.springframework.validation.Validator
y configurarla como validador en la clase del controlador utilizando la anotación @InitBinder
. Creemos un proyecto Spring MVC simple en Spring Tool Suite donde utilizaremos las especificaciones JSR-303 con su artefacto de implementación hibernate-validator. Utilizaremos la validación de formularios basada en anotaciones y crearemos nuestro propio validador personalizado basado en los estándares de especificaciones JSR-303. También crearemos nuestra propia clase de validador personalizado implementando la interfaz Validator
y la utilizaremos en uno de los métodos manejadores del controlador. Nuestro proyecto final se ve como la siguiente imagen. Veamos cada uno de los componentes uno por uno.
Validador de Formularios Spring MVC
Nuestro archivo pom.xml final se ve así. Aparte de los artefactos estándar de Spring MVC, tenemos dependencias de validation-api y hibernate-validator en el proyecto.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>spring</artifactId>
<name>SpringFormValidation</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.7</java-version>
<org.springframework-version>4.0.2.RELEASE</org.springframework-version>
<org.aspectj-version>1.7.4</org.aspectj-version>
<org.slf4j-version>1.7.5</org.slf4j-version>
</properties>
<dependencies>
<!-- Form Validation using Annotations -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.1.0.Final</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Descriptor de Despliegue
Cuando creas un proyecto Spring MVC desde STS, crea dos archivos de configuración de contexto. Lo he limpiado un poco y solo tengo un archivo de configuración de beans de Spring. Mi archivo web.xml final se ve así.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Archivo de Configuración de Beans de Spring
Por lo general, revisamos las conexiones de Spring al final, pero esta vez no tenemos muchas configuraciones en el archivo de configuración de beans de Spring. Nuestro archivo spring.xml final se ve así.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<beans:bean id="employeeValidator" class="com.journaldev.spring.form.validator.EmployeeFormValidator" />
<beans:bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<beans:property name="basename" value="classpath:message" />
<beans:property name="defaultEncoding" value="UTF-8" />
</beans:bean>
<context:component-scan base-package="com.journaldev.spring" />
</beans:beans>
El único punto importante a tener en cuenta es el bean employeeValidator
que inyectaremos en uno de los controladores y el bean messageSource
para leer los datos localizados de los paquetes de recursos. El resto de la parte es para admitir anotaciones, resolutores de vistas y proporcionar paquetes para escanear las clases de controladores y otros componentes.
Clases de Modelo
Tenemos dos clases de modelo en este proyecto: la primera donde usaremos la anotación JSR-303 y nuestro validador basado en anotaciones personalizadas, y la segunda donde solo usaremos nuestra implementación de Validador. Código Customer.java:
package com.journaldev.spring.form.model;
import java.util.Date;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
import com.journaldev.spring.form.validator.Phone;
public class Customer {
@Size(min=2, max=30)
private String name;
@NotEmpty @Email
private String email;
@NotNull @Min(18) @Max(100)
private Integer age;
@NotNull
private Gender gender;
@DateTimeFormat(pattern="MM/dd/yyyy")
@NotNull @Past
private Date birthday;
@Phone
private String phone;
public enum Gender {
MALE, FEMALE
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Nótese que estamos usando las anotaciones @Email, @NotEmpty y @DateTimeFormat, que son adicionales a JSR-303 y proporcionadas por la implementación del validador de Hibernate. Algunas de las anotaciones JSR-303 que estamos usando son @Size, @NotNull, etc. La anotación @Phone utilizada es nuestra implementación personalizada basada en las especificaciones de JSR-303, la examinaremos en la próxima sección. Código Employee.java:
package com.journaldev.spring.form.model;
public class Employee {
private int id;
private String name;
private String role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
El Empleado es un bean Java estándar y usaremos nuestra implementación personalizada de Validador para validar el formulario con el bean Employee.
Implementaciones de Validador Personalizadas
Código Phone.java:
package com.journaldev.spring.form.validator;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import javax.validation.Constraint;
import javax.validation.Payload;
@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Phone {
String message() default "{Phone}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
La mayor parte es código estándar para confirmar con las especificaciones JSR-303. La parte más importante es la anotación @Constraint, donde proporcionamos la clase que se utilizará para la validación, es decir, PhoneValidator
. Código de PhoneValidator.java:
package com.journaldev.spring.form.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PhoneValidator implements ConstraintValidator {
@Override
public void initialize(Phone paramA) {
}
@Override
public boolean isValid(String phoneNo, ConstraintValidatorContext ctx) {
if(phoneNo == null){
return false;
}
// validar números de teléfono en formato "1234567890"
if (phoneNo.matches("\\d{10}")) return true;
// validar número de teléfono con -, . o espacios
else if(phoneNo.matches("\\d{3}[-\\.\\s]\\d{3}[-\\.\\s]\\d{4}")) return true;
// validar número de teléfono con longitud de extensión de 3 a 5
else if(phoneNo.matches("\\d{3}-\\d{3}-\\d{4}\\s(x|(ext))\\d{3,5}")) return true;
// validar número de teléfono donde el código de área está entre paréntesis ()
else if(phoneNo.matches("\\(\\d{3}\\)-\\d{3}-\\d{4}")) return true;
// devolver false si nada coincide con la entrada
else return false;
}
}
Nuestra implementación de validador de especificaciones JSR-303 debería implementar la interfaz javax.validation.ConstraintValidator
. Si estamos utilizando algún recurso como DataSource, podemos inicializarlos en el método initialize()
. El método de validación es isValid
y devuelve true si los datos son válidos, de lo contrario, debería devolver false. Si eres nuevo en las expresiones regulares, puedes leer más al respecto en Tutorial de Expresiones Regulares en Java. Código de la clase EmployeeFormValidator.java:
package com.journaldev.spring.form.validator;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import com.journaldev.spring.form.model.Employee;
public class EmployeeFormValidator implements Validator {
// qué objetos pueden ser validados por este validador
@Override
public boolean supports(Class > paramClass) {
return Employee.class.equals(paramClass);
}
@Override
public void validate(Object obj, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "id.required");
Employee emp = (Employee) obj;
if(emp.getId() <=0){
errors.rejectValue("id", "negativeValue", new Object[]{"'id'"}, "id can't be negative");
}
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "name.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "role", "role.required");
}
}
EmployeeFormValidator es la implementación del validador específico para el Framework Spring. El método supports()
es implementado por Spring Framework para conocer los objetos en los cuales esta validación puede ser usada. Implementamos el método validate()
y añadimos errores si la validación de algún campo falla. Spring provee la clase de utilidad org.springframework.validation.ValidationUtils
para validaciones básicas como nulo o vacío. Una vez que este método retorna, el framework Spring enlaza el objeto Errors al objeto BindingResult que utilizamos en nuestro método controlador del handler. Observa que el último argumento de ValidationUtils.rejectIfEmptyOrWhitespace()
toma el nombre clave para los recursos de mensajes. De esta manera podemos proveer mensajes de error localizados al usuario. Para más información sobre i18n en Spring, lee Ejemplo de i18n en Spring.
Clases Controladoras
Tenemos dos clases controladoras, una para validación de formularios basada en anotaciones y otra para nuestro validador personalizado. Código de la clase CustomerController.java:
package com.journaldev.spring.form.controllers;
import java.util.HashMap;
import java.util.Map;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.journaldev.spring.form.model.Customer;
@Controller
public class CustomerController {
private static final Logger logger = LoggerFactory
.getLogger(CustomerController.class);
private Map<String, Customer> customers = null;
public CustomerController(){
customers = new HashMap<String, Customer>();
}
@RequestMapping(value = "/cust/save", method = RequestMethod.GET)
public String saveCustomerPage(Model model) {
logger.info("Returning custSave.jsp page");
model.addAttribute("customer", new Customer());
return "custSave";
}
@RequestMapping(value = "/cust/save.do", method = RequestMethod.POST)
public String saveCustomerAction(
@Valid Customer customer,
BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
logger.info("Returning custSave.jsp page");
return "custSave";
}
logger.info("Returning custSaveSuccess.jsp page");
model.addAttribute("customer", customer);
customers.put(customer.getEmail(), customer);
return "custSaveSuccess";
}
}
Cuando utilizamos la validación de formularios basada en anotaciones, solo necesitamos hacer pequeños cambios en la implementación de nuestro método controlador para que funcione. Primero, necesitamos anotar el objeto modelo que queremos validar con la anotación @Valid
. Luego necesitamos tener un argumento BindingResult en el método, Spring se encarga de poblarlo con mensajes de error. La lógica del método controlador es muy simple, si hay errores, respondemos con la misma página, de lo contrario redirigimos al usuario a la página de éxito. Otro punto importante a tener en cuenta es que estamos agregando el atributo “customer” al modelo, esto es necesario para que el framework de Spring sepa qué objeto modelo usar en la página del formulario. Si no lo hiciéramos, la vinculación del objeto a los datos del formulario no se llevaría a cabo y nuestra validación de formularios no funcionaría. Código de la clase EmployeeController.java:
package com.journaldev.spring.form.controllers;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
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;
import com.journaldev.spring.form.model.Employee;
@Controller
public class EmployeeController {
private static final Logger logger = LoggerFactory
.getLogger(EmployeeController.class);
private Map emps = null;
@Autowired
@Qualifier("employeeValidator")
private Validator validator;
@InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
public EmployeeController() {
emps = new HashMap();
}
@ModelAttribute("employee")
public Employee createEmployeeModel() {
// El valor ModelAttribute debe ser el mismo que se usa en empSave.jsp
return new Employee();
}
@RequestMapping(value = "/emp/save", method = RequestMethod.GET)
public String saveEmployeePage(Model model) {
logger.info("Returning empSave.jsp page");
return "empSave";
}
@RequestMapping(value = "/emp/save.do", method = RequestMethod.POST)
public String saveEmployeeAction(
@ModelAttribute("employee") @Validated Employee employee,
BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
logger.info("Returning empSave.jsp page");
return "empSave";
}
logger.info("Returning empSaveSuccess.jsp page");
model.addAttribute("emp", employee);
emps.put(employee.getId(), employee);
return "empSaveSuccess";
}
}
Para usar un validador personalizado, primero necesitamos inyectarlo en la clase del controlador. Estamos utilizando la inyección automática de beans de Spring para lograr esto usando las anotaciones @Autowired
y @Qualifier
. Luego necesitamos tener un método que tome WebDataBinder como argumento y configuramos nuestro validador personalizado para que se utilice. Este método debe estar anotado con la anotación @InitBinder
. Usar @ModelAttribute
es otra forma de agregar nuestro objeto bean al Modelo. El resto del código es similar a la implementación del controlador de clientes.
Archivo de recursos de mensajes de error de validación de formularios
Es hora de revisar nuestro archivo de recursos donde tenemos diferentes tipos de mensajes que se usarán para los errores de validación. archivo message_en.properties:
# mensajes de error definidos por la aplicación
id.required=Employee ID is required
name.required=Employee Name is required
role.required=Employee Role is required
negativeValue={0} can't be negative or zero
# mensajes de error del framework Spring que se utilizarán cuando falle la conversión de datos del formulario al bean
typeMismatch.int={0} Value must be an integer
typeMismatch.java.lang.Integer={0} must be an integer
typeMismatch={0} is of invalid format
# mensajes de la aplicación para anotaciones, {ValidationClass}.{modelObjectName}.{field}
# el {0} es el nombre del campo, los otros campos están en orden alfabético, máximo y luego mínimo
Size.customer.name=Customer {0} should be between {2} and {1} characters long
NotEmpty.customer.email=Email is a required field
NotNull.customer.age=Customer {0} should be in years
# mensajes de clase de anotación genérica
Email=Email address is not valid
NotNull=This is a required field
NotEmpty=This is a required field
Past=Date should be Past
# Anotación de validación personalizada
Phone=Invalid format, valid formats are 1234567890, 123-456-7890 x1234
I have provided message key details in the comment itself, so I will skip them here. The only important point to note here is the way messages will be looked up, first key name {ValidationClass}.{modelObjectName}.{field} is looked up and if that is not found then {ValidationClass}.{modelObjectName} is looked up. If that is missing, then finally {ValidationClass} key is looked up. If nothing is found then the default message provided will be returned. Read more about resource messages at Spring Localization Example.
Páginas de vista con formularios y errores
Dado que estamos utilizando la implementación de validación del framework Spring, tendremos que usar etiquetas de formulario Spring para obtener los errores y establecer los nombres del bean y las variables del formulario. El código de nuestro archivo custSave.jsp se muestra a continuación.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://www.springframework.org/tags/form"
prefix="springForm"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Customer Save Page</title>
<style>
.error {
color: #ff0000;
font-style: italic;
font-weight: bold;
}
</style>
</head>
<body>
<springForm:form method="POST" commandName="customer"
action="save.do">
<table>
<tr>
<td>Name:</td>
<td><springForm:input path="name" /></td>
<td><springForm:errors path="name" cssClass="error" /></td>
</tr>
<tr>
<td>Email:</td>
<td><springForm:input path="email" /></td>
<td><springForm:errors path="email" cssClass="error" /></td>
</tr>
<tr>
<td>Age:</td>
<td><springForm:input path="age" /></td>
<td><springForm:errors path="age" cssClass="error" /></td>
</tr>
<tr>
<td>Gender:</td>
<td><springForm:select path="gender">
<springForm:option value="" label="Select Gender" />
<springForm:option value="MALE" label="Male" />
<springForm:option value="FEMALE" label="Female" />
</springForm:select></td>
<td><springForm:errors path="gender" cssClass="error" /></td>
</tr>
<tr>
<td>Birthday:</td>
<td><springForm:input path="birthday" placeholder="MM/dd/yyyy"/></td>
<td><springForm:errors path="birthday" cssClass="error" /></td>
</tr>
<tr>
<td>Phone:</td>
<td><springForm:input path="phone" /></td>
<td><springForm:errors path="phone" cssClass="error" /></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Save Customer"></td>
</tr>
</table>
</springForm:form>
</body>
</html>
commandName="customer"
se utiliza para establecer el nombre del atributo del modelo bajo el cual se expone el objeto de formulario. Su valor predeterminado es “command”, por lo tanto, debemos establecerlo en el nombre del atributo del modelo que estamos utilizando en nuestras clases controladoras. springForm:errors
se utiliza para renderizar los errores, si los hay, encontrados cuando se renderiza la página. El atributo path
se utiliza para definir la propiedad del objeto que se utilizará para la vinculación de datos. El resto del código es HTML estándar con algo de CSS para el estilo de los mensajes de error. Nuestro archivo custSaveSuccess.jsp se muestra a continuación.
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="https://java.sun.com/jsp/jstl/fmt" %>
<%@ page session="false" %>
<html>
<head>
<title>Customer Saved Successfully</title>
</head>
<body>
<h3>
Customer Saved Successfully.
</h3>
<strong>Customer Name:${customer.name}</strong><br>
<strong>Customer Email:${customer.email}</strong><br>
<strong>Customer Age:${customer.age}</strong><br>
<strong>Customer Gender:${customer.gender}</strong><br>
<strong>Customer Birthday:<fmt:formatDate value="${customer.birthday}" type="date" /></strong><br>
</body>
</html>
Página JSP simple que muestra los valores del cliente si no hay errores de validación y esta página se devuelve como respuesta. Su nombre es empSave.jsp.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://www.springframework.org/tags/form"
prefix="springForm"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Employee Save Page</title>
<style>
.error {
color: #ff0000;
font-style: italic;
font-weight: bold;
}
</style>
</head>
<body>
<springForm:form method="POST" commandName="employee"
action="save.do">
<table>
<tr>
<td>Employee ID:</td>
<td><springForm:input path="id" /></td>
<td><springForm:errors path="id" cssClass="error" /></td>
</tr>
<tr>
<td>Employee Name:</td>
<td><springForm:input path="name" /></td>
<td><springForm:errors path="name" cssClass="error" /></td>
</tr>
<tr>
<td>Employee Role:</td>
<td><springForm:select path="role">
<springForm:option value="" label="Select Role" />
<springForm:option value="ceo" label="CEO" />
<springForm:option value="developer" label="Developer" />
<springForm:option value="manager" label="Manager" />
</springForm:select></td>
<td><springForm:errors path="role" cssClass="error" /></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Save"></td>
</tr>
</table>
</springForm:form>
</body>
</html>
Archivo empSaveSuccess.jsp:
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Employee Saved Successfully</title>
</head>
<body>
<h3>
Employee Saved Successfully.
</h3>
<strong>Employee ID:${emp.id}</strong><br>
<strong>Employee Name:${emp.name}</strong><br>
<strong>Employee Role:${emp.role}</strong><br>
</body>
</html>
Probar la Aplicación de Validación de Formulario Spring MVC
Nuestra aplicación está lista para implementarse y ejecutar algunas pruebas, despliéguela en su contenedor de servlets favorito. Estoy utilizando Apache Tomcat 7 y las imágenes a continuación muestran algunas de las páginas con mensajes de error de validación. Según sus datos de entrada, es posible que obtenga mensajes de error diferentes también.
Eso es todo para la validación de formularios de Spring MVC con diferentes métodos y el uso de paquetes de recursos para mensajes de error localizados. Puede descargar el proyecto de muestra desde el siguiente enlace y probarlo para aprender más.
Source:
https://www.digitalocean.com/community/tutorials/spring-validation-example-mvc-validator