Introdução ao Ajax para Aplicações Java Web

Este documento oferece uma introdução ao Ajax e demonstra algumas das funncionalidades no NetBeans IDE que permitem que você programe de forma mais rápida e eficaz ao trabalhar com tecnologias relacionadas ao Ajax. Enquanto aprende sobre a funcionalidade de baixo nível do Ajax, você constrói uma aplicação simples que utiliza a função autocompletar em um campo de texto. O conteúdo aqui foi adaptado do artigo e da aplicação de amostra de Greg Murray Using Ajax with Java Technology.

Ajax significa Asynchronous JavaScript and XML. Na essência, o Ajax é uma forma eficiente de uma aplicação web tratar as interações do usuário com uma página web: uma forma que reduz a necessidade de fazer uma atualização da página ou uma recarga completa da página para cada interação do usuário. Isso permite um comportamento detalhado (semelhante ao de uma aplicação de área de trabalho ou aplicação web com base em plug-in) na utilização de um browser. As interações do Ajax são tratadas assincronamente em segundo plano. Enquanto isso acontece, um usuário pode continuar trabalhando com a página. As interações do Ajax são iniciadas pelo código JavaScript. Quando a interação do Ajax é concluída, o JavaScript atualiza o código-fonte HTML da página. As alterações são feitas imediatamente sem requerer uma atualização da página. As interações do Ajax podem ser utilizadas para fazer coisas como validar entradas do form (enquanto o usuário as está digitando) utilizando lógica do lado do servidor, recuperar dados detalhados do servidor, atualizar dinamicamente os dados em uma página e submeter forms parciais a partir da página.

Conteúdo

O conteúdo desta página se aplica ao NetBeans IDE 7.2, 7.3, 7.4 e 8.0

Para concluir este tutorial, você precisa dos seguintes recursos e softwares.

Software ou Recurso Versão Necessária
NetBeans IDE, pacote Java EE 7.3, 7.4, 8.0
JDK (Java Development Kit) 7 ou 8
GlassFish Server
ou
servidor Tomcat
Open Source Edition 3.1.x ou 4.x

versão 7.x ou 8.x

Observações:

  • A instalação do Java EE do IDE permite instalar o servidor GlassFish e o contêiner de servlets do Apache Tomcat.
  • Este tutorial presume que você tenha conhecimento das várias tecnologias que ele utiliza (ou seja, HTML, CSS, JavaScript, Java e JSP). Ele tenta fornecer uma visão geral da funcionalidade fornecida pelo código, mas não explica como o código funciona linha por linha.
  • Se você precisar comparar seu projeto com uma solução que funciona, faça download da aplicação de amostra.

Visão Geral da Aplicação

Imagine uma página web em que um usuário pode procurar informações sobre compositores de música. A página inclui um campo onde o usuário pode digitar o nome do compositor. Na aplicação de exemplo, o campo de entrada possui uma funcionlidade autocompletar. Em outras palavras, o usuário pode digitar parte do nome do compositor e a aplicação web tentará completar o nome, listando todos os compositores cujo nome ou sobrenome começa com os caracteres digitados. A funcionalidade autocompletar poupa o usuário de ter que lembrar o nome completo do compositor e pode fornecer um caminho mais intuitivo e direto para a informação procurada.

Aplicação de amostra exibida no browser

Implementar a funcionalidade autocompletar em um campo de pesquisa é algo que pode ser feito por meio do Ajax. O Ajax funciona com o emprego de um objeto XMLHttpRequest para passar solicitações e respostas assincronamente entre o cliente e o servidor. O diagrama a seguir ilustra o fluxo do processo da comunicação que acontece entre o cliente e o servidor.

Diagrama de fluxo de processo do Ajax

O fluxo de processo do diagrama pode ser descrito pelas seguintes etapas:

  1. O usuário aciona um evento, por exemplo, liberando uma tecla ao digitar um nome. Isso resulta em uma chamada do JavaScript para uma função que inicializa um objeto XMLHttpRequest.
  2. O objeto XMLHttpRequest é configurado com um parâmetro de solicitação que inclui o ID do componente que acionou o evento e qualquer valor que o usuário digitou. O objeto XMLHttpRequest faz uma solicitação assíncrona ao servidor web.
  3. No servidor web, um objeto como um servlet ou um listener trata a solicitação. Os dados são recuperados do armazenamento de dados, e é preparada uma resposta contendo os dados do form em um documento XML.
  4. Finalmente, o objeto XMLHttpRequest recebe os dados XML utilizando uma função de chamada de retorno, processa-os e atualiza o HTML DOM (Document Object Model) para exibir a página que contém os novos dados.

Este tutorial demonstra como construir o cenário da funcionalidade autocompletar, seguindo o fluxo do processo indicado no diagrama acima. Primeiro você cria os arquivos do lado do cliente para a apresentação e a funcionalidade necessárias para gerar o objeto XMLHttpRequest. Em seguida, você configura o lado do servidor, criando o armazenamento de dados e a lógica de negócio utilizando tecnologia baseada em Java. Finalmente, você retorna ao lado do cliente e implementa callback(), e outra funcionalidade JavaScript para atualizar o HTML DOM.


Programando o Lado do Cliente: Parte 1

Comece criando um novo projeto de aplicação Web no IDE. O IDE contém modelos incorporados para vários tipos de projeto.

  1. Escolha Arquivo > Novo Projeto. Em Categorias, selecione Java Web. Em Projetos, selecione Aplicação Web e clique em Próximo.
  2. No painel Nome e Localização, digite MyAjaxApp como o Nome do Projeto. O campo Localização do Projeto permite que você especifique a localização do projeto em seu computador. Deixe as outras opções como default e clique em Próximo.
    Assistente Aplicação Web - painel Nome e Localização
  3. No painel Servidor e Definições, selecione o servidor em que deseja implantar a aplicação. Somente os servidores registrados no IDE estão listados.
    Assistente Nova Aplicação Web - painel Definições do Servidor
  4. Aceite as outras definições default e clique em Finalizar. O projeto será gerado no sistema de arquivos e aberto no IDE.

Quando os projetos baseados em Java são criados, é gerado automaticamente um script de construção Ant que lhe permite compilar o projeto de forma que ele possa ser implantado imediatamente e executado em um servidor que tenha sido registrado no IDE.

