corner imagecorner image
IDEPlatformPluginsDocs & SupportCommunityPartners
Tutorial do NetBeans E-commerce: Sessões de gerenciamento

Tutorial do NetBeans E-commerce: Sessões de gerenciamento

O conteúdo desta página se aplica ao NetBeans IDE, versões 6.8 e 6.9

Cada aplicativo e-commerce que oferece algum formulário da funcionalidade do carrinho de compras necessita estar habilitado a lembrar dados específicos do usuário conforme os usuários clicam no site. Infelizmente, o desenvolvedor, protocolo HTTP, sobre o qual a comunicação na Internet ocorre, é um protocolo sem declaração. Cada pedido recebido pelo servidor é uma peça de informação independente que não tem nenhuma relação com pedidos recebidos previamente. Portanto, se o cliente clicar em um botão para adicionar um item ao seu carrinho de compras, o aplicativo deve tomar medidas para assegurar não somente que o estado do carrinho do usuário esteja atualizado, mas que a ação não afeta o carrinho de outro usuário que pode estar navegando pelo site ao mesmo tempo.

A fim de manipular corretamente o cenário descrito acima, é necessário implementar uma funcionalidade de maneira que uma sessão possa ser criada e mantida durante toda a visita do usuário ao site. A tecnologia Servlet, que é a base de todos os aplicativos com base Java, fornece isso com sua interface HttpSession. É necessário também definir várias classes, chamadas ShoppingCart e ShoppingCartItem, que permitem ao aplicativo armazenar temporariamente dados de compra do usuário enquanto a sessão é mantida.

Esta unidade do tutorial utiliza uma abordagem diferente dos outros no Tutorial do NetBeans E-commerce. Ao invés de criar os arquivos de projeto e fornecer as etapas com fragmentos de código para copiar e colar no seu próprio projeto, você abre o instantâneo do projeto completo para essa unidade e examina o código utilizando o depurador IDE e outras ferramentas. No processo, será possível aprender como aplicar um objeto HttpSession ao seu código, de forma que cada visita ao site resulte em uma sessão dedicada. Você aprenderá também sobre variáveis de escopo, e seu uso em ambas as classes Java e páginas JSP. Esta unidade também discute o mecanismo padrão HttpSession para as sessões de manutenção (ex., cookies) e mostra que medidas devem ser tomadas no caso de os cookies estarem desativados no navegador do usuário. Finalmente, os tempos limite das sessões são cobertos e a unidade demonstra como manipulá-los criando um filtro simples que intercepta pedidos de verificação da existência da sessão.

É possível visualizar uma demonstração ao vivo do aplicativo construído neste tutorial:Aplicativo demonstrativo do Tutorial NetBeans E-commerce.



Software ou recurso Versão necessária
NetBeans IDE Pacote Java, 6.8 ou 6.9
Java Development Kit (JDK) versão 6
Servidor GlassFish v3 ou Open Source Edition 3.0.1
Servidor de banco de dados MySQL versão 5.1
Projeto AffableBean instantâneo 5

Notas:

  • O NetBeans IDE exige que o Java Development Kit (JDK) seja executado corretamente. Se você não possui nenhum dos recursos listados acima, o JDK deve ser o primeiro item a ser baixado e instalado.
  • O NetBeans IDE Java Bundle inclui o Java Web e as tecnologias EE, necessárias para o aplicativo construído neste tutorial.
  • O NetBeans IDE Java Bundle inclui também servidor GlassFish, necessário neste tutorial. É possível baixar o Servidor GlassFish independentemente, mas a versão fornecida com o download do NetBeans possui o benefício adicionado de ser automaticamente registrado com o IDE.
  • É possível seguir esta unidade do tutorial sem ter completado as unidades anteriores. Para fazê-lo, consulte as instruções de configuração, que descrevem como preparar o banco de dados e estabelecer uma conectividade entre o IDE, o GlassFish e o MySQL.

Manipulando dados de sessão

Os aplicativos podem gerenciar sessões de usuário com o objeto HttpSession. É possível vincular dados específicos do usuário específico ao objeto HttpSession e, em seguida, acessar estes dados em um estágio mais avançado. Ambas as ações de vincular e acessar podem ser feitas a partir das classe Java, assim como a partir de variáveis de sessões de escopo nas expressões EL.

Trabalhando com um objeto HttpSession

O aplicativo AffableBean utiliza o objeto HttpSession para identificar usuários entre várias solicitações. Um objeto HttpSession é obtido utilizando getSession() em uma requisição fornecida:

HttpSession session = request.getSession();

Se ainda não existe um objeto de sessão para a requisição, o método cria e retorna um novo objeto de sessão.

É possível utilizar o objeto de sessão como um veículo para a transferência de dados entre as solicitações. É possível utilizar o método setAttribute para vincular objetos à sessão. Da mesma forma, é possível utilizar o método getAttribute para recuperar objetos da sessão. No aplicativo AffableBean, por exemplo, o carrinho de compras do usuário é criado e vinculado à sessão do usuário da seguinte forma:

ShoppingCart cart = new ShoppingCart();
session.setAttribute("cart", cart);

Para recuperar o carrinho da sessão, o método getAttibute é aplicado:

cart = (ShoppingCart) session.getAttribute("cart");

Nas páginas JSP, é possível acessar objetos vinculados à sessão utilizando expressões EL. Continuando com o exemplo acima, se um objeto ShoppingCart chamado "cart" estiver vinculado à sessão, é possível acessá-lo utilizando a seguinte expressão EL:

${cart}

No entanto, acessar o objeto ShoppingCart em si tem pouco valor. O que você realmente quer é um jeito de acessar valores armazenados no objeto. Se explorar a nova classe ShoppingCart no instantâneo do projeto, notará que este contém as seguintes propriedades:

  • double total
  • int numberOfItems
  • List<String, ShoppingCartItem> items

Desde que as propriedades possuam métodos getter correspondentes, é possível acessar valores a partir de propriedades singulares utilizando uma simples notação de ponto em uma expressão EL. Se observar a página cart.jsp, verá que esta é a maneira exata como o valor para numberOfItems é acessado:

<p>Your shopping cart contains ${cart.numberOfItems} items.</p>

A fim de extrair dados de propriedades contendo valores múltiplos, tal como a lista items acima, a página cart.jsp utiliza um loop <c:forEach:

<c:forEach var="cartItem" items="${cart.items}" varStatus="iter">

  <c:set var="product" value="${cartItem.product}"/>

    <tr class="${((iter.index % 2) == 0) ? 'lightBlue' : 'white'}">
        <td>
            <img src="${initParam.productImagePath}${product.name}.png"
                 alt="${product.name}">
        </td>

        <td>${product.name}</td>

        <td>
            &euro; ${cartItem.total}
            <br>
            <span class="smallText">( &euro; ${product.price} / unit )</span>
        </td>
        ...
    </tr>

</c:forEach>

