Tutorial do NetBeans E-commerce: Gerenciando Sessões

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

Cada aplicação de e-commerce que oferece alguma forma de funcionalidade de carrinho de compras precisa poder lembrar dados específicos do usuário, conforme os usuários clicam no site. Infelizmente, para o desenvolvedor, o protocolo HTTP, sobre o qual a comunicação na Internet ocorre, é um protocolo sem estado. Cada solicitação recebida pelo servidor é uma informação independente que não tem nenhuma relação com solicitações recebidas anteriormente. Portanto, se o cliente clicar em um botão para adicionar um item ao seu carrinho de compras, a aplicação deverá tomar medidas para assegurar não somente que o estado do carrinho do usuário seja atualizado, mas que a ação não afete o carrinho de outro usuário que pode estar navegando pelo site ao mesmo tempo.

A fim de tratar 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 todas as aplicações web baseadas em Java, fornece isso com sua interface HttpSession. É necessário também definir várias classes, como, por exemplo, ShoppingCart e ShoppingCartItem, que permitem à aplicação armazenar temporariamente dados do usuário, enquanto a sessão é mantida.

Esta unidade do tutorial utiliza uma abordagem diferente das outras no Tutorial do NetBeans E-commerce. Ao invés de criar os arquivos de projeto e fornecer as etapas com snippets de código para copiar e colar no seu próprio projeto, você abre o snapshot do projeto completo para esta unidade e examina o código utilizando o depurador do 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 website resulte em uma sessão dedicada. Você aprenderá também sobre variáveis de escopo e seu uso nas classes Java e nas páginas JSP. Esta unidade também discute o mecanismo default de HttpSession para manutenção de sessões (ex., cookies) e mostra que medidas devem ser tomadas no caso de os cookies estarem desativados no browser do usuário. Por fim, os time-outs de sessão são cobertos e a unidade demonstra como tratá-los criando um filtro simples que intercepta solicitações de verificação da existência da sessão.

Você pode exibir uma demonstração ao vivo da aplicação construída neste tutorial: Aplicação de Demonstração do Tutorial do 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
GlassFish Server v3 ou Open Source Edition 3.0.1
Servidor de banco de dados MySQL versão 5.1
Projeto AffableBean snapshot 5

Observações:

  • O NetBeans IDE requer o Java Development Kit (JDK) para ser executado adequadamente. Se você não tiver nenhum dos recursos listados acima, o JDK deverá ser o primeiro item a ser submetido a download e instalado.
  • O Pacote Java do NetBeans IDE inclui o Java Web e tecnologias EE, que são necessárias para a aplicação construída neste tutorial.
  • O pacote Java do NetBeans IDE também inclui o GlassFish Server, necessário para este tutorial. Você poderia fazer download do GlassFish Server independentemente, mas a versão fornecida pelo NetBeans do qual fez download tem a vantagem adicional de ser registrada automaticamente no IDE.
  • Você pode seguir esta unidade do tutorial sem ter concluído as unidades anteriores. Para isso, 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.

Tratando Dados de Sessão

As aplicações podem gerenciar sessões de usuário com o objeto HttpSession. Você pode vincular dados específicos do usuário ao objeto HttpSession e, em seguida, acessar esses dados em um estágio mais avançado. As duas ações de vincular e acessar podem ser feitas por meio das classes Java, assim como usando variáveis de escopo de sessão em expressões EL.

Trabalhando com um Objeto HttpSession

A aplicação AffableBean utiliza o objeto HttpSession para identificar usuários em várias solicitações. Um objeto HttpSession é obtido utilizando getSession() em uma determinada solicitação:

HttpSession session = request.getSession();

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

Você pode utilizar o objeto de sessão como um veículo para a transferência de dados entre as solicitações. Você pode utilizar o método setAttribute para vincular objetos à sessão. Da mesma forma, você usa getAttribute para recuperar objetos da sessão. Na aplicação 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, você pode acessar objetos vinculados à sessão utilizando expressões EL. Continuando com o exemplo acima, se um objeto ShoppingCart chamado "cart" estiver vinculado à sessão, você poderá 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 é uma maneira de acessar valores armazenados no objeto. Se explorar a nova classe ShoppingCart no snapshot do projeto, você notará que ela contém as seguintes propriedades:

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

Desde que as propriedades tenham métodos getter correspondentes, você poderá acessar valores para propriedades singulares utilizando notação de ponto simples em uma expressão EL. Se examinar a página cart.jsp, verá que é exatamente assim que o valor para numberOfItems é acessado:

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

