[RESOLVIDO] VRaptor - Forma de validação

67 respostas
vitor.morales

Bom tarde pessoal !

Bom eu estou desenvolvendo um projeto pequeno aonde eu faço faculdade e comecei a utilizar o VRaptor + Hibernate.
Eu gostaria de saber qual a melhor forma de validação utilizando esses dois frameworks.

Por exemplo

Quero adicionar um produto no banco.
Tenho as validações na página normalmente mas preciso validar tbm no camada de negócio, se por exemplo, existe algum produto com o mesmo nome.

Qual a melhor forma de realizar isso? Caso o usuário tenha digitado um nome que já existe deve aparecer um alert na página informando isso.
Agradeço a paciẽncia !

Abraços
Vitor Morales

67 Respostas

kadu.m.lino

Leia a documentação man! rs

O link abaixo tem tudo o q vc precisa

http://vraptor.caelum.com.br/pt/docs/validacao/

kadu.m.lino

nesse caso… vc faz um ajax e verifica apenas se o nome está igual…
da pra fazer logo quando ele sai do input, instantâneo.

se vc tiver dificuldade grita que eu te dou as coordenadas

vitor.morales

Opa!
Eu li a documentação sim… até acompanho ela.
Mas queria saber se existe modo melhor do que aquelas regras no controle.
Essa validação Ajax como é? Tem como da um exemplo ou indicar um link?
Abraços
Vitor Morales

kadu.m.lino

vc pode fazer a sua!
de qualquer forma vc terá que fazer no controller… ou delegar pra uma outra camada que vai ter que retornar pro controller!
mas qual o problema de fazer no controller?

por ajax vc faria assim

vc manda o objeto e verifica no controller… vc faria + - assim

Ajax:

$("inputDoNomeDoProduto").blur(function(){

  var produto = {
      "produto.nome" : $("#idDoInput").val();
  }

  $.ajax({
    url: "produtos/valida",
    type: "POST",
    data : produto,
    dataType: "application/json",
    success : function(data){
        // faz alguma coisa se der certo
    }, 
    error : function () {
        // faz a lógica dependendo do status...
    }
  });
});
  
})

Controller:

public class ProdutoController{

    private Result result; 

    public ProdutoController(Result result){
        this.result = result;
    }

    @Get("/produtos/valida")
    public void validaProduto(Produto produto){
        //valida da forma que vc achar melhor

       //aqui tem várias formas...
       // retornar true ou false
       result.use(Results.json).from(expressãoBooleana).serialize();
     
       // ou tb se não tiver o produto devolve um status 200 
       result.nothing();

       // e se tem o nome daquele produto lança uma exceção  
    }

}

não sei se ficou muito claro pra vc… tenta aih

Lucas_Cavalcanti

um jeito bom é usar as anotações do bean validations… tipo @NotNull, @NotEmpty, @Length, etc… e no VRaptor usar só:

validator.validate(objeto);
vitor.morales

Pessoal.

Acho que esse modo vai resolver meu problema. Mas gostaria que fosse algo assim.

Ao enviar o formulário eu faço um monte de validação via javascript como se os campos estão no formato válido etc …
Gostaria uma requisição ajax que chamasse o método pra adicionar o produto e neste método tem as validações do tipo se já existe.
Caso tenha sucesso ou erro eu devo retornar uma mensagem específica pra tela e mostrar num alert por exemplo sem que seja necessário recarregar a página.

Como faria isso de um modo limpo ?
Eu implemento no .submit() do formulário umas validações javascript mesmo, mas necessito dessa lógica de validação também na camada da aplicação.

Agradeço a paciência ai !
Caso puderem dar um exemplo simples ou enviar alguma página que contenha um exemplo melhor ainda !

Abraços !

Vitor Morales

kadu.m.lino

Eai vitor!

vc pode fazer por ajax msm! o exemplo que te dei funciona para o seu caso! ou não?

por exemplo… se vc quer validar se o login de um usuário já foi cadastrado… no envento onblur do seu input vc teria um evento

e nele teria uma função ajax que bateria no controller e o controller te retornaria uma resposta de que achou ou não esse nome no banco! ou qualquer outra lógica de validação que vc precisar!

qual o problema que vc está tendo?

vitor.morales

É mais ou menos isso …
Mas como eu faço pra retornar um mensagem de erro do controlador pra página ?

Do tipo … dentro do método de adição possui alguns validações e pra cada validação eu preciso retornar uma mensagem diferente.

Como faço isso ?

e eu tenho essas validações javascript que não foram feitas por mim … como integraria isso dentro da função ajax submit ?

