Validar campos de formularios con JSF

De ChuWiki

Introducción[editar]

Vamos a ver aquí algunas de las posibilidades que nos facilita Java Server Faces (JSF) para validar los campos de un formulario antes de enviarlo.

Validators por defecto[editar]

JSF viene con algunos validadores habituales de campos. Por ejemplo, si queremos que un número esté dentro de un rango, podemos poner el siguiente código html en nuestro formulario

<h:form>
   <h:inputText id="idNumero2" required="true">
      <f:validateLongRange minimum="-10" maximum="10"></f:validateLongRange>
   </h:inputText>
   <h:commandButton action="bien.xhtml" value="Enviar">
   </h:commandButton>
   <h:message for="idNumero2"></h:message>
</h:form>

Es un formulario. Dentro de él hay un inputText y dentro del inputText un <f:validateLongRange> con un minimum y un maximum. El inputText además tiene required="true", por lo que no se podrá dejar en blanco.

Cuando pulsemos el botón de "Enviar" que hay justo debajo, se validará automáticamente el contenido del campo de texto, tanto que se ha rellenado como que lo introducido es un número entre -10 y 10 (ambos incluives) dando un error en caso contrario.

Si hay error, no se enviaré el formulario y se volverá a mostrar la misma página que lo contiene. El error aparecerá en la etiqueta <h:message>, en la que hemos puesto el atributo for="idNumero2", correpondiente al campo de texto. Cuando se muestre el formulario por primera vez,

Tenemos varios validators disponibles :

  • f:validateBean
  • f:validateDoubleRange
  • f:validateLength
  • f:validateLongRange
  • f:validateRegex
  • f:validateRequired

Validator a medida[editar]

Podemos hacernos fácilmente nuestra propia validación. En uno de los ManagedBean de JSF podemos poner un método de validación, de la siguiente forma

@ManagedBean
public class HolaMundo {
   ....

   public void validate(FacesContext arg0, UIComponent arg1, Object arg2)
         throws ValidatorException {
      if (((String)arg2).length()<5) {
         throw new ValidatorException(new FacesMessage("Al menos 5 caracteres "));
      }
   }
}

Un método (de nombre el que queramos) que admita los parámetros que se ponen ahí. En arg2 recibiremos el contenido del campo de texto, que en principio será un String con el contenido del campo de texto. Si el String recibido nos parece válido, no hay que hacer nada especial. Si el String no nos gusta, debemos lanzar una ValidatorExcepcion con el texto de error que queremos que se muestre en el navegador.

En el código html, pondremos algo así

<h:form>
   <h:inputText id="idNumero" validator="#{holaMundo.validate}">
   </h:inputText>
   <h:commandButton action="bien.xhtml" value="Enviar">
   </h:commandButton>
   <h:message for="idNumero"></h:message>
</h:form>

En el inputText hemos puesto un atributo validator en el que se hace la llamada al método del ManagedBean que acabamos de hacer.

Hemos comentado que en ese método el tipo recibido es "en principio un String". Esto es cierto si no asociamos el campo de texto a ningún atributo de ningún ManagedBean. Si hacemos por ejemplo algo como esto

   <h:inputText id="idNumero" value="#{holaMundo.valor}" validator="#{holaMundo.validate}">

siendo #{holaMundo.valor} un atributo, por ejemplo, de tipo entero, en nuestro método de validación recibiremos un Integer, siempre que lo escrito pueda convertirse a Integer, o String en caso contrario.

Registrar un validador[editar]

Podemos hacer una clase de validación y registrarla, de forma que luego la podamos usar cómodamente donde queramos. En primer lugar, creamos la clase que implemente Validator, definiendo el único método que tiene, igual que el que hemos hecho en el apartado anterior. En el siguiente ejemplo comprobamos que el campo es un número entero entre -10 y 10. Si lo es no hay que hacer nada, si no lo es, debemos lanzar una ValidatorException

package com.chuidiang.ejemplos.jsf;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

public class MiValidador implements Validator {

    @Override
    public void validate(FacesContext arg0, UIComponent arg1, Object arg2)
            throws ValidatorException {
        if (!(arg2 instanceof Integer)) {
            throw new ValidatorException(new FacesMessage("Debe ser un entero"));
        }

        int valor = (Integer) arg2;

        if ((valor < -10) || (valor > 10)) {
            throw new ValidatorException(new FacesMessage(
                    "Debe estar entre -10 y 10"));
        }
    }
}

Para registrarla, debemos poner esta clase en el fichero WEB-INF/faces-config.xml. En este fichero sólo debemos dar un identificador al validator y decir a qué clase corresponde, que es la que acabamos de hacer. El fichero puede quedar así

<?xml version="1.0" encoding="UTF-8"?>

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
	version="2.0">

	<validator>
		<validator-id>MasMenos10</validator-id>
		<validator-class>com.chuidiang.ejemplos.jsf.MiValidador</validator-class>
	</validator>
</faces-config>

Y ahora, en la página html, sólo tenemos que poner un tag <f:validator validatorId="MasMenos10"></f:validator>, tal que así

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">

<h:head>
	<title>Hola mundo</title>
</h:head>
<h:body>
	<h:form>
		<h:inputText id="unNumero" required="true" value="#{holaMundo.valor}">
			<f:validator validatorId="MasMenos10"></f:validator>
		</h:inputText>
		<h:commandButton value="Enviar" action="hola2.xhtml"></h:commandButton>
	</h:form>
	<h:message for="unNumero"></h:message>
</h:body>
</html>

donde al inputText le hemos puesto un value que hace referencia a un atributo entero (valor) de una clase (holaMundo), de forma que nuestro validador recibirá un entero en vez de un String, como se comentó en el apartado anterior.

Y en el validatorId hemos puesto el mismo <validator-id> que pusimos en el fichero WEB-INF/faces-config.xml