A propriedade do produto ShoppingCartItem identifica o tipo de item do carrinho. O loop acima tira vantagem disso definindo primeiramente uma variável produto para a expressão ${cartItem.product}. A seguir, ele utiliza a variável para obter informações sobre esse produto (ex., nome e preço).

Trabalhando com variáveis de escopos nos aplicativos da Web

Ao trabalhar com a tecnologia JSP/Servlet, há quatro objetos de escopo disponíveis dentro do território do aplicativo. A tecnologia JSP implementa objetos implícitos que permitem acessar classes definidas pelo Servlet API.

Escopo Definição Classe Servlet Objeto implícito JSP
Aplicativo Memória global para um aplicativo da web javax.servlet.ServletContext applicationScope
Sessão Dados específicos para uma sessão de usuário javax.servlet.http.HttpSession sessionScope
Requisição Dados específicos para uma requisição de servidor individual javax.servlet.HttpServletRequest requestScope
Página Dados que estão válidos somente no contexto de uma página simples (somente JSP) [n/a] pageScope

Se abrir o arquivo do projeto category.jsp no editor, verá que a expressão EL inclui diversas variáveis de escopo, incluindo ${categories}, ${selectedCategory} e ${categoryProducts}. A variável ${categories} é um aplicativo de escopo, definido no método init do ControllerServlet:

// lista da categoria de armazanamento no contexto servlet
getServletContext().setAttribute("categories", categoryFacade.findAll());

As outras duas, ${selectedCategory} e ${categoryProducts}, são inseridas no escopo da sessão do aplicativo a partir do ControllerServlet. Por exemplo:

// categoria selecionada colocada na sessão scope
session.setAttribute("selectedCategory", selectedCategory);

Observação: Se você estiver continuando a partir de unidades anteriores do tutorial, provavelmente notará que ${selectedCategory} e ${categoryProducts} foram originalmente colocados no escopo da solicitação. Em unidades anteriores, isso não era problema, mas considere agora o que acontece se um usuário clicar no botão 'adicionar ao carrinho' na página de uma categoria. O servidor responde a uma solicitção addToCart retornando a página de categoria em exibição no momento. Portanto, é preciso saber selectedCategory e categoryProducts relacionados à categoria selecionada. Em vez de estabelecer essas informações para cada solicitação, você a coloca no escopo da sessão de uma solicitação de categoria para que sejam mantidas entre várias solicitações e possam ser acessadas quando necessário. Além disso, examine a funcionalidade fornecida pela página do carrinho. (Uma descrição funcional é fornecida abaixo.) O botão 'continuar comprando' resulta no retorno do usuário à categoria exibida previamente. Novamente, as variáveis selectedCategory e categoryProducts são necessárias.

Ao fazer referência às variáveis do escopo na expressão EL, não é necessário especificar o escopo das variáveis (desde que você não possua duas variáveis com o mesmo nome em escopos diferentes). O mecanismo JSP verifica todos os escopos e retorna a primeira variável correspondente que encontrar. Em category.jsp por exemplo, a expressão:

${categoryProducts}

é uma abreviação para:

${sessionScope.categoryProducts}
Para mais informações, consulte os recursos a seguir:

Análise dos dados de sessão com o depurador Java

