Programador ajudante e aprendiz da comunidade open source.

Manipulando Dados JSon Via Ajax Com VRaptor 3

Olá pessoal,

Falarei um pouco de um novo jeito de manipular dados: JSon.

Com o JSon é possivel transformar um objeto Java em um conjunto de Strings que representará seu objeto e terá a forma de acesso aos seus atributos da mesma forma que um objeto Java normal, tornando-se um intermediário poderoso entre uma linguagem e o JavaScript.

Objetivo

Criar uma função que busca um usuário no banco e coloca os dados em um formulário deixando tudo pronto para uma edição, tudo via ajax utilizando JSon como meio de transporte e o VRaptor como gerenciador.

Para começarmos precisaremos de um projeto VRaptor, você pode baixar o Blank Project que atualmente esta em sua versão 3.1 e caso tenha alguma dificuldade poderá ler o artigo Iniciando Com VRaptor 3

Mãos à obra

Começaremos criando um classe chamada Contato:

public class Contato {

    private String telefone;
    private String celular;

   // getters e setters

}

E outra classe Usuario que possui um Contato.

public class Usuario {

    private Long id;
    private String nome;
    private String senha;
    private String email;
    private Contato contato;

    // getters e setters

}

Criamos duas classes nas quais representarão os dados do usuário buscado no banco.

Criaremos um DAO para simular o retorno do usuário a partir do banco:

@Component
public class UsuarioDao {

    public Usuario loadById(Long id) {
        if (id != null) {
            Usuario usuario = new Usuario();
            usuario.setId(id);
            usuario.setEmail("[email protected]");
            usuario.setNome("Washington Botelho dos Santos");
            usuario.setSenha("wbotelhos");

            Contato contato = new Contato();
            contato.setCelular("13012010");
            contato.setTelefone("13012005");

            usuario.setContato(contato);

            return usuario;
        }

        return null;
    }
}

Nosso DAO simula a recepção de um ID que a partir do mesmo buscaria um usuário no banco, mas ao invés disso, apenas criaremos um objeto Usuario na mão e retornaremos para quem chamar o método loadById.

Com nossa camada de persistência pronta vamos criar o controller que irá gerenciar nossas ações:

@Resource
public class UsuarioController {

    private UsuarioDao usuarioDao;
    private Result result;

    public UsuarioController(Result result, UsuarioDao usuarioDao) {
        this.result = result;
        this.usuarioDao = usuarioDao;
    }

    @Get
    @Path("/usuario")
    public void novo() {
    }

    @Get
    @Path("/usuario/editar/{usuario.id}")
    public void editar(Usuario usuario) {
        Usuario user = usuarioDao.loadById(usuario.getId());
        result.use(json()).from(user).include("contato").serialize();
    }

}
  • Injetamos o Result e o UsuarioDao para que possamos utilizá-los no controller;
  • Um método para redirecionar para a página novo.jsp na qual contêm nosso formulário e se encontra dentro da pasta usuario; e
  • Um método editar que recebe um ID e chama o DAO para buscar o usuário correspondente no banco.

Pra quem já esta familiarizado com o VRaptor, este controller não tem nada demais, a não ser uma recente funcionalidade na qual serializa um objeto em formato JSon:

result.use(json()).from(user).include("contato").serialize();

Nessa linha acima dizemos ao result que iremos utilizar o resultado em formato JSon e logo em seguida dizemos de onde virá os dados, neste caso do objeto Usuario que acabamos de buscar no banco. Sei que você lembrou que este possui uma referência para um objeto Contato, e logo percebeu que o incluímos na serialização, bastanto agora apenas chamar o método serialize para concluir a ação.

Onde ficam estes dados?

Caso não serializássemos o nosso objeto o VRaptor iria nos redirecionar para a página /usuario/novo.jsp, porém mudamos o content-type do nosso resultado para json() com isso iremos para uma "página" criada pelo VRaptor com os dados serializados.

Se acessarmos a URL http://ip:porta/json-ajax-vraptor-3/usuario/editar/1 por exemplo o navegador irá pedir para fazermos download de um arquivo sem extensão de mesmo nome do ID que passamos, no caso 1. Abra este arquivo e verá os dados serializados.

Como são estes dados serializados?