Uma página de entrada default será gerada e aberta no Editor de Código-fonte do IDE. Dependendo do servidor de destino, a página de entrada será index.jsp ou index.html.

A janela Projetos que contém o projeto recém-criado

Antes de começar a codificar, tente rapidamente executar a aplicação para garantir que a configuração entre o IDE, seu servidor e o browser esteja configurada corretamente.

  1. Na janela Projetos, clique com o botão direito do mouse no nó do projeto e selecione Executar.

    A aplicação é compilada, o servidor de aplicações é iniciado e a aplicação é implantada nele e executada. O IDE abre seu browser default e exibe a página de entrada default.

Usando o Editor HTML

Paleta que exibe elementos HTML

Agora que você tem certeza de que seu ambiente está configurado corretamente, comece transformando sua página de índice na interface de autocompletar que será vista pelos usuários.

Uma das vantagens do uso de um IDE é que o editor em que você trabalha normalmente fornece a funcionalidade autocompletar código, o que, se você aprender a aplicar quando codifica, pode aumentar, rapidamente, a sua produtividade. O Editor de Código-fonte do IDE geralmente se adapta à tecnologia que está sendo utilizada, portanto, se você estiver trabalhando em uma página HTML, pressionar a combinação de teclas de autocompletar código (Ctrl-Espaço) produzirá sugestões para tags e atributos HTML. Como será mostrado mais tarde, o mesmo se aplica a outras tecnologias, como CSS e JavaScript.

Uma segunda funcionalidade que pode ser utilizada é a Paleta do IDE. A Paleta fornece modelos fáceis de utilizar para elementos que são comumente aplicados na tecnologia em que você está codificando. Você simplesmente clica em um item e arrasta-o para um local no arquivo aberto no Editor de Código-Fonte.

Você pode exibir ícones grandes (como exibido aqui) clicando com o botão direito do mouse na Paleta e selecionando Mostrar Ícones Grandes.


  1. Substitua o conteúdo das tags <title> e <h1> para que leia: Auto-Completion using AJAX. A página de índice não requer nenhuma codificação de script do lado do servidor, portanto, você pode deletar com segurança quaisquer remanescentes criados por default. A página de índice agora deve ter a seguinte aparência.
    <!DOCTYPE html>
    
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Auto-Completion using AJAX</title>
        </head>
        <body>
            <h1>Auto-Completion using AJAX</h1>
        </body>
    </html>
    
  2. Adicione algum texto explicativo para descrever a finalidade do campo de texto. Você pode copiar e colar no texto a seguir, no ponto logo abaixo das tags <h1>:
    <p>This example shows how you can do real time auto-completion using Asynchronous
        JavaScript and XML (Ajax) interactions.</p>
    
    <p>In the form below enter a name. Possible names that will be completed are displayed
        below the form. For example, try typing in "Bach," "Mozart," or "Stravinsky,"
        then click on one of the selections to see composer details.</p>
    
  3. Adicione um form HTML à página. Faça isso utilizando os elementos listados na Paleta do IDE. Se a Paleta não estiver aberta, selecione Janela > Paleta no menu principal. Em seguida, em Forms HTML, clique e arraste um elemento Form para a página, um ponto abaixo das tags <p> que você acabou de adicionar. A caixa de diálogo Inserir Form será aberta. Especifique o seguinte:

    • Ação: autocompletar código
    • Método: GET
    • Nome: autofillform
    Caixa de diálogo Inserir form

    Clique em OK. As tags HTML <form> serão inseridas na página que contém os atributos especificados. (GET é aplicado por default e, portanto, não é declarado explicitamente.)

  4. Adicione uma tabela HTML à página. Na categoria HTML na Paleta, clique em um elemento Tabela e arraste-o para um ponto entre as tags <form>. A caixa de diálogo Inserir Tabela será aberta. Especifique o seguinte:

    • Linhas: 2
    • Colunas: 2
    • Tamanho da Borda: 0
    • Preenchimento de Células: 5
    Caixa de diálogo Inserir tabela
  5. Clique com o botão direito do mouse no Editor de Código-Fonte e selecione Formatar. Isso limpa o código. Seu form agora deve ser semelhante ao abaixo:
    <form name="autofillform" action="autocomplete">
      <table border="0" cellpadding="5">
        <thead>
          <tr>
            <th></th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td></td>
            <td></td>
          </tr>
          <tr>
            <td></td>
            <td></td>
          </tr>
        </tbody>
      </table>
    </form>
    
  6. Na primeira linha da tabela, digite o seguinte texto na primeira coluna (alterações em negrito):
    <td><strong>Composer Name:</strong></td>
  7. Na segunda coluna da primeira linha, em vez de arrastar um campo Entrada de Texto da Paleta, digite o código abaixo manualmente (alterações em negrito):
    <td>
        <input type="text"
            size="40"
            id="complete-field"
            onkeyup="doCompletion();">
    </td>
    
    Enquanto digita, tente utilizar o suporte à funcionalidade autocompletar código incorporado do IDE. Por exemplo, digite <i e, em seguida, pressione Ctrl-Espaço. Uma lista de opções sugeridas será exibida abaixo do seu cursor e uma descrição do elemento selecionado aparecerá em uma caixa acima. De fato, você pode pressionar Ctrl-Espaço a qualquer momento em que estiver codificando no Editor de Código-Fonte para ter acesso às opções possíveis. Além disso, caso só haja uma opção possível, pressionar Ctrl-Espaço completará automaticamente o nome do elemento.
    Função Autocompletar Código exibida no Editor de Código-Fonte

O atributo onkeyup que você digitou acima aponta para uma função JavaScript chamada doCompletion(). Essa função é chamada toda vez que uma tecla é pressionada no campo de texto do form, e mapeia para a chamada JavaScript representada no fluxograma do Ajax acima.

Utilizando o Editor JavaScript

O novo Editor JavaScript do IDE fornece muitos recursos de edição avançados, como autocompletar código inteligente, realce de semântica, renomeação instantânea e recursos de refatoração, assim como muitas outras funcionalidades.