$('#newNetworkForm').submit(function() {         
         
        //Validações antes de executar o comando final
        if($("#nomeRede").val() == ""){            
            $('#nomeRede').css('border','red solid 1px');
            alert("Digite um nome");
            $('#nomeRede').focus();
            return false;
        }
        else
        if($("#localRede").val() == ""){
            
            $('#localRede').css('border','red solid 1px');
            alert("Digite um Local");
            $('#localRede').focus();
            return false;
        }
        else
        if($("#ipRede").val() == ""){
            
            $('#ipRede').css('border','red solid 1px');
            alert("Digite um IP");
            $('#ipRede').focus();
            return false;
        }
        else
        if($("#mascaraRede").val() == ""){
            
            $('#mascaraRede').css('border','red solid 1px');
            alert("Digite uma Máscara");
            $('#mascaraRede').focus();
            return false;
        }
        else
        //Validação de Ip e Mask
        if(validarIP($("#ipRede").val()) == false){
            
            alert("Digite um IP válido");
            $("#ipRede").val("");
            $("#ipRede").focus();
            return false;
        }
        else
        if(validarIP($("#mascaraRede").val()) == false){
            
            alert("Digite uma Máscara válida");
            $("#mascaraRede").val("");
            $("#mascaraRede").focus();
            return false;
        }
        else
        if((validarIP($("#gatewayRede").val()) == false))
        {
            alert("Digite um Gateway válido.");
            $("#gatewayRede").val("");
            $("#gatewayRede").focus();
            return false;
            
        }
    
        $("#ipRede").val(ip2long($("#ipRede").val()));        
        $("#mascaraRede").val(ip2long($("#mascaraRede").val()));       
        $("#gatewayRede").val(ip2long($("#gatewayRede").val()));
        
        
    });

Sem que eu precise redirecionar ou recarregar a página até pq a navegação tbm ta via ajax.
Ao clicar num item do menu ele carregar uma outra página dentro de um div na página principal

Lucas_Cavalcanti

se vc quiser fazer isso batendo no servidor, vc pode fazer algo do tipo:

@Get("/bla")
public void valida(Objeto objeto) {
  validator.validate(objeto);
  validator.onErrorSendBadRequest();
  result.nothing();
}

daí vc pode fazer no javascript, antes do submit:

$.getJSON('.../bla').success(function() { form.submit() }).error(function(errors) {
   //mostra os erros
});
Lucas_Cavalcanti

ah… use o jquery validator, é melhor.

vitor.morales

Estou tentando da forma que foi passada ali via ajax

Mas me parece que tem algum erro na função. Alguma idéia ?
O método no controlador não está sendo chamado. O blur funciona se tirar o método $.ajax

Acho que aquilo lá resolve mesmo.

vitor.morales

Resolvi

