Como fazer a validação

Segue o pequeno tutorial que mostra um exemplo simples de como fazer a validação programática no VRaptor.

No final o tutorial explica porque (ainda) não existe um jeito de fazer as validações com anotações.

Tuda explicação é bem prática, porém o hibernate validator plugin é ainda mais vantagoso.

O modelo

Vamos escrever uma classe como modelo que representa uma pessoa. Crie o código seguinte:

package org.vraptor.examples.validation;

public class Person {

        private String name;

        private String address;

        private Long preferredNumber;
        
        // getters e setters

        @Override
        public String toString() {
                return String.format("[Person %s,%s,%d]", name, address,
                                preferredNumber);
        }

}

O URL: person.add.logic

Vamos continuar e configurar a lógica para adicionar uma pessoa.

Chamaremos o componente person e o método add que adiciona a pessoa.

Isso significa quando o url person.add.logic é chamado, o componente será criado, o objeto person será preenchido com os parâmetros da requisição e o método add será executado.

package org.vraptor.examples.validation;

import org.vraptor.annotations.Component;
import org.vraptor.annotations.Logic;
import org.vraptor.annotations.Parameter;

@Component
public class PersonLogic {

        public void add(Person p) {
                System.out.printf("Adding %s to the database!%n", p);
        }

}

O simples exemplo do VRaptor!

Vamos validar os dados da pessoa:

package org.vraptor.examples.validation;

import org.vraptor.annotations.Component;
import org.vraptor.validator.*;
import org.vraptor.i18n.*;

@Component
public class PersonLogic {


        public void add(Person p) {
                System.out.printf("Adding %s to the database!%n", p);
        }
        
        /**
          * Validação do método add
          */
        public void validateAdd(ValidationErrors errors, Person p) {
        
                // verifique se nulo ou vazio
                if(StringValidation.isBlank(p.getName())) {
                        errors.add(new Message("name","empty_name"));
                }
                
                // verifique se nulo ou vazio
                if(StringValidation.isEmpty(p.getAddress())) {
                        errors.add(new Message("address","empty_address"));
                }
                
                // verifique se nulo
                if(p.getPreferredNumber()==null) {
                        errors.add(new Message("number","empty_number"));
                }
                
        }

}

person/add.ok.jsp significa que tudo deu certo

Nosso método add na lógica só será chamado se a validação não registrou nenhum erro!

Então: se nenhum erro aconteceu, errors.size()==0, o Vraptor continua e chama person/add.ok.jsp:

<html>
        Você criou uma pessoa chamada ${person.name}, 
        que vive em ${person.address} e o numero preferido 
        é ${person.preferredNumber}.
</html>

person/add.invalid.jsp significa um (ou mais) erro na validação

Se errors.size()!=0 pelos menos um erro aconteceu ... VRaptor retorna invalid que redireciona ao component/logic.invalid.jsp, no nosso exemplo: person/add.invalid.jsp:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
Um erro na validação aconteceu:
<div id="errors">
<ul>
        <c:forEach var="error" items="${errors.iterator}">
                <li>${error.key}</li>
        </c:forEach>
</ul>
</div>
</html>

Página index: /index.jsp

Vamos criar uma página simples index.jsp que contém um formulário para uma pessoa:

<html>
<form action="person.add.logic" method="get">
        Nome: <input name="person.name"/><br/>
        Endereço: <input name="person.address"/><br/>
        Numero preferido: <input name="person.preferredNumber"/><br/>
        <input type="submit"/>
</form>
</html>

Pronto

Estamos preparados para testar a nossa lógica!

Mas o que nós fizemos? Vamos reparar:

  1. criamos o método chamado validateLogicName que recebe ValidationErrors como argumento.
  2. implementamos a validação no método
  3. criamos uma página para o resultado positivo person/add.ok.jsp e negativo person/add.invalid.jsp (ou podemos voltar à página com o formulário; continue para descobrir como voltar).

Opcional: voltar ao formulário

Vamos configurar VRaptor para voltar ao formulário em caso de um erro de validação acontecer.

Primeiro cria o arquivo views.properties no seu classpath (diretório java source ou resources).

Nos podemos mapear componentName.logic.invalid para qualquer arquivo desejado ... então vamos redirecionar ao nosso formulário.

person.add.invalid = /index.jsp

E alteraremos o arquivo index.jsp para mostrar os valores padrões da pessoa:

<html>
<form action="person.add.logic" method="get">
        Nome: <input name="person.name" value="${person.name}"/><br/>
        Endereço: <input name="person.address" value="${person.address}"/><br/>
        Numero preferido: <input name="person.preferredNumber" value="${person.preferredNumber}"/><br/>
        <input type="submit"/>
</form>
</html>

Opcional: i18n

Mensagens de erros deveriam ser implementadas de maneira internacional, por isso podemos usar o tag fmt:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

<div id="errors">
<ul>
        <c:forEach var="error" items="${errors.iterator}">
                <li><fmt:message key="${error.key}"/></li>
        </c:forEach>
</ul>
</div>

Não esqueça de configurar o resource bundle! (leia a documentação sobre fmt jstl ou download a aplicação amostra do VRaptor).

Mensagens de validação padrão

VRaptor já tem alguns mensagens padrão. Você deveria adicionar elas no seu arquivo de properties.

no_converter_found = Nenhum conversor foi encontrado.
invalid_converter = Não conseguir criar o conversor.

invalid_date = Data inválida.
invalid_time = Hora inválida.
invalid_value = Valor inválida.
invalid_number = Numero inválida.
invalid_character = Caracter inválida.

Misturando mensagens fixas com i18n

A interface básica de mensagem chama ValidationMessage enquanto a internacionalizada é Message (devido a problemas de compatibilidade).

Para misturar os dois tipos de mensagens, com e sem i18n, você deve usar a classe FixedMessage.

Ambas implementam o método isAlreadyLocalized: Message devolve false, enquanto FixedMessage develove true, portanto a sua view fica algo como:

<c:if test="${error.alreadyLocalized}">
        ${error.key}
</c:if>
<c:if test="${not error.alreadyLocalized}">
        <fmt:message key="${error.key}"/>
</c:if>

Error path

Você pode usar a propriedade path para acessar exatamente qual campo gerou o erro.

Anotações

O Vraptor dá suporte ao Hibernate Validator.