A funcionalidade autocompletar código JavaScript é automaticamente fornecida quando você codifica em arquivos .js, assim como em tags <script> quando trabalha com outras tecnologias (ou seja, HTML, RHTML, JSP, PHP). O IDE por fornecer algumas dicas quando você editar o código JavaScript. É possível especificar as opções de JavaScript escolhendo Ferramentas > Opções (NetBeans > Preferências, no Mac) para abrir a janela Opções e selecionar a linguagem JavaScript na guia Dicas, categoria Editor. Você também pode adicionar seus próprios modelos de código JavaScript na guia Modelos de Código, janela Opções.

Opções de Dicas de JavaScript na janela Opções

Adicione um arquivo JavaScript à aplicação e comece a implementar doCompletion().

  1. Na janela Projetos, clique com o botão direito do mouse no nó Páginas Web e escolha Novo > arquivo JavaScript. (Se o arquivo JavaScript não estiver listado, selecione Outro. Em seguida, escolha o arquivo JavaScript na categoria Web no assistente Novo arquivo.)
  2. Nomeie o arquivo como javascript e clique em Finalizar. O novo arquivo JavaScript aparecerá na janela Projetos, na pasta Páginas da Web.
  3. Digite o código abaixo em javascript.js.
    var req;
    var isIE;
    
    function init() {
        completeField = document.getElementById("complete-field");
    }
    
    function doCompletion() {
            var url = "autocomplete?action=complete&id=" + escape(completeField.value);
            req = initRequest();
            req.open("GET", url, true);
            req.onreadystatechange = callback;
            req.send(null);
    }
    
    function initRequest() {
        if (window.XMLHttpRequest) {
            if (navigator.userAgent.indexOf('MSIE') != -1) {
                isIE = true;
            }
            return new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            isIE = true;
            return new ActiveXObject("Microsoft.XMLHTTP");
        }
    }

    O código acima executa um verificação simples de compatibilidade do browser para o Firefox 3 e para o Internet Explorer versões 6 e 7). Se desejar incorporar um código mais robusto para problemas de compatibilidade, considere usar este script de detecção de browser disponível em http://www.quirksmode.org.

  4. Volte para a página do índice e adicione uma referência ao arquivo JavaScript entre as tags <head>.
    <script type="text/javascript" src="javascript.js"></script>

    Você pode alternar rapidamente entre as páginas abertas no Editor de Código-fonte, pressionando Ctrl-Tab.

  5. Insira uma chamada a init() na tag de abertura <body>.
    <body onload="init()">
    Isso garante que init() seja chamada toda vez que a página for carregada.

A atribuição de doCompletion() é:

  • criar um URL que contenha dados que possam ser utilizados pelo lado do servidor,
  • inicializar um objeto XMLHttpRequest, e
  • solicitar que o objeto XMLHttpRequest envie uma solicitação assíncrona para o servidor.

O objeto XMLHttpRequest é o núcleo do Ajax e se tornou o padrão de fato para permitir que dados XML sejam passados assincronamente por HTTP. A interação Assíncrona implica que o browser pode continuar a processar eventos na página depois que a requisição tiver sido enviada. Os dados são passados em segundo plano, e podem ser carregados automaticamente na página sem exigir uma atualização da página.

Observe que o objeto XMLHttpRequest é realmente criado por initRequest(), que é chamada por doCompletion(). A função verifica se XMLHttpRequest pode ser entendido pelo browser e, se for o caso, cria um objeto XMLHttpRequest. Caso contrário, ela executa uma verificação em ActiveXObject (o XMLHttpRequest equivalente do Internet Explorer 6) e cria um ActiveXObject, se identificado.

Três parâmetros são especificados quando você cria um objeto XMLHttpRequest: um URL, o método HTTP (GET ou POST), e se a interação é assíncrona ou não. No exemplo acima, os parâmetros são:

  • O URL autocomplete, e o texto digitado no complete-field pelo usuário:
    var url = "autocomplete?action=complete&id=" + escape(completeField.value);
  • GET, significando que as interações HTTP usam o método GET, e
  • true, significando que a interação é assíncrona:
    req.open("GET", url, true);

Se a interação for definida como assíncrona, uma função de chamada de retorno deve ser especificada. A função de chamada de retorno dessa interação é definida com a instrução:

req.onreadystatechange = callback;

e uma função callback() deve ser definida mais tarde. A interação HTTP começa quando XMLHttpRequest.send() é chamada. Essa ação mapeia para a solicitação HTTP que é enviada para o servidor web no fluxograma acima.


Programando o Lado do Servidor

O IDE oferece suporte abrangente para programação Web do lado do servidor. Embora isso inclua o suporte a editor básico para muitas linguagens de programação e de script populares, também inclui Web services, tais como SOAP, REST, SaaS e frameworks orientados a MVC, como JSF, Spring e Struts. Diversos plug-ins do NetBeans estão disponíveis no Portal de Plug-In do NetBeans para frameworks orientados para Ajax, como GWT e Struts2.

A lógica de negócios da aplicação processa as solicitações, recuperando dados do armazenamento de dados e, em seguida, preparando e enviando a resposta. Isso é implementado aqui por meio de um servlet. Antes de começar a codificar o servlet, configure o armazenamento de dados e a funcionalidade necessários pelo servlet para acessar os dados.

Criando o Armazenamento de Dados