Comece explorando como o aplicativo se comporta durante o tempo de execução. Utilize o depurador IDE para avançar pelo código e examinar como a HttpSession é criada e como outros objetos podem ser colocados no escopo da sessão para serem recuperados em um ponto mais adiante.

  1. Abra o instantâneo do projeto para esta unidade do tutorial no IDE. Clique no botão Abrir Projeto ( botão Abrir projeto ) e utilize o assistente para navegar até a localização no seu computador, onde o projeto foi baixado. Se estiver prosseguindo de uma unidade de tutorial prévia, observe que este instantâneo do projeto inclui um novo pacote cart, contendo as classes ShoppingCart e ShoppingCartItem. E note também que os seguintes arquivos foram modificados:
    • WEB-INF/web.xml
    • css/affablebean.css
    • WEB-INF/jspf/header.jspf
    • WEB-INF/jspf/footer.jspf
    • WEB-INF/view/cart.jsp
    • WEB-INF/view/category.jsp
    • WEB-INF/view/checkout.jsp
    • controller/ControllerServlet
  2. Execute o projeto ( botão Executar projeto ) para certificar-se de que este esteja configurado corretamente com o banco de dados e o servidor do aplicativo.

    Se receber uma mensagem de erro ao executar o projeto, consulte novamente as instruções de configuração, que descrevem como preparar um banco de dados e estabelecer conectividade entre o IDE, o GlassFish e o MySQL.

  3. Teste a funcionalidade do aplicativo no navegador. Se estiver prosseguindo diretamente da unidade prévia do tutorial, notará as seguintes melhorias.

    página da categoria

    • Clicar em "adicionar ao carrinho" pela primeira vez ativa o carrinho de compras e os assistentes "avançar para check-out" para serem exibidos no cabeçalho.
    • Clicar em "adicionar ao carrinho" resulta em uma atualização no número de itens no carrinho no assistente do carrinho de compras no cabeçalho.
    • Clicar em "visualizar carrinho" resulta na exibição da página do carrinho.
    • Clicar em "avançar para saída" resulta na exibição da página de saída.
    Imagem do navegador da página da categoria

    página do carrinho

    • Clicar em "limpar carrinho" resulta no esvaziamento dos itens do carrinho de compras.
    • Clicar em "continuar comprando" resulta em um retorno à categoria exibida previamente.
    • Clicar em "avançar para saída" resulta na exibição da página de saída.
    • Inserir um número (1 - 99) no campo de quantidade de itens e, em seguida, clicar em "atualizar" resulta no recálculo do preço total para o item e do subtotal.
    • Inserir zero no campo quantidade e, em seguida, clicar em "atualizar" resulta na remoção do item da tabela de exibição.
    Imagem do navegador da página do carrinho

    página de retirada

    • Clicar em "visualizar carrinho" resulta na exibição da página do carrinho.
    • Clicar em "Submeter compra" resulta na página de exibição da confirmação (sem dados de usuário específico).
    Imagem do navegador da página de saída
  4. Utilize a caixa de diálogo Vá para o arquivo para abrir o ControllerServlet no editor. Pressione Alt-Shift-O (Ctrl-Shift-O no Mac), digite 'Controller' na caixa de diálogo e clique em OK.
    Caixa de diálogo Vá para o arquivo
  5. Defina um ponto de interrupção no método doPost na linha que cria um objeto HttpSession (linha 150). Para definir um ponto de interrupção, clique na margem esquerda do editor.
    Ponto de interrupção definido no editor

    Para alternar números de linhas para o editor, clique com o botão direito do mouse na margem esquerda e selecione Exibir número de linhas.

  6. Execute o depurador. Clique no botão Depurar projeto (botão Depurar projeto) na barra de ferramentas principal do IDE. O servidor GlassFish é iniciado (ou reiniciado, se já estiver sendo executado) e abre um soquete no número da porta de depuração. A página de boas vindas do aplicativo é aberta no navegador.

    É possível visualizar e modificar o depurador de números de portas a partir da janela Servidores (Ferramentas > Servidores). Selecione a aba Java para o servidor que esteja utilizando. Especifique o número da porta no campo 'Endereço a ser utilizado' em Configurações de depuração.

  7. Quando aparecer no navegador a página de boas vindas do aplicativo, clique em qualquer imagem da categoria para navegar pela página da categoria. Lembre-se de que ao clicar no botão "adicionar ao carrinho" um pedido addToCart será enviado ao servidor:
    <form action="addToCart" method="post">
    Como você se lembra de Preparando sa exibições de página e o servlet do controlador, o método doPost de ControllerServlet trata solicitações para o padrão de URL /addToCart. Portanto, é possível esperar que quando um usuário clica no botão "adicionar ao carrinho" o método doPost é chamado.
  8. Clique em "adicionar ao carrinho" para qualquer produto na página Categoria. Volte para o IDE e note que o depurador é suspenso no ponto de interrupção.
    Depurador suspenso no ponto de interrupção
  9. Posicione o cursor na chamada para getSession() e pressione Ctrl-Espaço para invocar a documentação Javadoc.
    A documentação Javadoc é exibida no editor
    De acordo com a documentação, a getSession() retorna a HttpSession atualmente associada com o pedido e, caso não exista nenhuma sessão, o método cria um novo objeto de sessão.

  10. Passe o mouse sobre a variável de sessão. Observe que o depurador é suspenso na linha está para ser executado. O valor retornado pela getSession() ainda não foi salvo na variável da sessão e é possível ver um pop-up informando que " Asessão não é uma variável conhecida no contexto atual."
    O pop-up do depurador é exibido no editor
  11. Clique no botão Passar sobre ( botão Passar sobre ) na barra de ferramentas do depurador, localizada acima do editor. A linha é executada e o depurador passa para a próxima linha no arquivo.
  12. Passe novamente o mouse sobre a variável da sessão. Agora você pode ver o valor atual definido para a variável da session.
    O pop-up do depurador é exibido no editor

    No NetBeans 6.9, é possível clicar no ponteiro cinza ( botão Passar sobre ) no pop-up para expandir uma lista de valores de variáveis contidos no elemento realçado.

  13. Clique no botão Passar sobre ( botão Passar sobre) (F8, fn-F8 no Mac) até chegar à declaração if (linha 154). Como você acabou de clicar no botão "adicionar ao carrinho" no navegador, deve estar ciente de que a expressão userPath.equals("/addToCart) deve ser avaliada como verdadeira.
  14. Realce a expressão userPath.equals("/addToCart") (clicando com o mouse). Agora é possível ver um pop-up indicando o valor da expressão que foi realçada.
    Expressão avaliada exibida no pop-up
  15. Pressione F8 (fn-F8 no Mac) para passar à próxima linha (linha 158). O aplicativo foi projetado de maneira que o objeto ShoppingCart para a sessão do usuário seja criado somente quando o usuário adicionar um item ao carrinho pela primeira vez. Já que esta é a primeira vez que a requisição addToCart foi recebida nesta sessão de depuração, pode-se esperar que o objeto carrinho seja igual a nulo.
    Expressão avaliada exibida no pop-up
  16. Pressione F8 (fn-F8 no Mac) para passar à próxima linha (linha 160). Em seguida, na linha 160, onde o objeto ShoppingCart é criado, clique no botão Passar dentro ( botão Passar dentro ). O depurador passa dentro do método que está sendo chamado. Neste caso, você será levado diretamente ao construtor do ShoppingCart.
    Expressão avaliada exibida no pop-up
  17. Pressione Ctrl-Tab para voltar ao ControllerServlet. Observe que o IDE fornece uma identificação Pilha de chamadas (identificação Pilha de chamadas ) na linha 160, indicando que, no momento, o depurador está suspenso em algum lugar, em um método mais elevado que a pilha de chamada.

    Pressione Alt-Shift-3 (Ctrl-Shift-3 no Mac) para abrir a janela Pilha de chamada do IDE.

  18. Pressione F8 (fn-F8 no Mac) para continuar avançando pelo código. Quando o depurador completa o construtor ShoppingCart, você é levado de volta ao ControllerServlet.

    A linha 161 do ControllerServlet vincula o objeto recém criado cart à sessão.
    session.setAttribute("cart", cart);
    Para testemunhar isso, abra a janela Variáveis do depurador. Escolha Variáveis do depurador (Escolha Janela > Depurando > Variáveis ou pressione Alt-Shift-1 (Ctrl-Shift-1 no Mac).
    janela Variáveis
    Se expandir o nó sessão > sessão > atributos, será possível visualizar os objetos que estão vinculados à sessão. Na imagem acima, ha dois itens vinculados atualmente à sessão (realçado). Eles são selectedCategory e categoryProducts, instanciados no ControllerServlet, nas linhas 83 e 89, respectivamente. Ambos os itens foram vinculados anteriormente, quando você clicou na imagem da categoria, e o ControllerServlet processou a requisição da página da categoria.
  19. Pressione F8 (fn-F8 no Mac) para executar a linha 161. O objeto carrinho é vinculado à sessão e a janela Variáveis é atualizada para exibir as alterações. Na janela Variáveis, note que agora a sessão contém três atributos, sendo o terceiro o objeto ShoppingCart recém inicializado (realçado abaixo).
    janela Variáveis

    Até agora não "provamos" que a sessão, como listada na janela Variáveis, representa uma HttpSession. Como mencionado anteriormente a HttpSession é na verdade uma interface, portanto, quando falamos sobre um objetoHttpSession, ou sobre um objeto de sessão, estamos nos referindo a qualquer objeto que implementa a interface HttpSession. Na janela Variáveis, se você posicionar o cursor sobre "sessão", um pop-up é exibido indicando que a variável representa um objeto HttpSession. O tipo StandardSessionFacade, como exibido, é a classe interna que o GlassFish utiliza para implementar a interface HttpSession. Se você estiver familiarizado com Tomcat e está intrigado com os caminhos "org.apache.catalina" caminhos que aparecem na coluna Valor, é porque o recipiente GlassFishweb/Servlet é, na verdade, um derivado do recipiente Apache Tomcat.

    Um novo Shoppingcart é adicionado à sessão e a requisição continua a ser processada. A fim de completar a implementação da função "adicionar ao carrinho", são tomadas as seguintes ações:
    • a ID do produto selecionado é recuperada a partir da requisição (linha 165)
    • um objeto Product é criado utilizando a ID (linha 169)
    • um novo ShoppingCartItem é criado utilizando o product (linha 170)
    • o ShoppingCartItem é adicionado à lista de itens do ShoppingCart (linha 170)
  20. Pressione F8 (fn-F8 no Mac) para continuar avançando pelo código, ao mesmo tempo estando ciente das quatro ações listadas acima. Dê uma pausa quando o depurador for suspenso na linha 170.
  21. Crie um observador na sessão. Isso lhe permitirá visualizar valores contidos na sessão ao entrar no método addItem na próxima etapa. Clique com o botão direito do mouse na sessão na janela Variáveis e selecione Criar Watch fixo.
    Clique com o botão direito do mouse no menu exibido na janela Variáveis

    Alternativamente, é possível colocar o cursor na variável session e, a seguir, clicar com o botão direito do mouse e selecionar Novo observador. A caixa de diálogo Novo observador permite que você especifique variáveis ou expressões para observar constantemente quando depurar um aplicativo. (No caso de expressões, realce primeiro a expressão e, em seguida, clique com o botão direito do mouse e selecione Nova observação.)
    Caixa de diálogo Novo observador

    Um novo observador é criado na variável da sessão e em todas as variáveis que esta contiver. O observador é visível na janela Observar (Janela > Depurar > Observar) ou , se alternar o botão Observar ( botão Observar ) na margem esquerda da janela Variáveis, este será exibido na linha superior da janela Variáveis.

    O depurador lhe permite ficar atento às variáveis enquanto percorre o código. Isso pode ser proveitoso, por exemplo, se você quiser seguir as alterações de valores específicos de variáveis (e não quiser ter que analisar toda a lista apresentada na janela Variáveis em cada etapa) ou se entrar temporariamente em uma classe que não contenha as variáveis que lhe interessam.
  22. Clique no botão Passar dentro ( botão Passar dentro ) para passar dentro do método addItem do ShoppingCart.
  23. Percorra o método addItem até chegar na linha 53. Como o Javadoc atesta, addItem "adiciona um ShoppingCartItem a lista ShoppingCart item. Se o item do produto especificado já existe no carrinho de compra, a quantidade desse item é aumentada."
  24. Examine a variável session para a qual você criou um observador (etapa 21 acima). A declaração items.add(scItem) na linha 51 adicionou o novo ShoppingCartItem à lista items no ShoppingCart. Isso fica evidente ao entrar no terceiro atributo (ex., a variável carrinho) contida na sessão.
    .Janela Variáveis
    Nesta etapa, é possível ver como um HttpSession é criado para a requisição, como um objeto ShoppingCart é criado e anexado à sessão e como um ShoppingCartItem é criado com base na escolha de produto do usuário e adicionado à lista ShoppingCart itens. A única ação remanescente é encaminhar a requisição à visualização category.jsp.
  25. Abra o fragmento do cabeçalho JSP (cabeçalho.jsp) no editor e coloque um ponto de interrupção na linha 86. Essa linha contém a declaração EL dentro do assistente carrinho de compras que exibe o número de itens no carrinho.
    Ponto de interrupção definido na página JSP
  26. Clique no botão Continuar ( botão Continuar ) na barra de ferramentas do depurador. O depurador continua agindo até que a execução seja concluída ou até alcançar outro ponto de interrupção. Nesse caso, o depurador é suspenso na linha 86 no fragmento do cabeçalho JSP.

    Nota: para suspender o depurador em uma página JSP, é necessário definir um ponto de interrupção. Por exemplo, quando o ControllerServlet encaminha a requisição à visualização apropriada, o depurador não será suspenso automaticamente dentro da página JSP.

  27. Abra a janela Variáveis (Alt-Shift-1; Ctrl-Shift-1 no Mac) se ainda não estiver aberta. Ao contrário do que acontece com as classes Java, o depurador não fornece dicas de ferramenta quando o mouse é posicionado sobre as variáveis ou expressões em uma página JSP. Entretanto, a janela Variáveis lhe permitirá determinar os valores das variáveis ao percorrer o código. Então, onde você pode encontrar o valor para ${cart.numberOfItems}?
  28. Na janela Variáveis, amplie o nó Objetos implícitos > Conteúdo da página > sessão > sessão > atributos. Isso permite o acesso ao objeto de sessão, como o que foi visto anteriormente ao utilizar o ControllerServlet. Na verdade, é possível notar que a sessão, na qual um observador foi criado na etapa 21 acima, indica o mesmo objeto. Aqui é possível verificar que o valor de ${cart.numberOfItems} é igual a "1".
    janela Variáveis

    Maximize a janela Variáveis, ou qualquer janela no IDE, clicando com o botão direito do mouse no cabeçalho da janela e, em seguida, selecionando Maximizar janela (Shift-Esc).

    O depurador lhe dá acesso ao objeto implícito pageContext. pageContext representa o contexto da página JSP e oferece acesso direto aos vários objetos, incluindo os objetos HttpServletRequest, o HttpSession e o ServletContext. Para mais informações, consulte o Tutorial Java EE 5: objetos implícitos.
  29. Clique no botão Terminar sessão ( botão Terminar sessão ). O tempo de execução termina a execução e a sessão de depuração é finalizada. O navegador exibe uma página da categoria totalmente renderizada e é possível ver que o assistente carrinho de compras no cabeçalho da página contém um item.

Esperamos que agora você se sinta confortável ao utilizar o depurador do IDE, não somente para examinar seu projeto quando o mesmo apresentar um comportamento inesperado, mas também como uma ferramenta que o ajuda a se familiarizar mais com o código. Outros botões úteis na barra de ferramentas do depurador incluem:

  • ( botão Passar fora ) Passar fora: lhe conduz para fora da chamada do método atual. Execute e remova o melhor método de chamada da pilha de chamadas.
  • ( Botão Executar para o cursor ) Executar para o cursor: executa até a linha na qual seu cursor estiver posicionado.
  • ( Botão Aplicar alterações de código )Aplicar alterações do código: após a edição de um arquivo, é possível pressionar este botão, de forma que o arquivo é recompilado e as alterações são consideradas na sessão de depuração.
  • ( Botão Expressão Passar sobre ) Expressão Passar sobre: lhe permite visualizar os parâmetros de entrada e valores de saída resultantes de cada chamada de método dentro da expressão. É possível inspecionar os valores de saída do método anterior e os parâmetros de entrada para o próximo método na janela Variáveis locais. Quando não houver nenhuma chamada de método adicional, a expressão Passar sobre se comporta como o comando Passar sobre ( botão Passar sobre ).

Analisando as opções de rastreamento da sessão

Há três maneiras convencionais de rastrear as sessões entre o cliente e o servidor. Com certeza a mais comum é com cookies. A reescrita URL pode ser aplicada na ocasião em que os cookies não estiverem suportados ou desativados. Campos de formulários ocultos também podem ser utilizados como uma maneira de "manter o estado" sobre várias requisições, mas estes podem estar limitados ao uso dentro dos formulários.

O projeto AffableBean inclui um exemplo de método de campo oculto em ambas as páginas de categorias e do carrinho. Os botões "adicionar ao carrinho" e "atualizar", que são exibidos para os itens de produtos, contêm um campo oculto que reveza a ID do produto para o servidor quando o botão é clicado. Se abrir a página cart.jsp no editor, verá que as marcações <form> contêm um campo oculto.

<form action="updateCart" method="post">
    <input type="hidden"
           name="productId"
           value="${product.id}">
    ...
</form>

Dessa forma, a ID do produto é envidada como um parâmetro de requisição que o servidor utiliza para identificar o item dentro do carrinho do usuário, cuja quantidade precisa ser modificada.

O Servlet API fornece um mecanismo de alto nível para o gerenciamento de sessões. Essencialmente, ele cria e passa um cookie entre o cliente e o servidor em cada ciclo de requisição de resposta. Se o navegador do cliente não aceitar cookies, o mecanismo servlet reverte automaticamente para a reescrita URL. Os dois exercícios seguintes demonstram essa funcionalidade.

Analisando a comunicação servidor do cliente com o monitor HTTP

Como padrão, o mecanismo servlet utiliza cookies para manter e identificar sessões entre as requisições. Um número alfanumérico aleatório é gerado para cada objeto de sessão, que serve como um identificador exclusivo. Esse identificador é passado como um cookie "JSESSIONID" ao cliente. Quando o cliente faz uma requisição, o mecanismo servlet lê o valor do cookie JSESSIONID para determinar a sessão a qual a requisição pertence.

Para demonstrar isso, nós utilizaremos o depurador em conjunto com o monitor HTTP do IDE.

  1. Comece com a ativação do monitor HTTP para o servidor que esteja utilizando. Selecione Ferramentas > Servidores. Na coluna à esquerda da janela Servidores, selecione o servidor que você está utilizando (GlassFish). Em seguida, na coluna principal, selecione a opção Ativar monitor HTTP.
    Janela Servidores
  2. Se o servidor já estiver sendo executado, será necessário reiniciá-lo. Entretanto, já que planejamos utilizar o depurador, e a execução do mesmo reinicia o servidor para comunicar em um porta diferente, clique no botão Depurar projeto ( botão Depurar projeto ) na barra de ferramentas principal. Quando o servidor é reiniciado, uma sessão de depuração é iniciada e a página de boas vindas do aplicativo é aberta no navegador. O monitor HTTP é exibido na parte inferior do IDE.
    Monitor HTTP
  3. Clique no registro AffableBean na coluna à esquerda (como mostrada na imagem acima). Ao selecionar registros na coluna à esquerda, a coluna à direita (ex., principal) é atualizada para exibir os dados correspondentes. Na imagem acima, a aba Requisição exibe a URI solicitada ( /AffableBean/), o método HTTP ( GET) e indica que nenhuma string de consulta foi enviada com a requisição.
  4. Selecione a aba Sessão. Note que há uma declaração: "a sessão foi criada como um resultado desta requisição.&quot Isso se deve ao fato do servidor ter enviado um cabeçalho Set-Cookie para o cookieJSESSIONID na sua resposta. Note também que a nova ID da sessão está listada sob "Propriedades da sessão". Como será mostrado mais tarde, a ID da sessão é o valor do cookie JSESSIONID.
    Monitor HTTP: aba Sessão
    Talvez esteja pensando como um objeto de sessão foi criado a partir de uma requisição para a página de boas vindas do site. Afinal, o ControllerServlet não manipula as solicitações iniciais para /AffableBean/ e em nenhum lugar esta requisição encontra getSession(). Ou encontra? Lembre-se que as páginas JSP são compiladas em servlets na implantação. Uma vez que implantar o projeto no servidor, será possível utilizar o IDE para visualizar o servlet compilado do JSP no seu servidor.
  5. Na janela Projetos, clique com o botão direito do mouse no arquivo index.jsp e selecione Visualizar Servlet. É aberto um arquivo index_jsp.java no editor. Esse é o servlet que foi compilado automaticamente a partir da página index.jsp.
  6. Execute uma pesquisa no arquivo para o getSession. Pressione Ctrl-F (⌘-F no Mac), digite "getSession" na barra de pesquisa e, em seguida, pressione Enter.

    Ctrl-F (⌘-F no Mac) é um atalho do teclado para Editar > Localizar.

    Editor exibindo o método getSession
    O método getSession foi, na verdade, chamado. A razão para isto ocorrer é que as páginas do JSP incluem, por padrão, o objeto implícito pageContextsession. Se o desejado era desativar esse comportamento, você poderia ter adicionado a diretiva a seguir à parte superior do arquivo JSP:
    <%@page session="false" %>
    e o método getSession no servlet compilado seria removido.

    Para encontrar a localização do servlet compilado no servidor, é possível passar o mouse sobre a aba do nome do servlet acima do editor. Um pop-up exibe o caminho o caminho para o arquivo no computador.

  7. No navegador, selecione uma categoria e, em seguida, adicione um item ao seu carrinho. Volte para o IDE. Observe que o depurador é suspenso no ponto de interrupção no ControllerServlet, que foi definido anteriormente (linha 150). Todos os pontos de interrupção são lembrados entre as sessões. Para remover o ponto de interrupção, é possível clicar na identificação do ponto de interrupção ( identificação Ponto de interrupção ) na margem esquerda do editor. No entanto, como há vários pontos de interrupção já definidos no projeto, abra a janela Ponto de interrupção do depurador (Janela > Depuração > Pontos de interrupção).
    Janela Pontos de interrupção
    Na janela Pontos de interrupção, é possível visualizar ações de chamada em todos os pontos de interrupção definidos no projeto aberto no IDE.
  8. Clique com o botão direito do mouse no ponto de interrupção definido em header.jspf e selecione Excluir. Em seguida, clique com o botão direito do mouse no ponto de interrupção definido no ControllerServlet e selecione Desabilitar. (Você irá reabilitá-lo mais tarde neste exercício.)
  9. Clique no botão Continuar ( Botão Continuar). A execução da requisição termina e a página da categoria é exibida no navegador com um item adicionado ao carrinho.
  10. No monitor HTTP, pesquise pela requisição addToCart na coluna esquerda e, em seguida, selecione-a para exibir os detalhes na coluna principal.

    Clique no botão Ordem ascendente ( botão Ordem ascendente ), de forma que os registros mais recentes sejam listados na parte superior.


    Sob a aba Requisição, note que a URI requisitada (/AffableBean/addToCart), o método HTTP (POST) e os parâmetros da requisição (productId e submeter).
    aba Requisição: Monitor HTTP
  11. Selecione a aba Cookies. Aqui você verá que existe um cookie nomeado JSESSIONID e que foi enviado por um cliente ao servidor. Note que o valor para o cookie é o mesmo que o da ID da sessão exibida sob a aba Sessão.
    Monitor HTTP: aba Cookies
    Da mesma forma, se clicar na aba Cabeçalho, verá o cookie listado, já que "Cookie" é um cabeçalho da requisição enviada pelo cliente.
    Monitor HTTP: aba Cookies

    Consulte a Lista de cabeçalhos HTTP da Wikipédia para mais informações sobre cabeçalhos de solicitações e respostas.

  12. Selecione a aba Sessão. Há uma declaração que indica: "a sessão existiu antes desta requisição." Note também que o atributo carrinho é listado sob "Atributos de sessão após a requisição". Isso faz sentido, já que sabemos que o objeto carrinho está vinculado à sessão quando a requisição addToCart é processada pela primeira vez.
    Monitor HTTP: aba Sessão

    Nas próximas etapas, localize a ID da sessão e o cookie JSESSIONID na janela Variáveis.
  13. Reabilite o ponto de interrupção definido anteriormente no ControllerServlet. Pressione Alt-Shift-5 (Ctrl-Shift-5 no Mac) para abrir a janela Pontos de interrupção e, em seguida, clique na caixa de verificação ao lado da entrada do ponto de interrupção para reativá-lo.
  14. No navegador, clique no botão "adicionar ao carrinho" para um dos produtos listados.
  15. Alterne para o IDE e note que o depurador é suspenso no ponto de interrupção definido no ControllerServlet. Clique no botão Passar sobre ( botão Passar sobre ) de forma que a variável sessão seja atribuída ao objeto de sessão.
  16. Abra a janela Variáveis (Alt-Shift-1; Ctrl-Shift-1 no Mac) e expanda sessão > sessão. Você encontrará o ID da sessão listado como o valor para a variável id.
  17. Para localizar o cookie JSESSIONID, lembre-se de que pode acessar normalmente os cookies a partir do servlet chamando o método getCookies no HttpServletRequest. Portanto, entre no objeto requisitado: requisição > Herdado > requisição > requisição > Herdado > cookies. É possível ver aqui a ArrayList cookies. Se expandir a lista, encontrará o cookie JSESSIONID, cujo valor é a ID de sessão.
  18. Clique no botão Terminar sessão ( botão Terminar sessão ) para finalizar a sessão de depuração.

Manutenção de sessões com a reescrita URL

Como mencionado, o mecanismo servlet detecta se os cookies estão suportados para o navegador do cliente e, caso não estejam, ele alterna para a reescrita URL, como uma forma de manter as sessões. Isso tudo ocorre de um modo transparente para o cliente. Para o desenvolvedor, o processo não é totalmente transparente.

É necessário certificar-se de que os aplicativos podem reescrever a URL caso os cookies estejam desativados. É possível fazer isto chamando o método de resposta encodeURL em todas as URLs retornadas pelos servlets no aplicativo. Ao fazê-lo, habilita a ID da sessão para ser anexada à URL no caso do uso de cookies não ser uma opção, do contrário, ela retornará à URL sem alteração.

Por exemplo, o navegador envia uma requisição para a terceira categoria (padaria): AffableBeancategoria?3. O servidor responde com a ID de sessão incluído na URL:

/AffableBean/category;jsessionid=364b636d75d90a6e4d0085119990?3

Como foi declarado acima, todas as URLs retornadas pelos servlets do aplicativo devem estar codificadas. Lembre-se de que as páginas JSP são compiladas em servlets. Como é possível codificar as URLs em páginas JSP? A marcação <c.url> da JSTL serve para esse propósito. O exercício a seguir demonstra o problema e ilustra a solução.

  1. Desative os cookies temporariamente no navegador. Se estiver utilizando o Firefox, pode selecionar Ferramentas > Opções (Firefox > Preferências no Mac). Na janela exibida, selecione a aba Privacidade e, em seguida, sob Histórico, selecione "utilizar configurações personalizadas para o histórico" na lista suspensa. Desmarque a opção "aceitar cookies de sites".
    Janela Preferências do Firefox
  2. Execute o projeto AffableBean. Quando a página de boas vindas for exibida, clique na categoria e, em seguida, tente adicionar um item ao seu carrinho. Você verá que a funcionalidade do aplicativo está comprometida severamente no seu estado atual.
    Página Categorias interrompidas
    Como antes, o servidor gera uma sessão e vincula objetos à ela. Isso mostra como a página categoria é capaz de exibir a categoria e os produtos selecionados. Entretanto, o servidor falhou na sua tentativa de definir um cookie JSESSIONID. Portanto, quando o cliente faz um segundo pedido (quando o usuário clica em "adicionar ao carrinho"), o servidor não tem como identificar a sessão a qual o pedido pertence. Portanto, ele não pode localizar nenhum dos atributos definidos previamente na sessão, tais como selectedCategory e categoryProducts. Essa é a razão pela qual falta informações na resposta renderizada especificada por esses atributos.
  3. Abra a página de projeto category.jsp no editor. Localize a linha que implementa o botão "adicionar ao carrinho" (linha 58). O elemento <form> do atributo ação determina que o pedido foi enviado ao servidor.
    <form action="addToCart" method="post">
  4. Modifique o pedido, de forma que seja passado através da marcação <c.url>.
    <form action="<c:url value='addToCart'/>" method="post">
  5. Pressione Ctrl-S (⌘-S no Mac) para salvar as alterações do arquivo. Lembre-se de que o IDE fornece o recurso Implantar ao salvar, que é ativado por padrão. Isso significa que quaisquer alterações são implantadas automaticamente no servidor.
  6. No navegador, selecione uma categoria diferente de forma que o aplicativo renderize a página da categoria modificada recentemente.
  7. Examine o código-fonte para a página. No Firefox, é possível pressionar Ctrl-U (⌘-U no Mac). O botão "adicionar ao carrinho" para cada produto é exibido com a ID da sessão anexada à URL.
    <form action="addToCart;jsessionid=4188657e21d72f364e0782136dde" method="post">
  8. Clique no botão "adicionar ao carrinho" para qualquer item. Você verá que o servidor agora é capaz de determinar a sessão à qual o pedido pertence e de renderizar a resposta de forma adequada.
  9. Antes de prosseguir, certifique-se de reabilitar cookies para o navegador.

Em cada link em que o usuário puder clicar no aplicativo, cuja resposta exija alguma forma de dados relacionados à sessão, precisa ser codificado corretamente. As vezes a implementação não é direta, como o exemplo mostrado acima. Por exemplo, o assistente "limpar carrinho" utilizado no cart.jsp define atualmente um parâmetro limpar como verdadeiro quando o link é clicado.

<%-- clear cart widget --%>
<c:if test="${!empty cart && cart.numberOfItems != 0}">
    <a href="viewCart?clear=true" class="bubble hMargin">clear cart</a>
</c:if>

A marcação <c.url> pode ser aplicada à URL da seguinte forma:

<%-- clear cart widget --%>
<c:if test="${!empty cart && cart.numberOfItems != 0}">

    <c:url var="url" value="viewCart">
        <c:param name="clear" value="true"/>
    </c:url>

    <a href="${url}" class="bubble hMargin">clear cart</a>
</c:if>

O parâmetro clear=true é definido quando uma marcação <c:param é adicionado entre as marcações <c.url>. Uma variável nomeada "url" é definida quando o atributo var do <c.url> é utilizado e o var é então acessado na marcação âncora HTML utilizando a expressão ${url}.

É possível baixar e examinar o instantâneo 6 para ver como todos os links no projeto foram codificados.

A reescrita URL só deve ser utilizada no caso dos cookies não serem um método de rastreamento disponível. A reescrita URL é geralmente considerada como uma solução de qualidade inferior porque ela expõe a ID da sessão nos registros, marcadores, cabeçalhos de referência e HTML em cachê, além da barra de endereço do navegador. São necessários também mais recursos do lado do servidor, já que o servidor precisa executar etapas adicionais para cada entrada de pedido, a fim de extrair a ID da sessão da URL e emparelhá-la com uma sessão existente.


Manipulando o tempo limite da sessão

Configurando os intervalos de tempo da sessão

É necessário considerar o intervalo de tempo máximo no qual o servidor mantém as sessões. No caso de o site receber um tráfico intenso, um grande número de sessões poderiam gastar a capacidade de memória do servidor. É necessário portanto, encurtar o intervalo no intuito de remover as sessões não utilizadas. Por outro lado, você certamente não desejaria encurtar muito as sessões, já que isto poderia se tornar um problema de uso que poderia ter um impacto negativo nos negócios ligados ao site. Obtendo o exemplo do aplicativo AffableBean, onde uma usuária faz o check-out após encher seu carrinho de compras com itens. Ela então percebe que precisa inserir os detalhes do seu cartão de crédito e sai para pegar sua carteira. Após retornar ao computador com o cartão de crédito em mãos, preenche o formulário de check-out e clica em submeter. No entanto, durante esse tempo, sua sessão foi expirada no servidor. A usuária nota que seu carrinho de compras está vazio e é redirecionada à página inicial. Será que ela realmente irá gastar tempo percorrendo todo o processo novamente?

Os passos a seguir, demonstram como definir o intervalo de tempo de espera da sessão no projeto AffableBean para 10 minutos. Claro que a duração atual depende dos recursos do servidor, dos objetivos do negócios do aplicativo e da popularidade do seu site.

  1. Abra o descritor de implantação do aplicativo no editor. Pressione Alt-Shift-O (Ctrl-Shift-O no Mac) para utilizar a caixa de diálogo do IDE Vá para o arquivo. Digite 'web' e, em seguida, clique em OK.
    Caixa de diálogo Vá para o arquivo
    O editor exibe o arquivo web.xml na visualização XML. O modelo que o NetBeans fornece para o arquivo web.xml inclui uma configuração padrão para 30 minutos.
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
  2. Clique na aba Geral e digite "10" no campo Tempo limite da sessão.
    Aba Geral do arquivo web.xml
  3. Salve o arquivo (Ctrl-S; ⌘-S on Mac).

    Se voltar para a visualização XML, verá que o elemento <session-timeout> foi atualizado.
    <session-config>
        <session-timeout>10</session-timeout>
    </session-config>

Observação: Alternativamente, é possível remover completamente o elemento <session-timeout> e editar o elemento session-properties no descritor de implementação específico do GlassFish (sun-web.xml). Isso definiria o tempo limite global para todos os aplicativos no módulo da web do servidor. Consulte o O Guia de desenvolvimento de aplicativos do Sun GlassFish Server 3.0.1: Criando e gerenciando sessões para obter mais detalhes.

Manipulando de forma programática o tempo limite das sessões

Se seu aplicativo se baseia em sessões, será necessário tomar medidas para assegurar que ele possa lidar confortavelmente com situações nas quais um pedido é recebido para uma sessão que possui tempo limite ou que não pode ser identificada. É possível alcançar isso no aplicativo AffableBean criando um filtro simples que intercepta os pedidos enviados para o ControllerServlet. O filtro verifica se a sessão existe, se não existir, ele encaminha o pedido à página de boas vindas do site.

  1. Comece examinando o problema que aparece quando a sessão expira durante uma visita do usuário ao site. Redefina temporariamente o intervalo de tempo limite da sessão para um minuto. Abra o descritor de implantação da web (web.xml) e insira "1" entre as marcações <session-timeout>.
    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>
  2. Execute o projeto AffableBean. No navegador, clique na página da categoria, adicione vários itens ao carrinho e, em seguida, clique em "Ver carrinho".
    Página do carrinho exibindo itens no carrinho de compras
  3. Espere pelo menos um minuto completo.
  4. Atualize a quantidade para um dos itens exibidos na página do carrinho. (Qualquer número entre 1 e 99 é aceitável.) Clique em "atualizar". O servidor retorna uma mensagem HTTP Status 500.
    Mensagem de erro do GlassFish exibida no navegador
  5. Examine o registro do servidor GlassFish no IDE. Abra a janela Saída (Ctrl-4, ⌘-4 no Mac) e selecione a aba Servidor GlassFish. Vá para a parte inferior do registro para examinar o rastro da pilha fornecido pelo erro.
    mensagem de erro do GlassFish exibida no navegador
    O registro do servidor indica que uma NullPointerException ocorreu na linha 184 no ControllerServlet. A janela Saída forma um link com a linha onde ocorreu a exceção.
  6. Clique no link. É possível navegar diretamente até a linha 184 no ControllerServLet. Passar o mouse sobre a identificação do erro na margem esquerda do editor fornece uma dica de ferramenta que descreve a exceção.
    Identificação do erro e dica de ferramenta exibida no editor
    Como a sessão já havia expirado antes do pedido ser recebido, o mecanismo servlet não pode associar o pedido à sua sessão correspondente. Portanto, ele não foi capaz de localizar o objeto cart (linha 151). A exceção ocorreu finalmente na linha 184 quando o mecanismo tentou chamar um método em uma variável equivalente a null.

    Agora que identificamos o problema, vamos corrigi-lo implementando um filtro.
  7. Clique no botão Novo arquivo ( botão Novo arquivo ) na barra de ferramentas do IDE. (Outra alternativa é pressionar Ctrl-N; ⌘-N no Mac.)
  8. Selecione a categoria Webe, em seguida, selecione Filtro e clique em Avançar.
  9. Nomeie o filtroSessionTimeoutFilter. Digite filtro no campo Pacotes, de forma que a classe do filtro seja colocada em um novo pacote quando for criada.
  10. Clique em Avançar. Aceite as configurações padrão e clique em Terminar. Um modelo para o SessionTimeoutFilter é gerado e aberto no editor.

    Nota: atualmente, no NetBeans 6.9, não é possível utilizar o assistente para definir um mapeamento a um servlet que não seja registrado no descritor de implantação da web. (O ControllerServlet foi registrado usando a anotação @WebServlet.) Portanto, modificaremos o código gerado na próxima etapa.

  11. Modifique a assinatura da anotação @WebFilter, de maneira que apareça da seguinte forma.
    @WebFilter(servletNames = {"Controller"})
    public class SessionTimeoutFilter implements Filter {
    Isso define o filtro para interceptar qualquer pedido que seja manipulado pelo ControllerServlet. (Alternativamente, você poderia ter mantido o atributo urlPatterns e listado todos os padrões que manipulam o ControllerServlet.)

    Note que o "Controlador" é o nome do ControllerServlet, como especificado na assinatura da anotação @WebServlet. Note também que o atributo foi removido filterName, já que o nome da classe do filtro já foi utilizado por padrão.

    O modelo do filtro do IDE fornece vários códigos interessantes que valem a pena inspecionar por si só. No entanto, a maioria deles não é necessário para o nosso propósito. Qualquer classe de filtro deve implementar a interface Filtro, que define três métodos:
    • init: executa qualquer ação após o filtro ser inicializado, mas antes de começar a funcionar
    • destroy: remove o filtro do serviço. Esse método também pode ser utilizado para executar qualquer operação de limpeza.
    • doFilter: utilizado para executar operações para cada pedido que o filtro interceptar.

    Utilize a opção Pesquisa do índice Javadoc para puxar a documentação na interface Filtro. Pressione Shift-F1 (fn-Shift-F1 no Mac) e, em seguida, digite "Filtro" no campo pesquisar e tecle Enter. Selecione a entrada "Interface no javax.servlet". A documentação Javadoc é exibida no painel inferior da ferramenta de pesquisa do índice.

  12. Substitua o corpo do SessionTimeoutFilter pelos conteúdos a seguir.
    @WebFilter(servletNames = {"Controller"})
    public class SessionTimeoutFilter implements Filter {
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
    
            HttpServletRequest req = (HttpServletRequest) request;
    
            HttpSession session = req.getSession(false);
    
            // se a sessão não existe, encaminhe o usuário a página bem vindo
            if (session == null) {
                try {
                    req.getRequestDispatcher("/index.jsp").forward(request, response);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return;
            }
    
            chain.doFilter(request, response);
        }
    
        public void init(FilterConfig filterConfig) throws ServletException {}
    
        public void destroy() {}
    
    }
  13. Pressione Ctrl-Shift-I (⌘-Shift-I no Mac) para corrigir instruções de importações. (As importações precisam ser adicionadas às HttpServletRequest e HttpSession.) Além disso, use as dics do editor para adicionar a anotação @Override aos métodos init, destroy e doFilter.

    Nas etapas a seguir, você executará o depurador no projeto e percorrerá o método doFilter para ver como ele determina se o pedido está vinculado a uma sessão existente.
  14. Abra a janela Pontos de interrupção (Alt-Shift-5; Ctrl-Shift-5 no Mac) e assegure-se de que não haja nenhum ponto de interrupção definido. Para excluir um ponto de interrupção, clique com o botão direito do mouse no ponto de interrupção e escolha Excluir. (Se você concluiu o exercício acima, Examinando a comunicação cliente-servidor com o monitor de HTTP, poderá ter um ponto de verificação pendente definido no ControllerServlet.)
  15. Execute o depurador. Clique no botão Depurar projeto (botão Depurar projeto) na barra de ferramentas principal do IDE.
  16. Quando a página de boas vindas for exibida no navegador, selecione uma categoria e, em seguida, adicione vários itens ao seu carrinho de compras.
  17. Defina um ponto de interrupção na linha no método doFilter do SessionTimeoutFilter que tenta acessar a sessão (linha 32).
    Ponto de interrupção definido no editor
  18. No navegador, clique no botão "ver carrinho". Alterne para o IDE e note que o depurador foi suspenso no ponto de interrupção.

    Lembre-se que getSession() cria um novo objeto de sessão caso o atual não exista. Aqui, utilizamos o getSession(falso), que se abstém de criar um novo objeto caso não seja encontrado nenhum. Em outras palavras, o método retorna null se a sessão não existir.
  19. Clique no botão Passar sobre ( botão Passar sobre ) e, em seguida, passe o mouse sobre a variável sessão. Desde que não tenha passado um minuto de quando o pedido anterior foi enviado, você verá que a variável foi atribuída à StandardSessionFacade. Isso representa o objeto de sessão para o pedido.
    Pop-up exibindo a variável "sessão" atribuída a um objeto de sessão
  20. Continue percorrendo o método até que a solicitação seja processada. Como session não é igual a null, salte a declaração if e a chain.doFilter e, em seguida, encaminhe o pedido ao ControllerServlet (linha 44).
  21. No navegador, certifique-se de que se passou um minuto completo e, em seguida, atualize a quantidade para um dos itens de produtos no carrinho. Esse é o mesmo procedimento que executamos anteriormente no exercício, quando foi retornada a mensagem Status 500. Agora que o filtro intercepta os pedidos direcionados ao ControllerServlet, veremos o que acontece quando ocorrer o tempo limite da sessão.
  22. Após clicar em "atualizar", alterne para o IDE e note que o depurador é suspenso novamente no pontos de interrupção definido no filtro.
  23. Realce a expressão req.getSession(falsa)e, em seguida, passe o mouse sobre ela. Aqui você verá que a expressão equivale a null, já que a sessão já foi expirada.
    Pop-up exibindo a variável "sessão" equivale a "nula"
  24. Continue percorrendo o código. Agora que a variável session se equivale a null, a declaração if na linha 35 é processada e o pedido é encaminhado para /index.jsp. Quando o depurador finalizar a execução, você verá que o navegador exibe a página de boas vindas do site.
  25. Clique no botão Terminar sessão ( botão Terminar sessão ) para finalizar a sessão de depuração.
  26. Abra o arquivo do projeto web.xml e mude o intervalo do tempo de espera para 10 minutos.
    <session-config>
        <session-timeout>10</session-timeout>
    </session-config>
  27. Salve o arquivo (Ctrl-S; ⌘-S no Mac).

O Instantâneo 6 fornece a versão completa do projeto para esta unidade do tutorial. Um tópico de preocupação final sobre o gerenciamento de sessão deve ser mencionado. É possível finalizar explicitamente uma sessão chamando o método invalidate no objeto de sessão. Caso a sessão não seja mais necessária, ela deve ser removida a fim de conservar a memória disponível para o servidor. Depois de concluir a próxima unidade, Integrando lógica de negócio transacional, você verá como o ControllerServlet, ao processar com sucesso um pedido do cliente, destrói o objeto cart do usuário e termina a sessão usando o método invalidate.

// se o pedido foi processado com sucesso, enviar usuário para a página de confirmação
if (orderId != 0) {

    // desassociar o carrinho de compras da sessão
    cart = null;

    // end session
    session.invalidate();

    ...
}

Isso é demonstrado no instantâneo 8 do projeto (e em instantâneos posteriores).


Consulte também