Para extrair dados de propriedades que contêm 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 product de ShoppingCartItem identifica o tipo de produto de um item do carrinho. O loop acima aproveita isso definindo primeiramente uma variável product para a expressão ${cartItem.product}. Em seguida ele utiliza a variável para obter informações sobre esse produto (ex., nome e preço).

Trabalhando com Variáveis de Escopos em Aplicações Web

Quando se trabalha com a tecnologia JSP/Servlet, há quatro objetos de escopo disponíveis no realm da aplicação. A tecnologia JSP implementa objetos implícitos que permitem acessar classes definidas pela API do Servlet.

Escopo Definição Classe Servlet Objeto Implícito JSP
Aplicação Memória global para uma aplicação web javax.servlet.ServletContext applicationScope
Sessão Dados específicos para uma sessão de usuário javax.servlet.http.HttpSession sessionScope
Solicitação Dados específicos para uma solicitação de servidor individual javax.servlet.HttpServletRequest requestScope
Página Dados que são válidos somente no contexto de uma única página (somente JSPs) [n/d] pageScope

Se abrir o arquivo category.jsp do projeto no editor, verá que as expressões EL incluem diversas variáveis de escopo, incluindo ${categories}, ${selectedCategory} e ${categoryProducts}. A variável ${categories} é uma aplicação de escopo, definida no método init do ControllerServlet:

// store category list in servlet context
getServletContext().setAttribute("categories", categoryFacade.findAll());

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

// place selected category in session scope
session.setAttribute("selectedCategory", selectedCategory);

Observação: Se você estiver continuando de unidades anteriores do tutorial, provavelmente notará que ${selectedCategory} e ${categoryProducts} foram originalmente colocadas 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 solicitação addToCart retornando a página de categoria em exibição no momento. Portanto, é preciso saber a selectedCategory e a categoryProducts pertencentes à categoria selecionada. Em vez de estabelecer essas informações para cada solicitação, você as coloca no escopo da sessão de uma solicitação de category para que sejam mantidas em 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" retorna o usuário à categoria exibida anteriormente. Novamente, as variáveis selectedCategory e categoryProducts são necessárias.

Ao fazer referência às variáveis do escopo em uma expressão EL, você não precisa especificar o escopo da variável (desde que você não tenha duas variáveis com o mesmo nome em escopos diferentes). O mecanismo JSP verifica todos os quatro 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 obter mais informações, consulte os recursos a seguir:

Examinando Dados de Sessão com o Depurador Java