Para essa aplicação simples, você cria uma classe nomeada ComposerData que mantém os dados do composer utilizando um HashMap. Um HashMap permite armazenar pares de itens vinculados em pares chave-valor. Você também pode criar uma classe Composer que permita ao servlet recuperar dados de entradas no HashMap.

  1. Clique com o botão direito do mouse no nó do projeto na janela Projetos e selecione Novo > Classe Java.
  2. Nomeie a classe ComposerData e digite com.ajax no campo Pacote. Isso cria um novo pacote que contém a classe, assim como outras classes que serão criadas mais tarde.
  3. Clique em Finalizar. A classe será criada e aberta no Editor de Código-fonte.
  4. No Editor de Código-fonte, cole o seguinte código:
    package com.ajax;
    
    import java.util.HashMap;
    
    /**
     *
     * @author nbuser
     */
    public class ComposerData {
    
        private HashMap composers = new HashMap();
    
        public HashMap getComposers() {
            return composers;
        }
    
        public ComposerData() {
    
            composers.put("1", new Composer("1", "Johann Sebastian", "Bach", "Baroque"));
            composers.put("2", new Composer("2", "Arcangelo", "Corelli", "Baroque"));
            composers.put("3", new Composer("3", "George Frideric", "Handel", "Baroque"));
            composers.put("4", new Composer("4", "Henry", "Purcell", "Baroque"));
            composers.put("5", new Composer("5", "Jean-Philippe", "Rameau", "Baroque"));
            composers.put("6", new Composer("6", "Domenico", "Scarlatti", "Baroque"));
            composers.put("7", new Composer("7", "Antonio", "Vivaldi", "Baroque"));
    
            composers.put("8", new Composer("8", "Ludwig van", "Beethoven", "Classical"));
            composers.put("9", new Composer("9", "Johannes", "Brahms", "Classical"));
            composers.put("10", new Composer("10", "Francesco", "Cavalli", "Classical"));
            composers.put("11", new Composer("11", "Fryderyk Franciszek", "Chopin", "Classical"));
            composers.put("12", new Composer("12", "Antonin", "Dvorak", "Classical"));
            composers.put("13", new Composer("13", "Franz Joseph", "Haydn", "Classical"));
            composers.put("14", new Composer("14", "Gustav", "Mahler", "Classical"));
            composers.put("15", new Composer("15", "Wolfgang Amadeus", "Mozart", "Classical"));
            composers.put("16", new Composer("16", "Johann", "Pachelbel", "Classical"));
            composers.put("17", new Composer("17", "Gioachino", "Rossini", "Classical"));
            composers.put("18", new Composer("18", "Dmitry", "Shostakovich", "Classical"));
            composers.put("19", new Composer("19", "Richard", "Wagner", "Classical"));
    
            composers.put("20", new Composer("20", "Louis-Hector", "Berlioz", "Romantic"));
            composers.put("21", new Composer("21", "Georges", "Bizet", "Romantic"));
            composers.put("22", new Composer("22", "Cesar", "Cui", "Romantic"));
            composers.put("23", new Composer("23", "Claude", "Debussy", "Romantic"));
            composers.put("24", new Composer("24", "Edward", "Elgar", "Romantic"));
            composers.put("25", new Composer("25", "Gabriel", "Faure", "Romantic"));
            composers.put("26", new Composer("26", "Cesar", "Franck", "Romantic"));
            composers.put("27", new Composer("27", "Edvard", "Grieg", "Romantic"));
            composers.put("28", new Composer("28", "Nikolay", "Rimsky-Korsakov", "Romantic"));
            composers.put("29", new Composer("29", "Franz Joseph", "Liszt", "Romantic"));
    
            composers.put("30", new Composer("30", "Felix", "Mendelssohn", "Romantic"));
            composers.put("31", new Composer("31", "Giacomo", "Puccini", "Romantic"));
            composers.put("32", new Composer("32", "Sergei", "Rachmaninoff", "Romantic"));
            composers.put("33", new Composer("33", "Camille", "Saint-Saens", "Romantic"));
            composers.put("34", new Composer("34", "Franz", "Schubert", "Romantic"));
            composers.put("35", new Composer("35", "Robert", "Schumann", "Romantic"));
            composers.put("36", new Composer("36", "Jean", "Sibelius", "Romantic"));
            composers.put("37", new Composer("37", "Bedrich", "Smetana", "Romantic"));
            composers.put("38", new Composer("38", "Richard", "Strauss", "Romantic"));
            composers.put("39", new Composer("39", "Pyotr Il'yich", "Tchaikovsky", "Romantic"));
            composers.put("40", new Composer("40", "Guiseppe", "Verdi", "Romantic"));
    
            composers.put("41", new Composer("41", "Bela", "Bartok", "Post-Romantic"));
            composers.put("42", new Composer("42", "Leonard", "Bernstein", "Post-Romantic"));
            composers.put("43", new Composer("43", "Benjamin", "Britten", "Post-Romantic"));
            composers.put("44", new Composer("44", "John", "Cage", "Post-Romantic"));
            composers.put("45", new Composer("45", "Aaron", "Copland", "Post-Romantic"));
            composers.put("46", new Composer("46", "George", "Gershwin", "Post-Romantic"));
            composers.put("47", new Composer("47", "Sergey", "Prokofiev", "Post-Romantic"));
            composers.put("48", new Composer("48", "Maurice", "Ravel", "Post-Romantic"));
            composers.put("49", new Composer("49", "Igor", "Stravinsky", "Post-Romantic"));
            composers.put("50", new Composer("50", "Carl", "Orff", "Post-Romantic"));
    
        }
    }