$("#nomeRede").blur(function(){  
        alert("Blur");        
        
        $.ajax({  
            url: '<c:url value="/network/validate"/>',  
            type: "POST",  
            data : {
                p: $("#nomeRede").val()
            }, 
            dataType: "application/json",  
            success : function(data){  
                alert("ok");
            },   
            error : function () {  
                alert("erro");  
            }
        });

Vou tentar fazer o que tinha imaginado aqui e respondo.

Vlw pessoal.

vitor.morales

Ainda assim o método no controlador não foi chamado … o que pode ser ?
Ele sempre caio no caso de error do ajax;

Resolvi retirando o @Get do método e colocando @Path

Lucas_Cavalcanti

é por causa do type: “POST”, … só trocar pra GET

vitor.morales

Como faço pra retornar um texto no caso de erro pra função pra poder imprimir isso no alert?

Do tipo “Nome de rede existente”.

Lucas_Cavalcanti

se vc usar o esquema do validator.onErrorSendBadRequest(), só adicionar uma validação antes disso:

if (alguma coisa)
  validator.add(new ValidationMessage("Nome de rede existente", "algo"));

isso vai estar disponível na função de success.

vitor.morales

e como é esse esquema do validator.onErrorSendBadRequest() ?
hahaha

Lucas_Cavalcanti

o que eu tinha falado numa msg anterior:

http://www.guj.com.br/java/293030-vraptor---forma-de-validacao#1558899

vitor.morales

Eu mudei tudo.

Não consegui fazer da forma que eu queria.

O meu formulário agora envio via ajax e faço as validações dentro do metodo addNetwork.
Mas como eu retorno uma mensagem de erro dessa forma pra ser exibido no error: do ajax ?

Lucas_Cavalcanti

tb falei numa msg anterior:

http://www.guj.com.br/java/293030-vraptor---forma-de-validacao/2#1559012

só adicionar erros de validação.

vitor.morales

E como eu faço pra pegar essa mensagem na tela la no success ou no error ? ?

Lucas_Cavalcanti
success: function(coisa) {
   // coisa é o retorno de sucesso
},
error: function(erros) {
   // só pegar esse erros e fazer o que vc quiser
}
vitor.morales
function formAjaxSubmit()
    {
        $.ajax({
            type: "POST",
            url: "/network/add",
            data: {
                "p_network.name" : $("#nomeRede").val(),            
                "p_network.comments": $("#comentarioRede").val(),
                "p_network.baseIP": ip2long($("#ipRede").val()),
                "p_network.mask": ip2long($("#mascaraRede").val()), 
                "p_network.VLanID": $("#vlanIDRede").val(),
                "p_network.gateway": ip2long($("#gatewayRede").val()),
                "p_network.dns": $("#dnsRede").val()
            },
            success: function(success) {
                alert("ok");
            },
            error: function(error) {
                alert("Erro: "+ error);
            }
        })
    }
@Restrict
    @Post("/network/add")
    public void addNetwork(Network p_network)
    {                
         if(NETWORK_SERVICE.checkExistentNetwork(p_network.getName())) 
         {
            VALIDATOR.add(new ValidationMessage("Nome de rede existente.", "error")); 
                        
         }
         else
         {
            RESULT.nothing();
         }

    }

Ta imprimindo o object como faço pra pegar a mensagem que coloquei ali ? Essa era a pergunta.
Tem algo de errado nisso ?

kadu.m.lino

Ficaria assim o seu controller:

if (NETWORK_SERVICE.checkExistentNetwork(p_network.getName())) {
	validator.add(new ValidationMessage("Nome de rede existente.", "error"));
}
validator.onErrorSendBadRequest();
result.nothing();

e o seu ajax ficaria assim:

function formAjaxSubmit(){
    //....
    success: function(success) {  
         alert("ok");  },
    statusCode: {
	400: function(data) {
	var resposta = JSON.parse(data.responseText);
        //faz qualquer coisa com a resposta... 
    }
}
vitor.morales

Beleza …
Acho que agora eu entendi … mas fiz esses passos ai e não funcionou ainda.

function formAjaxSubmit()
    {
        $.ajax({
           //....
            success: function(success) {
                alert("Ok");
            },
            statusCode: {
                400: function(data)
                {
                    var response = JSON.parse(data.responseText);
                    alert("Erro:"+response);
                }
            }           
        })
    }
@Restrict
    @Post("/network/add")
    public void addNetwork(Network p_network)
    {                
         if(NETWORK_SERVICE.checkExistentNetwork(p_network.getName())) 
         {
            VALIDATOR.add(new ValidationMessage("Nome de rede existente.", "error"));                         
         }
         VALIDATOR.onErrorSendBadRequest();  
         RESULT.nothing;
         //...
Lucas_Cavalcanti

ele chega a passar pelo controller?

vitor.morales

Ta passando sim .

Tive que alterar só o endereço no ajax de “/network/add” para "network/add"
Mas ainda a mensagem não ta sendo exibida.

kadu.m.lino

posta o código!

vitor.morales
function formAjaxSubmit()
    {
        $.ajax({
            type: "POST",
            url: "network/add",
            data: {
                "p_network.name" : $("#nomeRede").val(),            
                "p_network.comments": $("#comentarioRede").val(),
                "p_network.baseIP": ip2long($("#ipRede").val()),
                "p_network.mask": ip2long($("#mascaraRede").val()), 
                "p_network.VLanID": $("#vlanIDRede").val(),
                "p_network.gateway": ip2long($("#gatewayRede").val()),
                "p_network.dns": $("#dnsRede").val()
            },
            success: function(success) {
                alert("Ok");
            },
            statusCode: {
                400: function(data)
                {
                    var response = JSON.parse(data.responseText);
                    alert("Erro:"+response);
                }
            }           
        })
    }
@Restrict
    @Post("/network/add")
    public void addNetwork(Network p_network)
    {                
         if(NETWORK_SERVICE.checkExistentNetwork(p_network.getName())) 
         {
            VALIDATOR.add(new ValidationMessage("Nome de rede existente.", "error"));                         
         }
         VALIDATOR.onErrorSendBadRequest();  
         RESULT.nothing();
         
//        NETWORK_SERVICE.addOrUpdateNetwork(p_network);
//        RESULT.nothing();
    }
Lucas_Cavalcanti

troca tudo por:

$.getJSON("network/add", 
     {  
        "p_network.name" : $("#nomeRede").val(),              
        "p_network.comments": $("#comentarioRede").val(),  
        "p_network.baseIP": ip2long($("#ipRede").val()),  
        "p_network.mask": ip2long($("#mascaraRede").val()),   
        "p_network.VLanID": $("#vlanIDRede").val(),  
        "p_network.gateway": ip2long($("#gatewayRede").val()),  
        "p_network.dns": $("#dnsRede").val()  
     }).success(function(success) {  
         alert("Ok");  
     }).error(function(data) {  
               alert("Erro:"+data);              
     }) ;

e troque de @Post("/network/add") pra @Get("/network/add")

vitor.morales

E é correto fazer isso usando Get ? formulários de cadastro do tipo não deveriam ser requisições Post não ?

kadu.m.lino

vitor.morales

Funfou porém a mensagem de erro ta “Erro: Object [objetc]” … algo do tipo.

vitor.morales

O que ? … Falei besteira ? kkkkk

kadu.m.lino

n, apenas respondi atrasado, n tinha visto q o lucas tinha respondido! rs

Lucas_Cavalcanti

apareceu [object Object] pq é um json… um objeto javascript…

pra vc imprimir as mensagens vc pode fazer algo como:

.error(function(messages) {
     $(messages).each(function() {
         alert(this.message);
     });
});
vitor.morales

Beleza… agora ta correto.
Mas a mensagem exibida esta sendo “Undefined”

E volta a pergunta … é correto usar requisições do tipo Get para cadastro e não Post ?

Lucas_Cavalcanti

troque o alert por console.log(messages) e veja isso no console do browser (Developer tools no Chrome, Firebug no Firefox)

vitor.morales

No final ta assim

responseText:"{“errors”: [{“message”: “Nome de rede existente.”,“category”: “error”}]}", status:400, statusText:“Bad Request”})

Interessante isso … usava essa ferramente mas não com log e console assim.

E ai ?

Lucas_Cavalcanti

bom, como você viu a mensagem tá aí, só usá-la pra mostrar na tela do jeito que vc achar melhor.

vitor.morales

Mas como eu pego a messagem … essa é a questão…

E sobre o envio do formulário ? É correto enviar pelo método Get ? Não post ?

Lucas_Cavalcanti

dá uma olhada:

{\"errors\": [{\"message\": \"Nome de rede existente.\",\"category\": \"error\"}]}

ou seja, da variável que veio na função, vc tem que chamar variavel.errors[0].message

ex:

.error(function(data) {
 var mensagem = data.errors[0].message;
  alert(mensagem); // ou algo melhor
});

o formulário tem que ser @Post, mas nesse caso vc tá fazendo um ajax ANTES de submeter o formulário, só pra verificar se a validação está correta. Como esse ajax não modifica nada no servidor, pode ser @Get sem problemas.

vitor.morales

entendi ali em cima …

Mas nesse caso cara
Eu vou fazer essa validação na hora que enviar o formulário e se caso existir algum registro com o mesmo nome eu retorno o erro senão já faço o cadastro no banco
Então deveria nesse caso enviar por post mesmo … tem alguma forma ?

Lucas_Cavalcanti

o ideal é vc no success fazer um form.submit() de verdade… algo como isso:

$('#seu-form').submit(function() {
   var form = this;
   $.getJSON(.....)
     .success(function() {
         form.submit();
     }).error(.....);
});

assim se a requisição ajax deu tudo certo vc faz o submit de tudo.

Lucas_Cavalcanti

faltou uma coisa, tem que dar um return false no final desse callback de submit

vitor.morales

Entendi … mas como eu faço para não realizar o submit no caso de erro ?

E no caso de sucesso eu não gostaria de retornar pra nenhuma outra página … mas só enviar de volta uma mensagem de sucesso que vai aparecer num alert do tipo "Cadastro realizado’.

Lucas_Cavalcanti

então o que vc quer é mais parecido com esse plugin do jquery:

http://malsup.com/jquery/form/

ele transforma o submit de um form qualquer em ajax.

vitor.morales

Cara … perfeito … agora ta redondo … da uma olhada no código…

Só to com dificuldade pra descobrir ainda como imprimir a mensagem que enviei no validator do controller no caso de erro.

var formOptions = {
        beforeSubmit: validate,
        success: showSuccess,
        error: showError        
    };
    
    $('#newNetworkForm').ajaxForm(formOptions);
    
    function showError(responseText, status, err){
       
        console.log(status);
        alert("Errors");
    }
    
    function showSuccess(responseText, statusText, xhr, jqForm ){
        alert("Sucesso");       
    }
    
    function validate(formData, jqForm, options){
           
        
//....
vitor.morales

coloquei esse código na função validate…

mas como no caso eu faço pra caso caia no error … ele retornar falso e cancelar o submit ?

$.getJSON("network/validate",   
         {    
            "p_network.name" : $("#nomeRede").val()           
        
         })   
         .error(function(data) {    
                   alert("Existe rede com o mesmo nome");
                   return false;
         }) ;
Lucas_Cavalcanti

se vc vai fazer um ajaxForm já, faz a validação já no método que recebe o post do form, não precisa criar um método a mais…

daí vc consegue tratar o erro já no showError

vitor.morales

Ok …
E no showError como receber a mensagem do validator ? To procurando aqui no console mas não to conseguindo.
Na variavel err vem o valor Not Found não a mensagem

Lucas_Cavalcanti

a variavel responseText deveria ter o json, se passou por aquele onErrorSendBadRequest…

na verdade vc pode mudar esse onErrorSendBadRequest por:

validator.onErrorUse(json()).withoutRoot().from(validator.getErrors()).serialize();

o badRequest deve estar procurando uma jsp que não existe.

vitor.morales

Ok …

Nesse código que passou o IDE não consegue resolver o json()… ta correto a escrita ?

Lucas_Cavalcanti

Results.json() e esse Results é do VRaptor

vitor.morales

Agora funcionou porém mesmo com os erros ta caindo no caso success do ajax

Lucas_Cavalcanti

justo…
volta pro onErrorSendBadRequest e faz no javascript, muda o formOptions pra:

var formOptions = {  
        beforeSubmit: validate,  
        success: showSuccess,
        dataType: "json",
        error: showError          
    };

e veja se no error aparece o json

vitor.morales

Blz

Funcionou … porém olha que estranho.

function showError(responseText, status, err){     
        alert('teste');
        console.log(responseText);
        alert("tam"+responseText.length); 
        for(var count = 0; count < responseText.length; count++)
        {
            alert(responseText[count].message);            
        }           
        
    }

No Console aparece o objeto responseText com as mensagens certinho … mas vou imprimir no alert aparece undefined ?
O que fiz de errado ai ?

Lucas_Cavalcanti

o responseText tá aparecendo como String ou como Object no console log?

vitor.morales

object

Lucas_Cavalcanti

e qual é a estrutura desse object? esse for que vc postou só serve se ele for um array… se for um:

{ "errors" : [ { "message": ".....", .... } ] }

vc tem que iterar em responseText.errors

vitor.morales
console.log(responseText);
console.log(responseText.errors);

//---------------------

responseText:"{\"errors\": [{\"message\": \"Nome de rede existente\",\"category\": \"existentError\"}]}", status:400, statusText:"Bad Request"})

undefined
undefined

E ai ?

Lucas_Cavalcanti

ele tá vindo como string então… vc tem que mudar o dataType da requisição ajax pra “json”, ou fazer um:

var json = JSON.parse(responseText);
var errors = json.errors;
//  imprimir esses errors.
vitor.morales
var formOptions = {
        beforeSubmit: validate,    
        success: showSuccess,  
        dataType: "json",  
        error: showError                  
    };

Já esta json …

Tentei sem e utilizando esse JSON.parse e ocorre um erro “JSON. parser unexpected charcter”

Lucas_Cavalcanti

aqueles console.log estão em qual função? na showSuccess? na showError? na validate?

vitor.morales

showError

Lucas_Cavalcanti

se o dataType tá como json, o responseText deveria ser o JSON já parseado… não uma string…

tem algo bem estranho acontecendo…

só pra ficar na mesma página, tenta fazer assim:

var formOptions = {  
    beforeSubmit: validate,      
    success: showSuccess,    
    dataType: "json",    
    error: function(json) {
         console.log(json);

         console.log(json.errors);
         console.log(json.errors[0].message);
    }                    
};

e veja o que aparece

vitor.morales

Resolvi aqui.

Parece que apesar de JSON estar definido lá ele vem em string.

Daí fiz isso.

function showError(response, status, err){     
                   
        var resposta = $.parseJSON(response.responseText);
        $.each(resposta.errors, function(i, erro) {
            alert(this.message);
        });
    }

Agora ta certo.
Vlw cara ! Muito obrigado ai ! … Aprendi até mais do que precisava.

Abraços !

Criado 6 de fevereiro de 2013
Ultima resposta 28 de fev. de 2013
Respostas 67
Participantes 3