Comece explorando como a aplicação se comporta durante o runtime. Utilize o depurador do 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 snapshot do projeto para esta unidade do tutorial no IDE. Clique no botão Abrir Projeto (Botão Abrir Projeto) e use o assistente para navegar para o local em seu computador em que você fez download do projeto. Se estiver prosseguindo de uma unidade de tutorial anterior, observe que este snapshot do projeto inclui um novo pacote cart, que contém 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 garantir que esteja configurado corretamente com seu banco de dados e servidor de aplicações.

    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 da aplicação no browser. Se estiver prosseguindo diretamente da unidade anterior do tutorial, notará as seguintes melhorias.

    página de categoria

    • Clicar em "adicionar ao carrinho" ativa, pela primeira vez, o carrinho de compras e os widgets "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 do carrinho no widget do carrinho de compras do cabeçalho.
    • Clicar em "exibir carrinho" resulta na exibição da página do carrinho.
    • Clicar em "avançar para check-out" resulta na exibição da página de check-out.
    Imagem do browser 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 check-out" resulta na exibição da página de check-out.
    • Inserir um número (1 a 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 de quantidade de um item e, em seguida, clicar em "atualizar" resulta na remoção do item da tabela exibida.
    Imagem do browser da página do carrinho

    página de check-out

    • Clicar em "exibir carrinho" resulta na exibição da página do carrinho.
    • Clicar em "submeter compra" resulta na exibição da página de confirmação (sem dados específicos do usuário).
    Imagem do browser da página de check-out
  4. Utilize a caixa de diálogo Ir para 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 Ir para 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 GlassFish Server será iniciado (ou reiniciado, se já estiver sendo executado) e abrirá um soquete no número da porta de depuração. A página de boas-vindas da aplicação será aberta no browser.

    É possível exibir e modificar o número da porta do depurador a partir da janela Servidores (Ferramentas > Servidores). Selecione a guia Java para o servidor que está utilizando. Especifique o número da porta no campo "Endereço a ser utilizado" em Definições de Depuração.

  7. Quando a página de boas-vindas da aplicação for exibida no browser, clique em qualquer imagem da categoria para navegar para a página da categoria. Lembre-se de que quando você clicar no botão "adicionar ao carrinho" uma solicitação addToCart será enviada ao servidor:
    <form action="addToCart" method="post">
    Como você deve se lembrar de Preparando as Views de Página e o Servlet do Controlador, o método doPost de ControllerServlet trata solicitações para o padrão de URL /addToCart. Você poderá, portanto, 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 da categoria. Volte para o IDE e note que o depurador é suspenso no ponto de interrupção.
    O depurador é suspenso no ponto de interrupção do editor
  9. Posicione o cursor na chamada para getSession() e pressione Ctrl-Espaço para chamar a documentação do Javadoc.
    Documentação do Javadoc exibida no editor
    De acordo com a documentação, a getSession() retorna a HttpSession atualmente associada à solicitação 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 session. Observe que o depurador é suspenso na linha está prestes a ser executado. O valor retornado por getSession() ainda não foi salvo na variável de session e você verá uma popup informando que " session não é uma variável conhecida "no contexto atual".
    Pop-up do depurador exibido no editor
  11. Clique no botão Fazer Step Over (Botão Fazer Step Over) na barra de ferramentas do depurador, localizada acima do editor. A linha será executada e o depurador passará para a próxima linha do arquivo.
  12. Passe novamente o mouse sobre a variável session. Agora você poderá ver o valor definido no momento para a variável session.
    Pop-up do depurador exibido no editor

    No NetBeans 6.9, você pode clicar no ponteiro cinza (Botão Fazer Step Over) no popup para expandir uma lista de valores de variáveis contidos no elemento destacado.

  13. Clique o botão Fazer Step Over (Botão Fazer Step Over) (F8; fn-F8 no Mac) para chegar à instrução if (linha 154). Como você acabou de clicar no botão "adicionar ao carrinho" no browser, deve sabe que a expressão userPath.equals("/addToCart) deverá ser avaliada como true.
  14. Realce a expressão userPath.equals("/addToCart") (clicando com o mouse enquanto mantém a tecla Ctrl pressionada). Desta vez você verá um popup que indica o valor da expressão que foi realçada.
    Expressão avaliada exibida no popup
  15. Pressione F8 (fn-F8 no Mac) para passar para a próxima linha (linha 158). A aplicação foi criada para 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 solicitação addToCart foi recebida nesta sessão de depuração, pode-se esperar que o objeto cart seja igual a null.
    Expressão avaliada exibida no popup
  16. Pressione F8 (fn-F8 no Mac) para passar à próxima linha (linha 160). Depois, na linha 160, onde o objeto ShoppingCart é criado, clique no botão Fazer Step Into (Botão Fazer Step Into). O depurador entra no método que está sendo chamado. Neste caso, você será levado diretamente ao construtor do ShoppingCart.
    Expressão avaliada exibida no popup
  17. Pressione Ctrl-Tab para voltar ao ControllerServlet. Observe que o IDE fornece um Emblema (Emblema da Pilha de Chamada) de Pilha de Chamada na linha 160, indicando que o depurador está suspenso temporariamente em algum lugar em um método mais no início da 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 conclui o construtor ShoppingCart, você é levado de volta ao ControllerServlet.

    A linha 161 do ControllerServlet vincula o objeto cart recém-criado à sessão.
    session.setAttribute("cart", cart);
    Para testemunhar isso, abra a janela 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, você poderá exibir os objetos que estão vinculados à sessão. Na imagem acima há dois itens vinculados atualmente à sessão (realçados). Eles são selectedCategory e categoryProducts, instanciados no ControllerServlet, nas linhas 83 e 89, respectivamente. Os dois itens foram vinculados anteriormente, quando você clicou na imagem de uma categoria, e o ControllerServlet processou a solicitação da página da categoria.
  19. Pressione F8 (fn-F8 no Mac) para executar a linha 161. O objeto cart será vinculado à sessão e a janela Variáveis será 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 "session", um popup será 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 o Tomcat e estiver intrigado com os caminhos "org.apache.catalina" que aparecem na coluna Valor, é porque o contêiner web/servlet do GlassFish é, na verdade, um derivado do contêiner Apache Tomcat.

    Um novo ShoppingCart é adicionado à sessão e a solicitação continua a ser processada. Para concluir a implementação da funcionalidade "adicionar ao carrinho", são realizadas as seguintes ações:
    • o ID do produto selecionado é recuperado da solicitação (linha 165)
    • um objeto Product é criado utilizando o 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 ciente das quatro ações listadas acima. Pause quando o depurador for suspenso na linha 170.
  21. Crie um watch na sessão. Isso lhe permitirá exibir valores contidos na sessão ao fazer step into 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

    Como alternativa, você pode colocar o cursor na variável session no editor e, em seguida, clicar com o botão direito do mouse e selecionar Novo Watch. A caixa de diálogo Novo Watch permite que você especifique variáveis ou expressões para watch continuamente ao depurar uma aplicação. (No caso de expressões, realce primeiro a expressão e, em seguida, clique com o botão direito do mouse e selecione Novo Watch.)
    Caixa de diálogo Novo Watch

    Um novo watch será criado na variável session e em todas as variáveis que ela contiver. O watch é visível na janela Watches (Janela >Depuração >Watches) ou, se você alternar o botão Watches (Botão Watches) na margem esquerda da janela Variáveis, ele 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 útil, por exemplo, se você quiser seguir as alterações de valores de variáveis específicas (e não quiser ter que analisar toda a lista apresentada na janela Variáveis em cada etapa) ou se fizer step into temporariamente em uma classe que não contenha as variáveis que lhe interessam.
  22. Clique na botão Fazer Step Into para (Botão Fazer Step Into) fazer step into no método addItem do ShoppingCart.
  23. Percorra o método addItem até chegar na linha 53. Como o Javadoc atesta, addItem "adiciona um ShoppingCartItem à lista de items do ShoppingCart. Se o item do product especificado já existe no carrinho de compra, a quantidade desse item é aumentada."
  24. Examine a variável session na qual você criou um watch (etapa 21 acima). A instrução items.add(scItem) na linha 51 adicionou o novo ShoppingCartItem à lista de items no ShoppingCart. Isso fica evidente ao entrar no terceiro atributo (ex., a variável cart) contida na sessão.
    Janela Variáveis
    Nesta etapa, você pode ver como uma HttpSession é criada para a solicitaçã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 de Items do ShoppingCart. A única ação remanescente é encaminhar a solicitação à view category.jsp.
  25. Abra o fragmento JSP do cabeçalho (header.jsp) no editor e coloque um ponto de interrupção na linha 86. Essa linha contém a instrução EL no widget do carrinho de compras que exibe o número de itens do 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é atingir outro ponto de interrupção. Nesse caso, o depurador é suspenso na linha 86 no fragmento JSP do cabeçalho.

    Observação: para suspender o depurador em uma página JSP, é necessário definir um ponto de interrupção. Por exemplo, quando o ControllerServlet encaminha a solicitação à view 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. Diferente 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 > pageContext > sessão > sessão > atributos. Isso permite o acesso ao objeto de sessão, como o que foi visto anteriormente ao trabalhar com o ControllerServlet. Na verdade, você pode notar que a sessão na qual um watch foi criado na etapa 21 acima indica o mesmo objeto. Aqui você pode verificar se 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, HttpSession e ServletContext. Para obter mais informações, consulte o Tutorial do Java EE 5: Objetos Implícitos.
  29. Clique no botão Finalizar Sessão (Botão Finalizar Sessão). O runtime finaliza a execução e a sessão de depuração é encerrada. O browser exibe uma página de categoria totalmente renderizada e você poderá ver que o widget 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 ele 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 Fazer Step Out) Fazer Step Out: você sai da chamada do método atual. Execute e remova o método de chamada superior da pilha de chamadas.
  • (Botão Executar até o Cursor) Executar até o Cursor: executa até a linha na qual o cursor está posicionado.
  • (Botão Aplicar Alterações de Código) Aplicar Alterações de Código: depois de editar um arquivo, você pode pressionar este botão para que o arquivo seja recompilado e as alterações levadas em conta na sessão de depuração.
  • (Botão Fazer Step Over da Expressão) Fazer Step Over da Expressão: permite que você exiba os parâmetros de entrada e os valores de saída resultantes de cada chamada de método dentro de uma expressão. Você pode 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 há mais nenhuma chamada de método, Fazer Step Over da Expressão se comporta como o comando Fazer Step Over (Botão Fazer Step Over).

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 de URL pode ser aplicada na ocasião em que os cookies não estiverem suportados ou desativados. Campos de forms ocultos também podem ser utilizados como uma maneira de "manter o estado" sobre várias solicitações, mas estão limitados ao uso dentro dos forms.

O projeto AffableBean inclui um exemplo do método de campo oculto nas duas páginas, da 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 retransmite ID do produto para o servidor quando o botão é clicado. Se abrir a página cart.jsp no editor, você verá que as tags <form> contêm um campo oculto.

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

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

A API do Servlet fornece um mecanismo de alto nível para o gerenciamento de sessões. Essencialmente, ela cria e passa um cookie entre o cliente e o servidor com cada ciclo de resposta da solicitação. Se o browser do cliente não aceitar cookies, o mecanismo do servlet será revertido automaticamente para a reescrita de URL. Os dois exercícios a seguir demonstram essa funcionalidade.

Analisando a Comunicação Cliente-Servidor com o Monitor HTTP

Como default, o mecanismo do servlet utiliza cookies para manter e identificar sessões entre as solicitaçõ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 solicitação, o mecanismo do servlet lê o valor do cookie JSESSIONID para determinar a sessão à qual a solicitaçã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 está utilizando. Selecione Ferramentas > Servidores. Na coluna à esquerda da janela Servidores, selecione o servidor que 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. No entanto, como pretende usar o depurador e executar o depurador reinicia o servidor para se comunicar em uma porta diferente, simplesmente clique no botão Depurar Projeto (Botão Depurar Projeto) no na barra de ferramentas principal do IDE. Quando o servidor é reiniciado, uma sessão de depuração é iniciada e a página de boas-vindas da aplicação é aberta no browser. O monitor HTTP é exibido na parte inferior do IDE.
    Monitor HTTP
  3. Clique no registro AffableBean na coluna à esquerda (como mostrado na imagem acima). Quando você seleciona registros na coluna à esquerda, a coluna à direita (ex., principal) será atualizada para exibir os dados correspondentes. Na imagem acima, a guia Solicitação exibe o URI solicitado ( /AffableBean/), o método HTTP ( GET) e indica que nenhuma string de consulta foi enviada com a solicitação.
  4. Selecione a guia Sessão. Note que há uma instrução: "a sessão foi criada como resultado desta solicitação.&quot Isso se deve ao fato de o servidor ter enviado um cabeçalho Set-Cookie para o cookieJSESSIONID na sua resposta. Observe também que o novo ID da sessão está listado em "Propriedades da sessão". Como será mostrado mais tarde, o ID da sessão é o valor do cookie JSESSIONID.
    Monitor HTTP - guia Sessão
    Talvez esteja pensando como um objeto de sessão foi criado de uma solicitação para a página de boas-vindas do site. Afinal, o ControllerServlet não trata a solicitação inicial para /AffableBean/ e em nenhum lugar essa solicitação encontra getSession(). Ou encontra? Lembre-se de que as páginas JSP são compiladas em servlets na implantação. Depois de ter implantado o projeto no servidor, você poderá, na verdade, utilizar o IDE para exibir 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 Exibir Servlet. Será 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 por 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 que exibe o método getSession
    O método getSession foi, na verdade, chamado. A razão para isso é que as páginas JSP incluem, por default, o objeto implícito pageContext.session. Se quisesse desativar esse comportamento, você poderia ter adicionado a diretiva a seguir à parte superior de um 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, você pode passar o mouse sobre a guia do nome do servlet acima do editor. Um popup exibe o caminho o caminho para o arquivo no computador.

  7. No browser, 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, você poderia clicar no emblema do ponto de interrupção (Emblema de 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 Pontos de interrupção do depurador (Janela > Depuração > Pontos de Interrupção).
    Janela Pontos de Interrupção
    Na janela Pontos de interrupção, você pode exibir chamar ações em todos os pontos de interrupção definidos nos projetos abertos no IDE.
  8. Clique com o botão direito do mouse no ponto de interrupção definido em header.jspf e selecione Deletar. Em seguida, clique com o botão direito do mouse no ponto de interrupção definido no ControllerServlet e selecione Desativar. (Você irá reabilitá-lo mais tarde neste exercício.)
  9. Clique no botão Continuar (Botão Continuar). A execução da solicitação é finalizada e a página da categoria será exibida no browser com um item adicionado ao carrinho.
  10. No Monitor HTTP, procure a solicitação addToCart na coluna esquerda e, em seguida, selecione-a para exibir os detalhes na coluna principal.

    Clique no botão Classificação Ascendente (Botão Classificação Ascendente) para que os registros mais recentes sejam listados na parte superior.


    Na guia Solicitação, observe o URI solicitado (/AffableBean/addToCart), o método HTTP (POST) e os parâmetros da solicitação (productId e submit).
    Monitor HTTP - guia Solicitação
  11. Selecione a guia Cookies. Aqui você verá que existe um cookie chamado JSESSIONID e que foi enviado do cliente para o servidor. Observe que o valor para o cookie é igual ao do ID da Sessão exibido na guia Sessão.
    Monitor HTTP - guia Cookies
    Da mesma forma, se clicar na guia Cabeçalho, verá o cookie listado, já que "Cookie" é um cabeçalho da solicitação enviado pelo cliente.
    Monitor HTTP - guia Cookies

    Consulte a Lista de cabeçalhos HTTP da Wikipedia para obter mais informações sobre cabeçalhos de solicitações e de respostas.

  12. Selecione a guia Sessão. Há uma instrução que indica: "A sessão existiu antes desta solilcitação". Note também que o atributo cart é listado em "Atributos de sessão depois da solicitação". Isso faz sentido, já que sabemos que o objeto cart está vinculado à sessão quando a solilcitação addToCart é processada pela primeira vez.
    Monitor HTTP - guia Sessão

    Nas próximas etapas, localize o ID da sessão e o cookie JSESSIONID na janela Variáveis.
  13. Reative 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 seleção ao lado da entrada do ponto de interrupção para reativá-lo.
  14. No browser, clique no botão "adicionar ao carrinho" para um dos produtos listados.
  15. Alterne para o IDE e note que o depurador está suspenso no ponto de interrupção definido no ControllerServlet. Clique no botão Fazer Step Over (Botão Fazer Step Over) para que a variável session seja atribuída ao objeto da 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 você pode acessar normalmente os cookies de um servlet chamando o método getCookies no HttpServletRequest. Portanto, entre no objeto da solicitação: solicitação > Herdado > solicitação > solicitação > Herdado > cookies. Aqui você pode ver a ArrayList cookies. Se expandir a lista, encontrará o cookie JSESSIONID, cujo valor é o ID da sessão.
  18. Clique no botão Finalizar Sessão (Botão Finalizar Sessão) para encerrar a sessão de depuração.

Mantendo Sessões com a Reescrita de URL

Como mencionado, o mecanismo do servlet detecta se os cookies são suportados para o browser do cliente e, caso não sejam, ele alterna para a reescrita de 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 a aplicação pode reescrever os URLs, caso os cookies sejam desativados. Você faz isso chamando o método encodeURL de resposta em todos os URLs retornados por servlets em sua aplicação. Fazer isso permite que o ID da sessão seja acrescentado ao URL, caso o uso de cookies não seja uma opção; caso contrário, será retornado o URL sem alteração.

Por exemplo, o browser envia uma solicitação para a terceira categoria (padaria) do AffableBeancategory?3. O servidor responde com o ID de sessão incluído no URL:

/AffableBean/category;jsessionid=364b636d75d90a6e4d0085119990?3

Como foi declarado acima, todos os URLs retornados pelos servlets da aplicação devem estar codificados. Lembre-se de que as páginas JSP são compiladas em servlets. Como é possível codificar os URLs em páginas JSP? A tag <c:url> do 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 browser. Se estiver utilizando o Firefox, poderá selecionar Ferramentas > Opções (Firefox > Preferências no Mac). Na janela exibida, selecione a guia Privacidade e, em seguida, em Histórico, selecione "Utilizar definições personalizadas para o histórico" na lista drop-down fornecida. 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 em uma categoria e, em seguida, tente adicionar um item ao seu carrinho. Você verá que a funcionalidade da aplicação está severamente comprometida no seu estado atual.
    Página de categorias danificada
    Como antes, o servidor gera uma sessão e vincula objetos a ela. Isso mostra como a página da categoria pode exibir a categoria e os produtos selecionados. Entretanto, o servidor falhou na sua tentativa de definir um cookie JSESSIONID. Portanto, quando o cliente faz uma segunda solicitação (quando o usuário clica em "adicionar ao carrinho"), o servidor não tem como identificar a sessão à qual a solicitação pertence. Portanto, ele não pode localizar nenhum dos atributos definidos anteriormente na sessão, 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 category.jsp do projeto no editor. Localize a linha que implementa o botão "adicionar ao carrinho" (linha 58). O atributo <form> do elemento action determina a solicitação enviada ao servidor.
    <form action="addToCart" method="post">
  4. Modifique a solicitação de forma que seja passada pela guia <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 a funcionalidade Implantar ao Salvar, que é ativada por default. Isso significa que quaisquer alterações salvas são implantadas automaticamente no servidor.
  6. No browser, selecione uma categoria diferente para que a aplicação renderize a página da categoria modificada recentemente.
  7. Examine o código-fonte da página. No Firefox, você pode pressionar Ctrl-U (⌘-U no Mac). O botão "adicionar ao carrinho" de cada produto é exibido com o ID da sessão acrescentado ao URL.
    <form action="addToCart;jsessionid=4188657e21d72f364e0782136dde" method="post">
  8. Clique no botão "adicionar ao carrinho" de qualquer item. Você verá que o servidor agora pode determinar a sessão à qual a solicitação pertence e de renderizar a resposta de forma adequada.
  9. Antes de prosseguir, certifique-se de reativar os cookies no browser.

Novamente, cada link em que o usuário pode clicar na aplicação, cuja resposta exija alguma forma de dados relacionados à sessão, precisa ser codificado corretamente. Às vezes a implementação não é direta, como o exemplo mostrado acima. Por exemplo, o widget "limpar carrinho" utilizado no cart.jsp define atualmente um parâmetro clear como true 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 tag <c.url> pode ser aplicada ao 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 tag <c:param é adicionada entre as tags <c.url>. Uma variável chamada "url" é definida quando o atributo var de <c.url> é utilizado e var é então acessado na tag âncora HTML utilizando a expressão ${url}.

É possível fazer download e examinar o snapshot 6 para ver como todos os links no projeto foram codificados.

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


Tratando Time-Outs de Sessão

Definindo 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 website receber um tráfego intenso, um grande número de sessões poderia usar toda 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 isso poderia se tornar um problema de uso que poderia ter impacto negativo nos negócios ligados ao website. Pegando a aplicação AffableBean como exemplo, 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 cartão de crédito e sai para pegar a carteira. Depois de retornar ao computador com o cartão de crédito em mãos, preenche o form 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 à home page. Será que ela realmente irá passar por todo o processo novamente?

As etapas a seguir demonstram como definir o intervalo de time-out de sessão no projeto AffableBean para 10 minutos. Claro que a duração real depende, em última análise, dos recursos do servidor, dos objetivos de negócios da aplicação e da popularidade do seu website.

  1. Abra o descritor de implantação da aplicação no editor. Pressione Alt-Shift-O (Ctrl-Shift-O no Mac) para utilizar a caixa de diálogo do IDE Ir para Arquivo. Digite "web" e, em seguida, clique em OK.
    Caixa de diálogo Ir para Arquivo
    O editor exibirá o arquivo web.xml na view XML. O modelo que o NetBeans fornece para o arquivo web.xml inclui uma definição default de 30 minutos.
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
  2. Clique na guia Geral e digite "10" no campo Time-out de Sessão.
    Guia Geral do arquivo web.xml
  3. Salve o arquivo (Ctrl-S; ⌘-S no Mac).

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

Observação: como alternativa, você pode remover completamente o elemento <session-timeout> e editar o elemento session-properties no descritor de implantação específico do GlassFish (sun-web.xml). Dessa forma, você definiria o time-out global para todas as aplicações no módulo web do servidor. Consulte o Oracle GlassFish Server 3.0.1 Application Development Guide: Creating and Managing Sessions para obter mais detalhes.

Tratando de Forma Programática Time-outs de Sessão

Se a sua aplicação se basear em sessões, será necessário tomar medidas para garantir que ela possa tratar, de maneira primorosa, situações nas quais uma solicitação é recebida para uma sessão que teve time-out ou que não pode ser identificada. Você pode realizar isso na aplicação AffableBean criando um filtro simples que intercepta as solicitações enviando-as para o ControllerServlet. O filtro verifica se a sessão existe, se não existir, ele encaminhará a solicitação à página de boas-vindas do site.

  1. Comece examinando o problema que aparece quando há um time-out da sessão durante uma visita do usuário ao site. Redefina temporariamente o intervalo de time-out da sessão para um minuto. Abra o descritor de implantação web (web.xml) e insira "1" entre as tags <session-timeout>.
    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>
  2. Execute o projeto AffableBean. No browser, clique na página da categoria, adicione vários itens ao carrinho e, em seguida, clique em "ver carrinho".
    Página Carrinho, que exibe itens no carrinho de compras
  3. Aguarde pelo menos um minuto completo.
  4. Atualize a quantidade de 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.
    Relatório de erro do GlassFish exibido no browser
  5. Examine o log do GlassFish Server no IDE. Abra a janela Saída (Ctrl-4, ⌘-4 no Mac) e selecione a guia GlassFish Server. Role para a parte inferior do log para examinar o rastreamento da pilha de erro.
    Relatório de erro do GlassFish exibido no browser
    O log do servidor indica que uma NullPointerException ocorreu na linha 184 no ControllerServlet. A janela Saída forma um link para a linha em que ocorreu a exceção.
  6. Clique no link. Você pode navegar diretamente até a linha 184 no ControllerServLet. Passar o mouse sobre o emblema do erro na margem esquerda do editor fornece uma dica de ferramenta que descreve a exceção.
    Emblema de erro e dica de ferramenta exibidos no Editor
    Como a sessão já havia expirado antes de a solicitação ter sido recebida, o mecanismo do servlet não poderá associar a solicitação à sua sessão correspondente. Portanto, ele não conseguiu 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. (Como alternativa, pressione Ctrl-N; ⌘-N no Mac.)
  8. Selecione a categoria Webe, em seguida, selecione Filtro e clique em Próximo.
  9. Nomeie o filtroSessionTimeoutFilter. Digite filter no campo Pacotes, para que a classe do filtro seja colocada em um novo pacote quando for criada.
  10. Clique em Próximo. Aceite as definições default e clique em Finalizar. Um modelo para o SessionTimeoutFilter será gerado e aberto no editor.

    Observação: atualmente, no NetBeans 6.9, não é possível utilizar o assistente para definir um mapeamento para um servlet que não esteja 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 solicitação que seja tratada pelo ControllerServlet. (Como alternativa, você poderia ter mantido o atributo urlPatterns e listado todos os padrões que o ControllerServlet trata.)

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

    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ária para o nosso propósito. Qualquer classe de filtro deve implementar a interface Filter, que define três métodos:
    • init: executa qualquer ação após o filtro ter sido inicializado, mas antes de ele ser colocado em serviço
    • 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 solicitação que o filtro interceptar

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

  12. Substitua o corpo do SessionTimeoutFilter pelo conteúdo 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);
    
            // if session doesn't exist, forward user to welcome page
            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ção. (As importações precisam ser adicionadas a HttpServletRequest e HttpSession.) Além disso, use as dicas 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 a solicitação está vinculada a uma sessão existente.
  14. Abra a janela Pontos de Interrupção (Alt-Shift-5; Ctrl-Shift-5 no Mac) e verifique se não há nenhum ponto de interrupção existente definido. Para deletar um ponto de interrupção, clique com o botão direito do mouse no ponto de interrupção e selecione Deletar. (Se tiver concluído 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 browser, 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 browser, clique no botão "ver carrinho". Alterne para o IDE e note que o depurador foi suspenso no ponto de interrupção.

    Lembre-se de que getSession() cria um novo objeto de sessão, caso o atual não exista. Aqui, utilizamos o getSession(false), 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 Fazer Step Over (Botão Fazer Step Over) e, em seguida, passe o ponteiro do mouse sobre a variável session. Contanto que não tenha se passado um minuto desde que a solicitação anterior foi enviada, você verá que a variável foi designada a StandardSessionFacade. Isso representa o objeto de sessão para a solicitação.
    Popup que exibe a variável
  20. Continue percorrendo o método, até que a solicitação seja processada. Como session não é igual a null, ignore a instrução if e chain.doFilter e, em seguida, encaminhe a solicitação ao ControllerServlet (linha 44).
  21. No browser, certifique-se de que se passou um minuto completo e, em seguida, atualize a quantidade de 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 as solicitações direcionadas ao ControllerServlet, veremos o que acontece quando ocorrer o time-out da sessão.
  22. Depois de clicar em "atualizar", alterne para o IDE e note que o depurador é suspenso novamente no ponto de interrupção definido no filtro.
  23. Realce a expressão req.getSession(false) e, em seguida, passe o mouse sobre ela. Aqui você verá que a expressão equivale a null, já que a sessão já expirou.
    Popup que exibe variável
  24. Continue percorrendo o código. Agora que a variável session equivale a null, a instrução if na linha 35 será processada e a solicitação será encaminhada para /index.jsp. Quando o depurador finalizar a execução, você verá que o browser exibirá a página de boas-vindas do site.
  25. Clique no botão Finalizar Sessão (Botão Finalizar Sessão) para encerrar a sessão de depuração.
  26. Abra o arquivo web.xml do projeto e mude o intervalo de time-out da sessão de volta para 10 minutos.
    <session-config>
        <session-timeout>10</session-timeout>
    </session-config>
  27. Salve o arquivo (Ctrl-S; ⌘-S no Mac).

O Snapshot 6 fornece a versão completa do projeto para esta unidade do tutorial. Um tópico final com relação ao gerenciamento de sessão deve ser mencionado. É possível encerrar 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 para 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 encerra a sessão usando o método invalidate.

// if order processed successfully send user to confirmation page
if (orderId != 0) {

    // dissociate shopping cart from session
    cart = null;

    // end session
    session.invalidate();

    ...
}

Isso é demonstrado no snapshot 8 do projeto (e em snapshots posteriores).


Consulte Também

get support for the NetBeans

Support


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