Você observará que uma advertência será exibida na margem esquerda do editor porque a classe Composer não pode ser encontrada. Execute as etapas a seguir para criar a classe Composer.

  1. Clique com o botão direito do mouse no nó do projeto na janela Projetos e selecione Novo > Classe Java.
  2. Nomeie a classe Composer e selecione com.ajax na lista drop-down no campo Pacote. Clique em Finalizar.

    Quando você clica em Finalizar, o IDE cria a classe e abre o arquivo no Editor de Código-fonte.

  3. No Editor de Código-fonte, cole o seguinte código:
    package com.ajax;
    
    public class Composer {
    
        private String id;
        private String firstName;
        private String lastName;
        private String category;
    
        public Composer (String id, String firstName, String lastName, String category) {
            this.id = id;
            this.firstName = firstName;
            this.lastName = lastName;
            this.category = category;
        }
    
        public String getCategory() {
            return category;
        }
    
        public String getId() {
            return id;
        }
    
        public String getFirstName() {
            return firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    }

Depois que você cria a classe Composer, se você observar a classe ComposerData no editor, poderá ver que as anotações de advertência não existem mais. Se ainda você vir as anotações de advertência no ComposerData você pode tentar resolver o erro adicionando as instruções de importação ausentes.

Criando um Servlet

Crie um servlet para tratar o URL autocomplete que é recebido pela solicitação de entrada.

  1. Clique com o botão direito do mouse no nó do projeto na janela Projetos e escolha Novo > Servlet para abrir o assistente para Novo Servlet. (Escolha Outros e selecione Servlet na categoria da Web se Servlet não for exibido por default no menu pop-up).
  2. Nomeie o servlet AutoCompleteServlet e selecione com.ajax na lista drop-down no campo Pacote. Clique em Próximo.
    Assistente Novo Servlet, painel Nome e Localização concluído
  3. No painel Configurar a Implantação do Servlet, altere o padrão do URL para /autocomplete para que ele corresponda ao URL que foi definido anteriormente no objeto XMLHttpRequest.
    Assistente Novo Servlet, painel Configurar Implantação do Servlet concluído

    Esse painel elimina a necessidade de adicionar manualmente esses detalhes no descritor de implantação.

  4. como opção, selecione "Adicionar informações do servlet ao descritor da implantação". Isso faz com que seu projeto seja o mesmo da amostra da qual fez download. Com versões posteriores do IDE, por default o servlet é registrado por uma anotação @WebServlet, em vez de um descritor da implantação. O projeto ainda funcionará se você usar a anotação @WebServlet, em vez de um descritor de implantação.
  5. Clique em Finalizar. O servlet será criado e aberto no Editor de Código-fonte.

Os únicos métodos que você precisa substituir são doGet(), para definir como o servlet trataa solicitação autocomplete GET, e init(), que precisa iniciar um ServletContext de forma que o servlet possa acessar outras classes na aplicação, depois de ter sido posto em serviço.

Você pode substituir métodos de superclasses usando o menu pop-up Inserir Código do IDE. Implemente init() executando as etapas a seguir.

  1. Coloque o seu cursor embaixo da declaração de classe AutoCompleteServlet no Editor de Código-fonte. Pressione Alt-Insert (Ctrl-I no Mac) para abrir o menu pop-up Gerar Código.
    Menu pop-up Inserir Código exibido no Editor de Código-fonte
  2. Selecione Substituir Método. Na caixa de diálogo que é exibida, todas as classes que AutoCompleteServlet herda são exibidas. Expanda o nó GenericServlet e selecione init(Servlet Config config).
    A caixa de diálogo Substituir listando classes herdadas
  3. Clique em OK. O método init() é adicionado no Editor de Código-fonte.
  4. Adicione uma variável para um objeto ServletContext e modifique init() (alterações em negrito):
    private ServletContext context;
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.context = config.getServletContext();
    }
  5. Adicione uma instrução de importação para ServletContext. Você pode fazer isso clicando no ícone da lâmpada exibido na margem esquerda do Editor de Código-fonte
    Dica de importação exibida na margem esquerda do Editor de Código-fonte

O método doGet() precisa fazer parsing do URL da solicitação, recuperar dados do armazenamento de dados e preparar uma resposta em formato XML. Note que a declaração do método foi gerada quando você criou a classe. Para exibi-la, pode ser necessário expandir métodos HttpServlet clicando no ícone de expansão (ícone de expansão) na margem esquerda.

  1. Adicione as declarações de variável a seguir embaixo da declaração da classe AutocompleteServlet.
    private ComposerData compData = new ComposerData();
    private HashMap composers = compData.getComposers();
    Isso cria um HashMap de todos os dados do composer, que é, em seguida, utilizado por doGet().
  2. Role para baixo para doGet() e implemente o método da seguinte forma:
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
    
        String action = request.getParameter("action");
        String targetId = request.getParameter("id");
        StringBuffer sb = new StringBuffer();
    
        if (targetId != null) {
            targetId = targetId.trim().toLowerCase();
        } else {
            context.getRequestDispatcher("/error.jsp").forward(request, response);
        }
    
        boolean namesAdded = false;
        if (action.equals("complete")) {
    
            // check if user sent empty string
            if (!targetId.equals("")) {
    
                Iterator it = composers.keySet().iterator();
    
                while (it.hasNext()) {
                    String id = (String) it.next();
                    Composer composer = (Composer) composers.get(id);
    
                    if ( // targetId matches first name
                         composer.getFirstName().toLowerCase().startsWith(targetId) ||
                         // targetId matches last name
                         composer.getLastName().toLowerCase().startsWith(targetId) ||
                         // targetId matches full name
                         composer.getFirstName().toLowerCase().concat(" ")
                            .concat(composer.getLastName().toLowerCase()).startsWith(targetId)) {
    
                        sb.append("<composer>");
                        sb.append("<id>" + composer.getId() + "</id>");
                        sb.append("<firstName>" + composer.getFirstName() + "</firstName>");
                        sb.append("<lastName>" + composer.getLastName() + "</lastName>");
                        sb.append("</composer>");
                        namesAdded = true;
                    }
                }
            }
    
            if (namesAdded) {
                response.setContentType("text/xml");
                response.setHeader("Cache-Control", "no-cache");
                response.getWriter().write("<composers>" + sb.toString() + "</composers>");
            } else {
                //nothing to show
                response.setStatus(HttpServletResponse.SC_NO_CONTENT);
            }
        }
        if (action.equals("lookup")) {
    
            // put the target composer in the request scope to display 
            if ((targetId != null) && composers.containsKey(targetId.trim())) {
                request.setAttribute("composer", composers.get(targetId));
                context.getRequestDispatcher("/composer.jsp").forward(request, response);
            }
        }
    }

Como pode ver neste servlet, não há nada exatamente novo que você precise aprender para escrever código do lado do servidor para processamento Ajax. O tipo de conteúdo da resposta precisa ser definido como text/xml para casos em que você deseje trocar documentos XML. Com o Ajax você também pode trocar texto simples ou até mesmo snippets de JavaScript, que podem ser avaliados ou executados pela função chamada de retorno no cliente. Observe também que alguns browsers podem armazenar no cache os resultados; portanto, talvez seja necessário definir o cabeçalho Cache-Control HTTP como no-cache.

Nesse exemplo, o servlet gera um documento XML que contém todos os composers com nome ou sobrenome começando com os caracteres digitados pelo usuário. Este documento mapeia para os dados XML ilustrados no fluxograma acima. Aqui está um exemplo de um documento XML que é retornado para o objeto XMLHttpRequest:

<composers>
    <composer>
        <id>12</id>
        <firstName>Antonin</firstName>
        <lastName>Dvorak</lastName>
    </composer>
    <composer>
        <id>45</id>
        <firstName>Aaron</firstName>
        <lastName>Copland</lastName>
    </composer>
    <composer>
        <id>7</id>
        <firstName>Antonio</firstName>
        <lastName>Vivaldi</lastName>
    </composer>
    <composer>
        <id>2</id>
        <firstName>Arcangelo</firstName>
        <lastName>Corelli</lastName>
    </composer>
