Este documento describe diferentes métodos para validar la entrada de usuarios en aplicaciones Struts. Explica la validación manual en el Action y en el ActionForm, así como la validación automática proporcionada por Struts mediante ficheros XML. También incluye dos ejemplos completos ilustrando la validación manual parametrizada y la configuración de la validación automática.
2. Introducción
Toda aplicación web debería chequear siempre la entrada del usuario
Los campos HTML son demasiado genéricos (aceptan todo)
Struts proporciona dos vías de validación
Validación manual
En los Action
Todo el control (tenemos acceso a lógica de negocio, etc.)
Repetición de código en multiples Actions
Escribir las reglas de validación uno mismo
En los ActionForm
En los métodos set
Impedir valores “malignos”
En validate()
No tan poderoso como en Action pero menos costoso
Muestra página de entrada automáticamente si falla
Requiere igualmente escribir reglas de validación
Validación automática
Struts proporciona comprobaciones automáticas para casos comunes
También validación automática en cliente (javascript)
3. Validación en el Action
Solución más flexible pero más costosa
Procedimiento
Recuperar datos de ActionForm
Por cada valor incorrecto o no presente
Añadir mensaje de error al propio ActionForm
Utilizar mapping.findForward para devolver código de error en
cada caso
En struts-config.xml mapear todos los errores al mismo
formulario de entrada
Utilizar bean:write para mostrar mensajes de error (si
contienen código HTML usar filter=“false”)
4. Validación en el ActionForm
Lógica de validación dentro de validate()
Si no hay errores devolver null o objeto ActionErrors vacío
Por cada error
Añadir ActionMessage con nombre y clave a ActionErrors
Cada clave corresponde a un mensaje de properties (i18n)
Si se devuelve ActionErrors no vacío Struts redirecciona
automáticamente al formulario de entrada
Crear fichero properties con mensajes de error
El fichero debe estar declarado en struts-config.xml
En el formulario utilizar el tag: <html:errors />
El Action no necesita lógica de validación
5. Validación en el ActionForm
(II)
Varios Action pueden usar el mismo
ActionForm
¿Qué ocurre si uno no requiere validación?
<action path="..."
type="somePackage.SomeClass"
name="someFormBean"
scope="request"
input="/somePath/original-form.jsp"
validate="false">
<forward name="..." path"..."/>
</action>
6. Ejemplo 1: Elección de
formato
Formulario que pide parámetros de formato de una
página de resultados:
Tres tipos de letra (para title, heading, y body)
Dos colores (fondo y letra)
Se utiliza <html:errors/> para mostrar los mensajes
El ActionForm
Recoge los datos del formulario y comprueba en validate()
Action
No tiene código de validación
struts-config.xml
Indica path a formulario de entrada en argumento del action
input.
7. Ejemplo 1: ActionForm
ActionForm FormatFormBean. Método validate():
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if (isMissing(getTitleSize())) {
errors.add("title",
new ActionMessage("titleSize.required"));
}
if (isMissing(getHeadingSize())) {
errors.add("heading",
new ActionMessage("headingSize.required"));
}
if (isMissing(getBodySize())) {
errors.add("body",
new ActionMessage("bodySize.required"));
}
if (isMissing(getBgColor())) {
errors.add("bg",
new ActionMessage("bgColor.required"));
}
if (isMissing(getFgColor())) {
errors.add("fg",
new ActionMessage("fgColor.required"));
} else if (getFgColor().equals(getBgColor())) {
errors.add("fg",
new ActionMessage("colors.notMatch"));
}
return(errors);
}
8. Ejemplo 1: Mensajes de error
Fichero de properties con mensajes. MessageResources.properties:
# -- Standard errors --
errors.header=<UL>
errors.prefix=<LI><B><FONT COLOR="RED">
errors.suffix=</FONT></B></LI>
errors.footer=</UL>
# -- Custom validation messages --
titleSize.required=Se requiere un tamaño para el título.
headingSize.required=Se requiere un tamaño para el
encabezado.
bodySize.required=Se requiere un tamaño para el cuerpo.
bgColor.required=Se requiere un color para el fondo.
fgColor.required=Se requiere un color para el texto.
colors.notMatch=Los colores de fondo y texto han de ser
diferentes.
10. Ejemplo 1: Formulario
Fichero de entrada forms/index.jsp:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>Elige el formato</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H1 ALIGN="CENTER">Elige el formato</H1>
Elige el tamaño de letra y los colores para mostrar la información de
su CV.
<P>
<CENTER>
<%@ taglib uri="http://struts.apache.org/tags-html"
prefix="html" %>
<html:errors/>
<html:form action="/actions/showSample">
Tamaño título: <html:text property="titleSize"/><BR>
Tamaño encabezado: <html:text property="headingSize"/><BR>
Tamaño cuerpo: <html:text property="bodySize"/><BR>
Color fondo: <html:text property="bgColor"/><BR>
Color letra: <html:text property="fgColor"/><BR>
<html:submit value="Show Sample"/>
</html:form>
</CENTER>
</BODY></HTML>
11. Ejemplo 1: Action
El fichero Action no requiere hacer ninguna validación.
package app;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class ShowSampleAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return(mapping.findForward("success"));
}
}
12. Ejemplo 1: Resultados
Tras construir el proyecto y desplegar el war
accedemos al formulario de entrada:
http://localhost:8080/struts-manual-validation/forms/index.jsp
13. Ejemplo 1: Resultados (II)
Si dejamos sin rellenar algún campo nos lo
indica y nos deja los que ya hemos rellenado
14. Ejemplo 1: Resultados (III)
Si rellenamos todos los campos se muestra resultado con formato
(/WEB-INF/results/sample.jsp):
Eligiendo por ejemplo tamaños de letra: 22,18 y 10, y colores ‘blue’ y ‘yellow’
obtendríamos:
15. Ejemplo 2: Mensajes
parametrizados
Vamos a incorporar mensajes de error con parámetros
Menos necesidad de mensajes de error
Más información con valores de ejecución
En el fichero MessagesResource.properties:
Insertamos en los mensajes {0}, {1}, {2}, … donde queramos
que vayan los parámetros
Recoge los datos del formulario y comprueba en validate()
ActionForm
En validation() habrá que pasar los argumentos en el
constructor de cada ActionMessage (hasta 4). Si se requieren
más array
16. Ejemplo 2: ActionForm
Creamos FormatFormBean2 partiendo de FormatFormBean. Vemos los
cambios de validate():
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if (isMissing(getTitleSize())) {
errors.add("titleSizeMissing", new ActionMessage("value.required", "Tamaño del título"));
} else if (!isInt(getTitleSize())) {
errors.add("titleNotInt", new ActionMessage("value.int","tamaño del título",getTitleSize()));
}
if (isMissing(getHeadingSize())) {
errors.add("headingSizeMissing", new ActionMessage("value.required","Tamaño del título"));
} else if (!isInt(getHeadingSize())) {
errors.add("headingNotInt", new ActionMessage("value.int", "tamaño del título",getHeadingSize()));
}
if (isMissing(getBodySize())) {
errors.add("bodySizeMissing",new ActionMessage("value.required","tamaño del texto del cuerpo"));
} else if (!isInt(getBodySize())) {
errors.add("bodyNotInt",new ActionMessage("value.int","tamaño del texto del cuerpo",getBodySize()));
}
if (isMissing(getBgColor())) {
errors.add("bgColorMissing", new ActionMessage("value.required","Color de fondo"));
}
if (isMissing(getFgColor())) {
errors.add("fgColorMissing", new ActionMessage("value.required","Color de fuente"));
} else if (getBgColor().equals(getFgColor())) {
errors.add("colorsIdentical",new ActionMessage("colors.match",getBgColor()));
}
return(errors);
}
17. Ejemplo 2: Mensajes de error
Creamos otro fichero de error MessageResources2.properties con las
cadenas que aceptan argumentos:
# -- Standard errors --
errors.header=<UL>
errors.prefix=<LI><B><FONT COLOR="RED">
errors.suffix=</FONT></B></LI>
errors.footer=</UL>
# -- Custom validation messages --
value.required=Se necesita {0}.
value.int=Se requiere un número para {0}; "{1}" no es un entero.
colors.match=Los colores de fondo y fuente son ambos "{0}".
18. Ejemplo 2: Configuración
Añadimos entrada para nuevo message-resources esta vez indicándole un nombre con argumento key y una
entrada para otro Action que reaprovecha la clase de antes pero usa nuevo ActionForm
<struts-config>
<form-beans>
<form-bean name="formatFormBean" type="app.FormatFormBean"/>
<form-bean name="formatFormBean2" type="app.FormatFormBean2"/>
</form-beans>
<action-mappings>
<action path="/actions/showSample"
type="app.ShowSampleAction"
name="formatFormBean"
scope="request"
input="/forms/index.jsp">
<forward name="success" path="/WEB-INF/results/sample.jsp"/>
</action>
<action path="/actions/showSample2"
type="app.ShowSampleAction"
name="formatFormBean2"
scope="request"
input="/forms/index2.jsp">
<forward name="success"
path="/WEB-INF/results/sample.jsp"/>
</action>
</action-mappings>
<message-resources parameter="MessageResources" null="false"/>
<message-resources parameter="MessageResources2" key="withArgs" null="false"/>
</struts-config>
19. Ejemplo 2: Formulario
Creamos index2.jsp a partir de index.jsp
Cambiamos en <errors> la referencia al resource bundle. Esta vez no es el de por defecto
Cambiamos action a showSample2
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>Elige el formato</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H1 ALIGN="CENTER">Elige el formato</H1>
Elige el tamaño de letra y los colores para mostrar la información de su CV.
<P>
<CENTER>
<%@ taglib uri="http://struts.apache.org/tags-html"
prefix="html" %>
<html:errors bundle="withArgs"/>
<html:form action="/actions/showSample2">
Tamaño título: <html:text property="titleSize"/><BR>
Tamaño encabezado: <html:text property="headingSize"/><BR>
Tamaño cuerpo: <html:text property="bodySize"/><BR>
Color fondo: <html:text property="bgColor"/><BR>
Color letra: <html:text property="fgColor"/><BR>
<html:submit value="Show Sample"/>
</html:form>
</CENTER>
</BODY></HTML>
21. Validación automática
Struts dispone de un validador automático
válido para muchas situaciones
Permite utilizar reglas de validación
estándar
Funciona en el servidor y opcionalmente
también en el cliente (javascript)
Se describe a través de ficheros XML
22. Validación en cliente vs
Validación en servidor
Validación en cliente
Javascript verifica campos
Cuadros de diálgo muestran errores
No se envían datos si hay algo incorrecto
Es rápida pero puede saltarse deliberadamente (opciones
navegador) y no permite comprobaciones exhaustivas
Validación en servidor
El código Java en el servidor verifica entrada del form.
Obligatoria
Permite volver a mostrar formulario con advertencias y
campos rellenados
24. Utilización de validación
automática (II)
Poner reglas de validación en validation.xml
Utilizar form-bean para identificar ActionForm
<form name="beanNameFromStrutsConfig">
Utilizar <field property=“..” depends=“..”> para identificar
propiedad del ActionForm y qué regla de chequeo usar
<field property=“propName” depends=“ruleName”>
Utilizar <argX > para pasar argumentos a los mensajes de
error
<field property=“propName” depends=“ruleName”>
<arg0 key=“key.Name”/>
</field>
25. Estructura de validation.xml
Etiquetas globales <form-validation> y <formset>
Referencia a ActionForms declarados en struts-config.xml:
<form name=“beanName”/>
Regla de validación por campo
<field property=“firstName” depends=“required”/>
Tipos de comprobaciones (depends):
required. El cambo debe tener un valor
mask. Debe seguir una expresión regular
email. Campo de tipo email
creditCard. Número de tarjeta de crédito válido (pruebas: 411111111111)
Utilizar <field property=“..” depends=“..”> para identificar propiedad del ActionForm y
qué regla de chequeo usar
<field property=“propName” depends=“ruleName”>
Utilizar <argX > para pasar argumentos a los mensajes de error
<field property=“propName” depends=“ruleName”>
<arg0 key=“key.Name”/>
</field>
Dentro de field
<arg0 key="property.subname"/>
Reemplaza {0} con el valor dado de la propiedad en mensaje property.subname
27. Utilización de validación
automática (IV)
Los bean de formulario han de extenderse
de ValidatorForm en vez de ActionForm.
Para habilitar Javascript, añadir tags al JSP
con formulario:
<html:javascript formName="beanName"/>
Y añadir a <html:form> el argumento:
onsubmit="return validateBeanName(this);"
28. Ejemplo 3: La tienda de pelis
Vamos a crear un sitio con un formulario
de rellenado de datos para sitio de
compra online
Habrá que definir un validation.xml
Ahora AcitionForm (ValidatorForm en
realidad) y Action no tendrán lógica de
comprobación
El formulario tendrá campos de varios
tipos
29. Ejemplo 3: Action
Extremadamente simple
package app;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class Order extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return(mapping.findForward("success"));
}
}
31. Ejemplo 3: Mensajes de error
MessageResources.properties
# -- Custom messages for this application --
inputForm.firstName=Nombre
inputForm.lastName=Apellido
inputForm.address=Dirección
inputForm.zipCode=CP (5 dígitos)
inputForm.creditCardNumber=Nº tarjeta crédito
inputForm.email=Email
# -- Standard errors --
errors.header=<UL>
errors.prefix=<LI><B><FONT COLOR="RED">
errors.suffix=</FONT></B></LI>
errors.footer=</UL>
# -- validator --
errors.invalid={0} es incorrecto/a.
errors.maxlength={0} no puede tener más de {1} caracteres.
errors.minlength={0} no pude tener menos de {1} caracteres.
errors.range={0} no está entre {1} y {2}.
errors.required={0} es obligatorio/a.
errors.byte={0} debe ser un byte.
errors.date={0} no es una fecha.
errors.double={0} debe ser un double.
errors.float={0} debe ser un float.
errors.integer={0} debe ser un entero.
errors.long={0} debe ser un long.
errors.short={0} debe ser un short.
errors.creditcard={0} no es un nº de tarjeta de crédito válido.
errors.email={0} no es un email correcto.
# -- other --
errors.cancel=Operación cancelada.
errors.detail={0}
errors.general=El proceso no se pudo completar. Detalles a continuación.
errors.token=La peticion no se completó. Operación fuera de secuencia.
33. Ejemplo 3: Bean de formulario
Esta vez extendido de ValidatorForm
package app;
import org.apache.struts.validator.*;
public class OrderFormBean extends ValidatorForm {
….
public String getEmail() {
return(email);
}
public void setEmail(String email) {
this.email = email;
}
…
}
34. Ejemplo 3: Formulario
Creamos dos: forms/order-form.jsp y forms/order-form2.jsp (sin javascript)
<HTML>
<HEAD><TITLE>TOP Cine</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H1 ALIGN="CENTER">TOP Cine</H1>
Gracias por comprar la filmografía completa de <b>Chiquito de la Calzada</b>
por el asombroso precio de 100 euros. Para completar su pedido, por favor
rellene y envíe la siguiente información.
<P>
<CENTER>
<%@ taglib uri="http://struts.apache.org/tags-html"
prefix="html" %>
<html:errors/>
<html:form action="/actions/order"
onsubmit="return validateOrderFormBean(this);">
Nombre: <html:text property="firstName"/><BR>
Apellido: <html:text property="lastName"/><BR>
Dirección: <html:text property="address"/><BR>
CP (5 dígitos): <html:text property="zipCode"/><BR>
Nº tarj. crédito:
<html:text property="creditCardNumber"/><BR>
Email para confirmación:
<html:text property="email"/><BR>
<html:submit value="Enviar"/>
</html:form>
<html:javascript formName="orderFormBean"/>
</CENTER>
</BODY></HTML>
35. Ejemplo 3: Resultados
Errores detectados en cliente (formulario con javascript)
http://localhost:8080/struts-automatic-validation/forms/order-form.jsp
36. Ejemplo 3: Resultados
Errores detectados en servidor (formulario sin javascript)
http://localhost:8080/struts-automatic-validation/forms/order-form2.jsp