Os dados são de simples leitura representados por Strings sempre dentro de chaves iniciais padrão:

{
    "usuario": {
        "id": 2,
        "nome": "Washington Botelho dos Santos",
        "senha": "wbotelhos",
        "email": "[email protected]",
        "contato": {
            "telefone": "13012005",
            "celular": "13012010"
        }
    }
}
  • Nosso JSon começa com chaves e dentro delas o nome do nosso objeto que se chama usuario;
  • Dentro de usuario envolvido por chaves para indicar um conjunto de atributos pertecente a um objeto esta todos os atributos do objeto usuario;
  • Separamos do lado esquerdo o nome do atributo e do lado direto separado por dois pontos ':' o valor do atributo em questão;
  • Repare que temos todos nossos atributos entre aspas, assim como os valores dos mesmos;
  • Temos um sub-bloco dentro de usuario chamado de contato, que também é um objeto, logo os atributos de contato também estarão contidos dentro de um conjunto de chaves.

Por padrão o nome do objeto é utilizado no JSon, caso queira personalizá-lo basta incluir como primeiro parâmetro do método from o nome que deseja: .from("nomeObjeto", user)>

Parabéns, você agora já conhece o formato JSon e já esta preparado para capturar estes dados e manipulá-los da forma que achar melhor. O VRaptor já fez seu trabalho, agora vamos desfrutar do Ajax para concluirmos nosso objetivo e nos tornamos "Trendys"! d:B

Formulário de edição:

Vamos criar nosso formulário que será preenchido com os dados consultados:

<form>
    ID: <input id="id" type="text"/>
    Nome: <input id="nome" type="text"/>
    Senha: <input id="senha" type="text"/>
    E-mail: <input id="email" type="text"/>

    Telefone: <input id="telefone" type="text"/>
    Celular: <input id="celular" type="text"/>

    <input type="button" value="Salvar"/>
</form>

Um formulário normal, sem muito segredo. Todos os campos devem ter um ID para servir de âncora e podermos manipulá-los.

Também criaremos um formulário para que possamos digitar o ID da consulta:

<form>
    Buscar ID: <input id="idBusca" type="text"/>
    <input type="button" value="Consultar" onclick="consultar();"/>
</form>

Com isso nosso objetivo esta quase concluído, faltando apenas fazer uma manipulação JavaScript.

Como sabemos trabalhar com JavaScript puramente é massante, trabalhoso e mais propício a erros, então vamos ser "descolados" e utilizar uma framework, no caso o jQuery.