</composers>

Você pode utilizar o Monitor HTTP do IDE para exibir os dados XML retornados ao concluir a aplicação.

Programando o Lado do Cliente: Parte 2

Você deve definir a função de chamada de retorno para tratar a resposta do servidor, e adicionar qualquer funcionalidade necessária para refletir alterações na página exibida pelo usuário. Isso requer a modificação do HTML DOM. Você precisa criar páginas JSP para exibir os resultados de uma solicitação bem-sucedida ou as mensagens de erro de uma solicitação com falha. Em seguida, é possível criar uma folha de estilo simples para a apresentação.

Adicionando a Funcionalidade de Retorno de Chamada

A função de retorno de chamada é chamada assincronamente em pontos específicos durante a interação HTTP quando a propriedade readyState do objeto XMLHttpRequest é alterada. Na aplicação que está sendo construída, a função chamada de retorno é callback(). Você lembra que em doCompletion(), callback foi definido como a propriedade XMLHttpRequest.onreadystatechange para uma função. Agora, implemente a função de retorno de chamada da seguinte forma.

  1. Abra javascript.js no Editor de Código-fonte e digite o código abaixo.
    function callback() {
        if (req.readyState == 4) {
            if (req.status == 200) {
                parseMessages(req.responseXML);
            }
        }
    }

Um readyState de "4" significa a conclusão da interação HTTP. A API de XMLHttpRequest.readState indica que há 5 valores possíveis que podem ser definidos. São elas:

Valor readyState Definição do Status do Objeto
0 não inicializado
1 carregando
2 carregado
3 interativo
4 completo

Observe que a função parseMessages() somente é chamada quando o XMLHttpRequest.readyState é "4" e o status (a definição do código de status HTTP da solicitação) é "200", significando êxito. Você definirá parseMessages() em seguida em Atualizando o HTML DOM.

Atualizando o HTML DOM

A função parseMessages() trata os dados XML de entrada. Fazendo isso, ela conta com várias funções auxiliares, como appendComposer(), getElementY() e clearTable(). Você também deve introduzir novos elementos na página de índice, como uma segunda tabela HTML que serve como a caixa autocompletar, e os IDs dos elementos, para que eles possam ser referenciados em javascript.js. Finalmente, crie novas variáveis que correspondam aos IDs para os elementos na página do índice, inicialize-as na função init() implementada anteriormente e adicione alguma funcionalidade que seja necessária sempre que a página do índice for carregada.

Observação: As funções e elementos que você cria nas etapas seguintes funcionam de forma interdependente. Recomendamos que você percorra esta seção e, em seguida, examine o código quando tudo estiver no lugar.

  1. Abra a página do índice no Editor de Código-fonte e digite o código abaixo para a segunda linha da tabela HTML que você criou anteriormente.
    <tr>
        <td id="auto-row" colspan="2">
            <table id="complete-table" />
        </td>
    </tr>
    A segunda linha da tabela contém outra tabela HTML. Essa tabela representa a caixa autocompletar que será utilizada para preencher os nomes do composer.
  2. Abra javascript.js no Editor de Código-fonte e as três variáveis seguintes no início do arquivo.
    var completeField;
    var completeTable;
    var autoRow;
  3. Adicione as seguintes linhas (em negrito) na função init().
    function init() {
        completeField = document.getElementById("complete-field");
        completeTable = document.getElementById("complete-table");
        autoRow = document.getElementById("auto-row");
        completeTable.style.top = getElementY(autoRow) + "px";
    }
    Uma finalidade de init() é tornar os elementos que estão dentro da página de índice acessíveis para outras funções que modificarão o DOM da página de índice.
  4. Adicione appendComposer() a javascript.js.
    function appendComposer(firstName,lastName,composerId) {
    
        var row;
        var cell;
        var linkElement;
    
        if (isIE) {
            completeTable.style.display = 'block';
            row = completeTable.insertRow(completeTable.rows.length);
            cell = row.insertCell(0);
        } else {
            completeTable.style.display = 'table';
            row = document.createElement("tr");
            cell = document.createElement("td");
            row.appendChild(cell);
            completeTable.appendChild(row);
        }
    
        cell.className = "popupCell";
    
        linkElement = document.createElement("a");
        linkElement.className = "popupItem";
        linkElement.setAttribute("href", "autocomplete?action=lookup&id=" + composerId);
        linkElement.appendChild(document.createTextNode(firstName + " " + lastName));
        cell.appendChild(linkElement);
    }
    Essa função cria uma nova linha da tabela, insere um link em um criador utilizando os dados passados para a função por meio de seus três parâmetros e insere a linha no elemento complete-table da página de índice.
  5. Adicione getElementY() a javascript.js.
    function getElementY(element){
    
        var targetTop = 0;
    
        if (element.offsetParent) {
            while (element.offsetParent) {
                targetTop += element.offsetTop;
                element = element.offsetParent;
            }
        } else if (element.y) {
            targetTop += element.y;
        }
        return targetTop;
    }
    Essa função é aplicada para localizar a posição vertical do elemento pai. Isso é necessário porque a posição real do elemento, quando ele é exibido, frequentemente depende do tipo e da versão do browser. Note que o elemento complete-table, quando é exibido contendo nomes de criador, é deslocado para o lado direito inferior da tabela em que ele está. O posicionamento correto da altura é determinado por getElementY().

    Observação: Consulte esta explicação de offset em http://www.quirksmode.org/.

  6. Adicione clearTable() a javascript.js.
    function clearTable() {
        if (completeTable.getElementsByTagName("tr").length > 0) {
            completeTable.style.display = 'none';
            for (loop = completeTable.childNodes.length -1; loop >= 0 ; loop--) {
                completeTable.removeChild(completeTable.childNodes[loop]);
            }
        }
    }
    Essa função define a exibição do elemento complete-table como "none" (ou seja, o torna invisível) e remove quaisquer entradas de nome de criador existentes que tenham sido criadas.
  7. Modifique a função callback() para que chame clearTable() cada vez que novos dados forem recebidos do servidor. Quaisquer entradas do criador que já existam na caixa autocompletar serão, portanto, removidas, antes que esta seja preenchida com novas entradas.
    function callback() {
    
        clearTable();
    
        if (req.readyState == 4) {
            if (req.status == 200) {
                parseMessages(req.responseXML);
            }
        }
    }
  8. Adicione parseMessages() a javascript.js.
    function parseMessages(responseXML) {
    
        // no matches returned
        if (responseXML == null) {
            return false;
        } else {
    
            var composers = responseXML.getElementsByTagName("composers")[0];
    
            if (composers.childNodes.length > 0) {
                completeTable.setAttribute("bordercolor", "black");
                completeTable.setAttribute("border", "1");
    
                for (loop = 0; loop < composers.childNodes.length; loop++) {
                    var composer = composers.childNodes[loop];
                    var firstName = composer.getElementsByTagName("firstName")[0];
                    var lastName = composer.getElementsByTagName("lastName")[0];
                    var composerId = composer.getElementsByTagName("id")[0];
                    appendComposer(firstName.childNodes[0].nodeValue,
                        lastName.childNodes[0].nodeValue,
                        composerId.childNodes[0].nodeValue);
                }
            }
        }
    }

