Skip to content

8. Exemplo 06 – A Sessão

8.1. O conceito de sessão

Quando o navegador de um cliente se liga a uma aplicação web pela primeira vez, recebe um token de sessão, uma sequência única de caracteres que reenvia com cada novo pedido que faz à aplicação web. Isto permite que a aplicação web reconheça o navegador do cliente. A aplicação web pode então associar dados a este token de sessão. Estes dados pertencem a um único navegador de cliente. Assim, à medida que o navegador do cliente faz pedidos, vai-se acumulando uma memória.

Conforme mostrado acima, cada utilizador (navegador) tem a sua própria memória, conhecida como sessão. Esta memória é partilhada por todas as solicitações do mesmo utilizador. Existe também uma memória de nível superior chamada memória da aplicação. Esta memória é partilhada por todas as solicitações de todos os utilizadores. Geralmente, é de leitura apenas.

8.2. O Projeto NetBeans

O projeto [example-06] é criado a partir da cópia do projeto [example-05]. Iremos alterar alguns elementos para

  • tirar partido da sessão do utilizador.
  • Adicione uma nova ação [Limpar] [1] para limpar o campo de entrada.

8.3. Configuração

O ficheiro [struts.xml] é alterado da seguinte forma:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">
 
<struts>
  <!-- internationalization -->
  <constant name="struts.custom.i18n.resources" value="messages" />
  <!-- default package -->
  <package name="default" namespace="/" extends="struts-default">
    <default-action-ref name="index" />
    <action name="index">
      <result type="redirectAction">
        <param name="actionName">Saisir</param>
        <param name="namespace">/actions</param>
      </result>
    </action>
  </package>
  <!-- equity package -->
  <package name="actions" namespace="/actions" extends="struts-default">
    <action name="Saisir">
      <result name="success">/vues/Saisie.jsp</result>
    </action>
    <action name="Confirmer" class="actions.Confirmer">
      <result name="success">/vues/Confirmation.jsp</result>
    </action>
    <action name="Effacer" class="actions.Effacer">
      <result name="success">/vues/Saisie.jsp</result>
    </action>
  </package>
</struts>

As linhas 27–29 definem uma nova ação [Delete] associada a uma classe [Delete]. A resposta a esta ação é a vista [Input.jsp].

8.4. A ação [Confirm]

Evolui da seguinte forma:


package actions;
 
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
 
public class Confirmer extends ActionSupport implements SessionAware{
 
  // model
  private String nom;
  // session
  private Map<String, Object> session;
 
  // getters and setters
 
  public String getNom() {
    return nom;
  }
 
  public void setNom(String nom) {
    this.nom = nom;
  }
 
  @Override
  public void setSession(Map<String, Object> session) {
    this.session=session;
  }
 
  @Override
  public String execute(){
    // put the name in the session
    session.put("nom",nom);
    // navigation
    return SUCCESS;
  }
 
}
  • Linha 7: A classe [Confirm] implementa a interface SessionAware. Esta interface tem apenas um método, o método setSession nas linhas 25–27. Antes de o método execute ser chamado, um dos interceptores de pedidos irá injetar, através do método setSession, a sessão do utilizador na forma de um dicionário Map<String, Object> (linha 25). Optamos por armazenar este dicionário no campo session na linha 12.
  • Linhas 30–34: o método `execute` da ação. Quando este é executado, o campo session já foi inicializado por um dos interceptores e o campo name por outro interceptor. Utilizamos este dicionário de sessão para armazenar o campo name. Assim, o nome fará parte da sessão do utilizador e estará disponível para todos os seus pedidos.

8.5. As vistas [Confirmation.jsp] e [Saisie.jsp]

A vista [Confirmation.jsp] permanece inalterada. A vista [Saisie.jsp] sofre as seguintes alterações:


<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title><s:text name="saisie.titre1"/></title>
  </head>
  <body>
    <h1><s:text name="saisie.titre2"/></h1>
    <s:form action="Confirmer">
      <s:textfield key="saisie.libelle" name="nom" value="%{#attr['nom']}"/>
      <s:submit key="saisie.valider" action="Confirmer"/>
      <s:submit key="saisie.effacer" action="Effacer"/>
    </s:form>
  </body>
</html>
  • Linha 12: Adicionamos um atributo `value` à tag `<s:textfield>`. Este atributo define o valor a ser exibido no campo de entrada. Se este atributo for omitido, `value` assume por predefinição o valor `name`. Aqui, o valor do atributo é uma expressão OGNL (Object-Graph Navigation Language) na forma `%{expressão_a_avaliar}`. Aqui, a expressão a ser avaliada é #attr['name']. O atributo name será procurado na ação atual, na página, na solicitação, na sessão e na aplicação, nessa ordem. Como a ação [Confirm] coloca o atributo name na sessão, ele será encontrado lá. Isto é demonstrado pela seguinte solicitação:

Em [1], o nome introduzido foi ST. Sabemos que a ação [Confirm] colocou este nome na sessão. O link [2] leva-nos para o URL [3]. A vista [Saisie.jsp] é apresentada. Para o campo de entrada, o atributo %{#attr['name']} recupera o nome da sessão.

  • Linha 14: o botão [Limpar], que aciona a execução da ação [Limpar] e a exibição da vista [Saisie.jsp]

<action name="Effacer" class="actions.Effacer">
      <result name="success">/vues/Saisie.jsp</result>
</action>

8.6. A ação [Apagar]

O código para a ação [Apagar] é o seguinte:


package actions;
 
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
 
public class Effacer extends ActionSupport implements SessionAware{
 
  // session
  private Map<String, Object> session;
 
  @Override
  public String execute(){
    // retrieve the name from the session
    String nom=(String)session.get("nom");
    // remove it from the session if necessary
    if(nom!=null){
      session.remove("nom");
    }
    // navigation
    return SUCCESS;
  }
 
  @Override
  public void setSession(Map<String, Object> map) {
    this.session=map;
  }
}

  • Linha 7: A classe [Delete] implementa a interface [SessionAware], tal como a ação [Confirm] fez.
  • linha 13: A ação [Delete] deve limpar o conteúdo do campo de entrada de nome na vista [Input.jsp]. Sabemos que esta vista recupera este nome da sessão. Devemos, portanto, remover o nome da sessão. É isso que o método execute faz.

Vamos ver como isto funciona:

Em [1], queremos limpar o campo de entrada. Clicamos no botão [Limpar].


<s:submit key="saisie.effacer" action="Effacer"/>

A ação [Limpar] será executada. Em [2], verificamos que o URL chamado foi o da ação [Confirmar]. Isto deve-se à tag <s:form> no formulário:


<s:form action="Confirmer">

o que faz com que o formulário seja enviado para a ação [Confirm]. Quando se clica no botão [Limpar], o parâmetro

action:Delete=Delete

foi enviado para o URL [/actions/Confirm.action]. O Struts utiliza este parâmetro para processar os dados enviados pela ação [Delete]. Esta ação remove o nome da sessão. A página [Input.jsp] é a resposta à ação [Delete]:


<action name="Effacer" class="actions.Effacer">
      <result name="success">/vues/Saisie.jsp</result>
</action>

Esta, que exibe o nome da sessão, exibe em seguida uma string vazia [3].

Escrevemos vários exemplos simples para apresentar conceitos importantes do Struts 2:

  • internacionalização de páginas
  • injeção de parâmetros enviados em campos de ação
  • o conceito de sessões
  • a relação entre Ações e Visualizações

Agora que dominamos estes conceitos, estamos prontos para abordar exemplos mais complexos. Começaremos por apresentar as várias tags que podem ser utilizadas num formulário.