Ah! No dia 14 de Janeiro de 2009 foi aniversário do jQuery e nada melhor do que começarmos a utilizar sua nova versão 1.4. (;

Vamos importar o script jquery-1.4.js:

<script type="text/javascript" src="<c:url value='/js/jquery-1.4.js'/>"></script>

Com o script importado só nos resta criar a função que chama a página com os dados JSon via Ajax e logo em seguida utilizá-los. (:

Função JavaScript Consultar:

Primeiramente vamos declará-la e já capturar o ID pelo qual o usuário quer fazer a busca.

<script type="text/javascript">
    function consultar() {
        var idBusca = $('#idBusca').val();
               // ...
    }
</script>

Precisamos agora de um método do jQuery chamado getJSON, no qual a partir de uma url nos retorna um objeto em JavaScript vindo de uma página com dados JSon via ajax, ou seja, de forma assíncrona.

$.getJSON('<c:url value="/usuario/editar/"/>' + idBusca, function (json) {
    // ...
}

A passagem de parâmetro como segundo argumento é opcional e como queremos passar apenas o valor do ID para ser "injetado" na entidade que o espera no controller, este foi passado embutido no primeiro parâmetro junto a URL.

Podemos também utilizar a função que nos retorna um JSon via post, porém não existe postJSON, sendo necessário passar um parâmetro entre aspas do tipo do retorno, no caso 'json' logo após o callback.

O callback (retorno) estando contindo dentro da variável json, podemos utilizar este conteúdo como se fosse um objeto normal, assim se temos um objeto Usuario, basta acessar seus atributos com um ponto '.' da mesma forma que um objeto Java, ficando nosso método final o seguinte:

<script type="text/javascript">
    function consultar() {
        var idBusca = $('#idBusca').val();

        $.getJSON('<c:url value="/usuario/editar/"/>' + idBusca, function (json) {
            $('#id').val(json.usuario.id);
            $('#nome').val(json.usuario.nome);
            $('#email').val(json.usuario.email);
            $('#senha').val(json.usuario.senha);

            $('#telefone').val(json.usuario.contato.telefone);
            $('#celular').val(json.usuario.contato.celular);
        });
    }
</script>

Pronto, agora cada campo recebe seus devidos valores de atributo.

Com isso vimos como o VRaptor nos ajuda a criar o JSon, uma ótima estrutura de dados na qual é totalmente compatível com JavaScript e consequentemente muito conveniente a implementação com Ajax.

Link do projeto:

http://github.com/wbotelhos/manipulando-dados-json-via-ajax-com-vraptor-3

  1. Bayma 18 Mai 2012 08:43

    [DÚVIDA]
    Sei que faz muito tempo deste post mas...
    e se o usuário tiver uma lista de contatos como eu faço? Estou com esse problema :(

  2. Geovana 14 Out 2011 12:09

    Washington,

    O exemplo apresentado está sendo utilizado em um sistema que estamos desenvolvendo na minha empresa. O sistema estava sendo testado no JBOSS 5.1 EAP. Agora a empresa comprou o WEBLOGIC 11g (10.3.5) e vamos ter que fazer o deploy da aplicação no WEBLOGIC. Ao fazer os testes iniciais no WEBLOGIC, ocorreu o seguinte:

    • O retorno do JSON não acrescenta o root, ou seja, no exemplo abaixo, no WEBLOGIC, o retorno vem sem o "usuário" da linha 02. A serialização comporta como se tivessemos chamado o método "withoutRoot". Porém, no JBOSS, funciona conforme está no exemplo.
    {  
        "usuario": {  
            "id": 2,  
            "nome": "Washington Botelho dos Santos",  
            "senha": "wbotelhos",  
             "email": "[email protected]",  
            "contato": {  
                "telefone": "13012005",  
                "celular": "13012010" 
            }  
        }  
    } 
    

    Você tem alguma dica para resolver este problema no WEBLOGIC?

    1. Washington Botelho autor 14 Out 2011 19:31

      Fala Geovane,

      Cara, tú já fez um debug pra ver se a entidade esta chegando certinha, é o mesmo método com o .withoutroot() e tal?
      Atualiza o VRaptor para a versão 3.4 que tem alguns fix do XStream também.

      Esse é aquele tipo de erro que você se mata pra descobrir depois de tempos que é uma outra coisa totalmente fora do contexto.

  3. juniorsatanas 18 Jul 2011 12:37

    Como vai fiar o script :

    function consultar() {
        var idBusca = $('#idBusca').val();
    
        $.getJSON('' + idBusca, function (json) {
            $('#id').val(json.usuario.id);
            $('#nome').val(json.usuario.nome);
            $('#email').val(json.usuario.email);
            $('#senha').val(json.usuario.senha);
            $('#telefone').val(json.usuario.contato.telefone);
            $('#celular').val(json.usuario.contato.celular);
        });
    }
    

    ja que os meus dados vem do banco?
    os nomes dos meus campos ficam como?
    por exemplo: clienteFisica.clfiNome

  4. Jandrei Carlos Masiero 9 Fev 2011 06:06

    Parabéns, seu blog é muito bom!!!

  5. Moacir RF 25 Out 2010 13:42

    Excelente!! Parabens!

  6. Flavio Duarte 16 Jul 2010 19:07

    mas eu quero criar o arquivo pagina.json.jsp para json não tem muito sentido, mas por exemplo com um xml para formatar para RSS tem algum sentido dai eu criei o arquivo mas não ta funcionando :(
    tens idéia do que pode ser?

    1. Washington Botelho autor 16 Jul 2010 21:20

      Flávio,

      Seu arquivo deve ter o nome do método do seu controller + .xml.jsp (usuario.xml.jsp). Lembrando que você inclui o objeto no result, logo na sua jsp você recupera este mesmo objeto usando ${nomeDadoNoInclude}. Detalhe que o VRaptor nesse caso não vai gerar o XML nem o JSON pra você, terá de fazer isso na unha.

  7. Flavio Duarte 16 Jul 2010 13:31

    Legal o tutorial, eu depois estava dando uma olhada na documentação e com a necessidade de implementar um template para o json e achei essa página: http://vraptor.caelum.com.br/documentacao/view-e-ajax que fala: Accepts e o parâmetro _format

    fiz tudo o que ta ali e não funcionou, tens idéia por que?

    Abraços

    1. Washington Botelho autor 16 Jul 2010 14:40

      Fala Flávio,

      Não entendi qual é a dúvida. Especifique melhor o que você quer fazer e o que esta dando errado.

      Se for um resultado JSON, utilize o Results.json(), em vez de http://URL?_format=json
      Assim evita criar um pagina.json.jsp para manter o resultado, pois o VRaptor já te entrega isso como resposta.

  8. Arthur Moura Carvalho 4 Mai 2010 15:54

    Boa cara!
    O tutorial ajudou bastante.

  9. Diogo Soares 30 Mar 2010 11:37

    Cara ficou muito bom esse teu exemplo, eu tava apanhando em uns detalhes no vraptor 3 mais agora realmente me abriu a mente, valeu mesmo.

  10. Rusco 8 Mar 2010 10:55

    Ainda não percebo pq o vraptor inclui o XStream original e não a versão modificado que resolve os issues de reflecção com a Google Appengine !???

    json + vraptor 311 não funciona ("out of the box") em cima de GAE !!!!!

    1. Washington Botelho autor 8 Mar 2010 14:25

      Eu não tive esse problema já que não utilizo o GAE.
      Mas você pode ajudar os desenvolvedores mandando este bug para a Lista do VRaptor: caelum-vraptor[@]googlegroups[.]com

      Caso resolva seu problema, utilize o FlexJson que é muito bom.

      Obrigado pelo feedback.

  11. Fabio 27 Fev 2010 20:55

    Tá ... pode me chamar de mané!

    import static br.com.caelum.vraptor.view.Results.json
    
  12. Fabio 27 Fev 2010 20:53

    Não entendi esse tal json() ... daonde veio isso?

    1. Washington Botelho autor 1 Mar 2010 09:11

      json() é um método próprio do VRaptor, porém esta escrito de uma forma resumida, sem mencionar o pacoto no qual pertence, que no caso é uma nova feature do Java 5. O import static serve apenas para resumir a escrita. Vejamos:

      import java.lang.Math;
      
      double r = 2.0;
      double area = (Math.PI * R) * (Math.PI * R);
      

      Desta forma, para acessar o PI que é estático devemos mencionar o pacote, porém podemos resumir simplesmente com:

      import static java.lang.Math.PI;
      
      double r = 2.0;
      double area = (PI * R) * (PI * R);
      

      No nosso caso a forma sem static ficaria:

      import br.com.caelum.vraptor.view.Results;
      
      Results.json();
      

      De fato, o static torna o código muito mais ilegível e não é todos programadores que gostam.

  13. Rodrigo Bisterço 22 Fev 2010 19:28

    Washington,

    Utilizando seu exemplo, estava com problemas com acentuação.
    Para funcionar fiz as seguintes alterações no novo.jsp:

     <%@ page contentType="text/html; charset=ISO-8859-1"%>
    

    no web.xml:

    <context-param>
        <param-name>br.com.caelum.vraptor.encoding</param-name>
        <param-value>ISO-8859-1</param-value>
    </context-param>
    
    1. Washington Botelho autor 22 Fev 2010 19:58

      Isso ai Rodrigo, eu apenas tinha omitido tais códigos assim como outras tags padrões.
      Eu costumo utilizar:

      <jsp-config>
          <jsp-property-group>
              <url-pattern>*.jsp</url-pattern>
              <page-encoding>ISO-8859-1</page-encoding>
          </jsp-property-group>
      </jsp-config>
      

      Pois já incluo um prelude nessa tag.
      Mas ambos funcionam. (:

      Abraço.

  14. Rodrigo Bisterço 18 Fev 2010 20:49

    Washington,

    Muito legal esse exemplo !!

    Valeu.

Em resposta:
(cancelar)
Formate seu código utilizando Markdown.