A função parseMessages() recebe como parâmetro uma representação de objeto do documento XML retornado pelo servlet AutoComplete. A função percorre programaticamente o documento XML, extraindo firstName, lastName e id de cada entrada e, em seguida, ela passa esses dados para appendComposer(). Isso resulta em uma atualização dinâmica do conteúdo do elemento complete-table. Por exemplo, uma entrada que é gerada e inserida em complete-table deve ter a seguinte aparência:

<tr>
    <td class="popupCell">
        <a class="popupItem" href="autocomplete?action=lookup&id=12">Antonin Dvorak</a>
    </td>
</tr>

A atualização dinâmica do elemento complete-table representa a etapa final do fluxo do processo de comunicação que acontece durante a comunicação por meio do Ajax. Essa atualização mapeia para os dados HTML e CSS sendo enviados para a apresentação no fluxograma acima.

Exibindo os Resultados

Para exibir os resultados, você precisa de um arquivo JSP chamado composers.jsp. Esta página é chamada a partir do AutoCompleteServlet durante uma ação de busca. Você também precisa de um arquivo error.jsp, que é chamado a partir do AutoCompleteServlet se o composer não puder ser encontrado.

Para exibir resultados e erros:

  1. Na janela Projetos, clique com o botão direito do mouse na pasta Páginas Web e selecione Novo > JSP. O assistente Novo JSP será aberto.
  2. No campo Nome do Arquivo, digite composer. No campo Arquivo Criado, você verá um caminho que termina em /web/composer.jsp.
  3. Clique em Finalizar. O arquivo composer.jsp será aberto no editor. Aparecerá um nó para o arquivo na janela Projetos na pasta Páginas Web.
  4. Substitua o código do placeholder no composer.jsp pelo seguinte código:
    <html>
      <head>
        <title>Composer Information</title>
    
        <link rel="stylesheet" type="text/css" href="stylesheet.css">
      </head>
      <body>
    
        <table>
          <tr>
            <th colspan="2">Composer Information</th>
          </tr>
          <tr>
            <td>First Name: </td>
            <td>${requestScope.composer.firstName}</td>
          </tr>
          <tr>
            <td>Last Name: </td>
            <td>${requestScope.composer.lastName}</td>
          </tr>
          <tr>
            <td>ID: </td>
            <td>${requestScope.composer.id}</td>
          </tr>
          <tr>
            <td>Category: </td>
            <td>${requestScope.composer.category}</td>
          </tr>      
        </table>
    
        <p>Go back to <a href="index.html" class="link">application home</a>.</p>
      </body>
    </html>

    Observação. Você precisará alterar o link para voltar à página de índice, se sua página de índice for index.jsp.

  5. Crie outro arquivo JSP na pasta Páginas Web do projeto. Nomeie o arquivo de error.jsp.
  6. Substitua o código do placeholder no error.jsp pelo seguinte código:
    <!DOCTYPE html>
    
    <html>
        <head>
            <link rel="stylesheet" type="text/css" href="stylesheet.css">      
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Seach Error</title>
        </head>
        <body>
            <h2>Seach Error</h2>
            
            <p>An error occurred while performing the search. Please try again.</p>
            
            <p>Go back to <a href="index.html" class="link">application home</a>.</p>
        </body>
    </html>

    Observação. Você precisará alterar o link para voltar à página de índice, se sua página de índice for index.jsp.

Anexando uma Folha de Estilo

Nesse estágio, você concluiu todo o código necessário para a funcionalidade da aplicação. Para ver os resultados dos seus esforços, tente executar a aplicação agora.

  1. Na janela Projetos, clique com o botão direito do mouse no nó do projeto e selecione Executar. O projeto será recompilado e implantado no servidor de destino. Seu browser será aberto e você poderá ver a página de índice.
    Aplicação exibida no browser sem folha de estilo

Para adicionar uma folha de estilo à sua aplicação, basta criar um arquivo .css e vinculá-lo a partir da(s) página(s) da sua apresentação. Quando você trabalha em arquivos .css, o IDE oferece o suporte para autocompletar código. assim como as seguintes janelas, para ajudá-lo a gerar e editar regras de folhas de estilo:

  • Janela Estilos de CSS. A janela Estilos de CSS permite editar as declarações de regras de elementos e seletores HTML em um arquivo CSS.
  • Caixa de diálogo Criar Regras CSS. A caixa de diálogo Criar Regras de CSS permite criar novas regras em uma folha de estilos de CSS.
  • Caixa de diálogo Adicionar Propriedade de CSS.A caixa de diálogo Adicionar Propriedade de CSS permite adicionar declarações a uma regra de CSS em uma folha de estilos, adicionando propriedades e valores.

Para adicionar uma folha de estilo à sua aplicação execute as etapas a seguir.

  1. Na janela Projetos, clique com o botão direito do mouse no nó Páginas Web e selecione Novo > Folha de Estilo em Cascata (caso Folha de Estilo em Cascata não esteja listado, selecione Outro. Em seguida, escolha Folha de Estilo em Cascata na categoria Web no assistente Novo arquivo.)
  2. No campo de texto Nome do Arquivo CSS, digite stylesheet. Clique em Finalizar.

    O movo arquivo será criado e aberto no editor.

  3. Digite as seguintes regras em stylesheet.css, no editor. Você pode utilizar o suporte à funcionalidade autocompletar código do IDE pressionando Ctrl-Espaço nos pontos em que desejar acionar sugestões.
    body {
       font-family: Verdana, Arial, sans-serif;
       font-size: smaller;
       padding: 50px;
       color: #555;
       width: 650px;
    }
    
    h1 {
       letter-spacing: 6px;
       font-size: 1.6em;
       color: #be7429;
       font-weight: bold;
    }
    
    h2 {
       text-align: left;
       letter-spacing: 6px;
       font-size: 1.4em;
       color: #be7429;
       font-weight: normal;
       width: 450px;
    }
    
    table {
       width: 550px;
       padding: 10px;
       background-color: #c5e7e0;
    }
    
    td {
       padding: 10px;
    }
    
    a {
      color: #be7429;
      text-decoration: none;
    }
    
    a:hover {
      text-decoration: underline;
    }
    
    .popupBox {
      position: absolute;
      top: 170px;
      left: 140px;
    }
    
    .popupCell {
       background-color: #fffafa;
    }
    
    .popupCell:hover {
      background-color: #f5ebe9;
    }
    
    .popupItem {
      color: #333;
      text-decoration: none;
      font-size: 1.2em;
    }
  4. Abra a janela Estilos de CSS escolhendo Janela > Web > Estilos CSS.
    Janela Estilos de CSS exibindo as propriedades de regra h1

    Você pode usar a janela Estilos de CSS para exibir rapidamente as propriedades e editar as regras de estilo. Quando você seleciona uma regra no painel superior da janela Estilo de CSS, pode ver as propriedades da regra no painel inferior. Você pode adicionar uma Regra de CSS à folha de estilos clicando no ícone Editar Regras de CSS (Ícone Nova Propriedade de CSS) na barra de ferramentas do painel superior. Você pode modificar as regras no painel inferior, editando a folha de propriedades, e adicionar propriedades clicando no ícone Adicionar Propriedade (Ícone Nova Propriedade de CSS) na barra de ferramentas do painel inferior.

  5. Alterne para a página no Editor de Código-fonte, e adicione uma referência à folha de estilo entre as tags <head>.
    <link rel="stylesheet" type="text/css" href="stylesheet.css">
  6. Adicione a classe popupBox que está definida na folha de estilo ao elemento complete-table (alterações em negrito).
    <tr>
        <td id="auto-row" colspan="2">
            <table id="complete-table" class="popupBox" />
        </td>
    </tr>

    É possível usar o recurso autocompletar código no editor para ajudá-lo a selecionar a regra de estilo que você quer aplicar ao seletor.

    Recurso autocompletar código no editor

    Como indicado em stylesheet.css, esta regra posiciona o elemento complete-table para que seja exibido um pouco à direita de seu elemento pai.

Quando você salva a página de índice, a aplicação é automaticamente reimplantada no servidor. Se a página ainda estiver aberta no browser, você poderá recarregá-la para ver se ela agora é renderizada de acordo com as regras da folha de estilos de CSS.


Executando o Projeto

Quando você executar a aplicação novamente, ela será exibida no browser utilizando a folha de estilo que acabou de ser criada. Toda vez que você digita um caractere, uma solicitação assíncrona é enviada para o servidor e retornada com dados XML que foram preparados por AutoCompleteServlet. Conforme você digita mais caracteres, o número de nomes de criador diminui para refletir a nova lista de correspondências.

Utilizando o Monitor do Servidor HTTP

Você pode utilizar o monitor do Servidor HTTP do IDE para verificar a comunicação HTTP que acontece quando as solicitações e as respostas são passadas entre o cliente e o servidor. O Monitor do Servidor HTTP exibe informações como cabeçalhos do cliente e do servidor, propriedades da sessão, detalhes do cookie, assim como parâmetros de solicitação.

Antes de começar a utilizar o monitor HTTP, você deve primeiro ativá-lo no servidor que está utilizando.

  1. Abra a janela Servidores, selecionando Ferramentas > Servidores no menu principal.
  2. No painel esquerdo, selecione o servidor que está usando com o projeto. Em seguida, no painel direito, selecione a opção Ativar Monitor HTTP.

    Observação: essa opção é exibida na guia Comum do GlassFish Server. Para Tomcat, ela reside na guia Conexão.

  3. Clique em Fechar.

Se o servidor já estiver em execução, você precisará reiniciá-lo para permitir que as alterações tenham efeito. Você pode reiniciar o servidor, abrindo a janela Serviços (Janela > Serviços) e, em seguida, clicando com o botão direito do mouse no servidor embaixo do nó Servidores e selecionando Reiniciar.

Agora, quando você executar a aplicação novamente, o monitor HTTP será aberto na região inferior do IDE. Você pode selecionar um registro no painel esquerdo e, em seguida, clicar nas guias na janela principal para exibir as informações sobre cada solicitação que é feita.

O monitor do Servidor HTTP é exibido no IDE

Você pode verificar os dados XML que são enviados do servidor como resultado da solicitação assíncrona feita quando um usuário indica um caractere no campo autocompletar.

  1. Na view em árvore do lado esquerdo do monitor HTTP, clique com o botão direito do mouse no registro de uma solicitação e selecione Reexecutar.

A resposta será gerada em seu browser. Nesse caso, como a resposta consiste em dados XML, o browser exibirá os dados em seu visualizador XML nativo.

O monitor do Servidor HTTP é exibido no IDE

Conclusão

Isso conclui a Introdução ao Ajax. Esperamos que agora você saiba que o Ajax está simplesmente trocando informações por HTTP em segundo plano, e atualizando essa página dinamicamente, com base nos resultados.

Você talvez note que a aplicação que construiu tem vários problemas, como, por exemplo, nada acontece quando o nome de um criador é selecionado na caixa autocompletar! Você é bem-vindo a fazer download do projeto de solução para ver como isso pode ser implementado utilizando tecnologia JSP. Além disso, talvez queira investigar a validação do lado do servidor que impede que um usuário solicite um nome que não existe no armazenamento de dados. Você pode aprender mais sobre essas técnicas e tecnologias, seguindo outros tutoriais na Trilha de Aprendizado do Java Web e do Java EE.


Consulte Também

Para obter mais informações sobre a tecnologia Ajax e Java em netbeans.org, consulte os seguintes recursos:

get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo